Lines Matching +full:no +full:- +full:read +full:- +full:rollover

1 // SPDX-License-Identifier: GPL-2.0
3 * Native support for the I/O-Warrior USB devices
5 * Copyright (c) 2003-2005, 2020 Code Mercenaries GmbH
11 * usb-skeleton.c by Greg Kroah-Hartman <[email protected]>
27 #define DRIVER_DESC "USB IO-Warrior driver"
68 /*--------------*/
70 /*--------------*/
81 unsigned char *int_in_buffer; /* buffer for data to be read */
85 wait_queue_head_t write_wait; /* wait-queue for writing to the device */
86 atomic_t write_busy; /* number of write-urbs submitted */
89 atomic_t overflow_flag; /* signals an index 'rollover' */
98 /*--------------*/
100 /*--------------*/
112 inter->desc.bInterfaceNumber, buf, size, in usb_get_report()
127 intf->cur_altsetting->desc.bInterfaceNumber, buf, in usb_set_report()
131 /*---------------------*/
133 /*---------------------*/
155 struct iowarrior *dev = urb->context; in iowarrior_callback()
160 int status = urb->status; in iowarrior_callback()
167 case -ECONNRESET: in iowarrior_callback()
168 case -ENOENT: in iowarrior_callback()
169 case -ESHUTDOWN: in iowarrior_callback()
175 intr_idx = atomic_read(&dev->intr_idx); in iowarrior_callback()
177 aux_idx = (intr_idx == 0) ? (MAX_INTERRUPT_BUFFER - 1) : (intr_idx - 1); in iowarrior_callback()
178 read_idx = atomic_read(&dev->read_idx); in iowarrior_callback()
182 && (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0)) { in iowarrior_callback()
184 offset = aux_idx * (dev->report_size + 1); in iowarrior_callback()
186 (dev->read_queue + offset, urb->transfer_buffer, in iowarrior_callback()
187 dev->report_size)) { in iowarrior_callback()
194 aux_idx = (intr_idx == (MAX_INTERRUPT_BUFFER - 1)) ? 0 : (intr_idx + 1); in iowarrior_callback()
198 atomic_set(&dev->read_idx, read_idx); in iowarrior_callback()
199 atomic_set(&dev->overflow_flag, 1); in iowarrior_callback()
203 offset = intr_idx * (dev->report_size + 1); in iowarrior_callback()
204 memcpy(dev->read_queue + offset, urb->transfer_buffer, in iowarrior_callback()
205 dev->report_size); in iowarrior_callback()
206 *(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++; in iowarrior_callback()
208 atomic_set(&dev->intr_idx, aux_idx); in iowarrior_callback()
209 /* tell the blocking read about the new data */ in iowarrior_callback()
210 wake_up_interruptible(&dev->read_wait); in iowarrior_callback()
215 dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d\n", in iowarrior_callback()
221 * USB Callback handler for write-ops
226 int status = urb->status; in iowarrior_write_callback()
228 dev = urb->context; in iowarrior_write_callback()
231 !(status == -ENOENT || in iowarrior_write_callback()
232 status == -ECONNRESET || status == -ESHUTDOWN)) { in iowarrior_write_callback()
233 dev_dbg(&dev->interface->dev, in iowarrior_write_callback()
237 usb_free_coherent(urb->dev, urb->transfer_buffer_length, in iowarrior_write_callback()
238 urb->transfer_buffer, urb->transfer_dma); in iowarrior_write_callback()
239 /* tell a waiting writer the interrupt-out-pipe is available again */ in iowarrior_write_callback()
240 atomic_dec(&dev->write_busy); in iowarrior_write_callback()
241 wake_up_interruptible(&dev->write_wait); in iowarrior_write_callback()
249 dev_dbg(&dev->interface->dev, "minor %d\n", dev->minor); in iowarrior_delete()
250 kfree(dev->int_in_buffer); in iowarrior_delete()
251 usb_free_urb(dev->int_in_urb); in iowarrior_delete()
252 kfree(dev->read_queue); in iowarrior_delete()
253 usb_put_intf(dev->interface); in iowarrior_delete()
257 /*---------------------*/
259 /*---------------------*/
265 read_idx = atomic_read(&dev->read_idx); in read_index()
266 intr_idx = atomic_read(&dev->intr_idx); in read_index()
268 return (read_idx == intr_idx ? -1 : read_idx); in read_index()
282 dev = file->private_data; in iowarrior_read()
284 if (file->f_flags & O_NONBLOCK) { in iowarrior_read()
285 retval = mutex_trylock(&dev->mutex); in iowarrior_read()
287 return -EAGAIN; in iowarrior_read()
289 retval = mutex_lock_interruptible(&dev->mutex); in iowarrior_read()
291 return -ERESTARTSYS; in iowarrior_read()
295 if (!dev->present) { in iowarrior_read()
296 retval = -ENODEV; in iowarrior_read()
300 dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n", in iowarrior_read()
301 dev->minor, count); in iowarrior_read()
303 /* read count must be packet size (+ time stamp) */ in iowarrior_read()
304 if ((count != dev->report_size) in iowarrior_read()
305 && (count != (dev->report_size + 1))) { in iowarrior_read()
306 retval = -EINVAL; in iowarrior_read()
310 /* repeat until no buffer overrun in callback handler occur */ in iowarrior_read()
312 atomic_set(&dev->overflow_flag, 0); in iowarrior_read()
313 if ((read_idx = read_index(dev)) == -1) { in iowarrior_read()
315 if (file->f_flags & O_NONBLOCK) { in iowarrior_read()
316 retval = -EAGAIN; in iowarrior_read()
321 int r = wait_event_interruptible(dev->read_wait, in iowarrior_read()
322 (!dev->present in iowarrior_read()
326 -1)); in iowarrior_read()
329 retval = -ERESTART; in iowarrior_read()
332 if (!dev->present) { in iowarrior_read()
334 retval = -ENODEV; in iowarrior_read()
337 if (read_idx == -1) { in iowarrior_read()
345 offset = read_idx * (dev->report_size + 1); in iowarrior_read()
346 if (copy_to_user(buffer, dev->read_queue + offset, count)) { in iowarrior_read()
347 retval = -EFAULT; in iowarrior_read()
350 } while (atomic_read(&dev->overflow_flag)); in iowarrior_read()
353 atomic_set(&dev->read_idx, read_idx); in iowarrior_read()
354 mutex_unlock(&dev->mutex); in iowarrior_read()
358 mutex_unlock(&dev->mutex); in iowarrior_read()
374 dev = file->private_data; in iowarrior_write()
376 mutex_lock(&dev->mutex); in iowarrior_write()
378 if (!dev->present) { in iowarrior_write()
379 retval = -ENODEV; in iowarrior_write()
382 dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n", in iowarrior_write()
383 dev->minor, count); in iowarrior_write()
390 if (count != dev->report_size) { in iowarrior_write()
391 retval = -EINVAL; in iowarrior_write()
394 switch (dev->product_id) { in iowarrior_write()
406 retval = usb_set_report(dev->interface, 2, 0, buf, count); in iowarrior_write()
415 if (atomic_read(&dev->write_busy) == MAX_WRITES_IN_FLIGHT) { in iowarrior_write()
417 if (file->f_flags & O_NONBLOCK) { in iowarrior_write()
418 retval = -EAGAIN; in iowarrior_write()
421 retval = wait_event_interruptible(dev->write_wait, in iowarrior_write()
422 (!dev->present || (atomic_read (&dev-> write_busy) < MAX_WRITES_IN_FLIGHT))); in iowarrior_write()
425 retval = -ERESTART; in iowarrior_write()
428 if (!dev->present) { in iowarrior_write()
430 retval = -ENODEV; in iowarrior_write()
433 if (!dev->opened) { in iowarrior_write()
435 retval = -ENODEV; in iowarrior_write()
440 atomic_inc(&dev->write_busy); in iowarrior_write()
443 retval = -ENOMEM; in iowarrior_write()
446 buf = usb_alloc_coherent(dev->udev, dev->report_size, in iowarrior_write()
447 GFP_KERNEL, &int_out_urb->transfer_dma); in iowarrior_write()
449 retval = -ENOMEM; in iowarrior_write()
450 dev_dbg(&dev->interface->dev, in iowarrior_write()
454 usb_fill_int_urb(int_out_urb, dev->udev, in iowarrior_write()
455 usb_sndintpipe(dev->udev, in iowarrior_write()
456 dev->int_out_endpoint->bEndpointAddress), in iowarrior_write()
457 buf, dev->report_size, in iowarrior_write()
459 dev->int_out_endpoint->bInterval); in iowarrior_write()
460 int_out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; in iowarrior_write()
462 retval = -EFAULT; in iowarrior_write()
465 usb_anchor_urb(int_out_urb, &dev->submitted); in iowarrior_write()
468 dev_dbg(&dev->interface->dev, in iowarrior_write()
470 retval, atomic_read(&dev->write_busy)); in iowarrior_write()
479 /* what do we have here ? An unsupported Product-ID ? */ in iowarrior_write()
480 dev_err(&dev->interface->dev, "%s - not supported for product=0x%x\n", in iowarrior_write()
481 __func__, dev->product_id); in iowarrior_write()
482 retval = -EFAULT; in iowarrior_write()
486 usb_free_coherent(dev->udev, dev->report_size, buf, in iowarrior_write()
487 int_out_urb->transfer_dma); in iowarrior_write()
491 atomic_dec(&dev->write_busy); in iowarrior_write()
492 wake_up_interruptible(&dev->write_wait); in iowarrior_write()
494 mutex_unlock(&dev->mutex); in iowarrior_write()
508 int io_res; /* checks for bytes read/written and copy_to/from_user results */ in iowarrior_ioctl()
510 dev = file->private_data; in iowarrior_ioctl()
512 return -ENODEV; in iowarrior_ioctl()
514 buffer = kzalloc(dev->report_size, GFP_KERNEL); in iowarrior_ioctl()
516 return -ENOMEM; in iowarrior_ioctl()
518 mutex_lock(&dev->mutex); in iowarrior_ioctl()
521 if (!dev->present) { in iowarrior_ioctl()
522 retval = -ENODEV; in iowarrior_ioctl()
526 dev_dbg(&dev->interface->dev, "minor %d, cmd 0x%.4x, arg %ld\n", in iowarrior_ioctl()
527 dev->minor, cmd, arg); in iowarrior_ioctl()
532 if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 || in iowarrior_ioctl()
533 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24SAG || in iowarrior_ioctl()
534 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 || in iowarrior_ioctl()
535 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 || in iowarrior_ioctl()
536 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) { in iowarrior_ioctl()
539 dev->report_size); in iowarrior_ioctl()
541 retval = -EFAULT; in iowarrior_ioctl()
543 io_res = usb_set_report(dev->interface, 2, 0, in iowarrior_ioctl()
545 dev->report_size); in iowarrior_ioctl()
550 retval = -EINVAL; in iowarrior_ioctl()
551 dev_err(&dev->interface->dev, in iowarrior_ioctl()
553 dev->product_id); in iowarrior_ioctl()
558 io_res = usb_get_report(dev->udev, in iowarrior_ioctl()
559 dev->interface->cur_altsetting, 1, 0, in iowarrior_ioctl()
560 buffer, dev->report_size); in iowarrior_ioctl()
564 io_res = copy_to_user(user_buffer, buffer, dev->report_size); in iowarrior_ioctl()
566 retval = -EFAULT; in iowarrior_ioctl()
574 struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc; in iowarrior_ioctl()
578 info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); in iowarrior_ioctl()
579 info.product = dev->product_id; in iowarrior_ioctl()
580 info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice); in iowarrior_ioctl()
583 info.speed = dev->udev->speed; in iowarrior_ioctl()
584 info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber; in iowarrior_ioctl()
585 info.report_size = dev->report_size; in iowarrior_ioctl()
587 /* serial number string has been read earlier 8 chars or empty string */ in iowarrior_ioctl()
588 memcpy(info.serial, dev->chip_serial, in iowarrior_ioctl()
589 sizeof(dev->chip_serial)); in iowarrior_ioctl()
591 info.power = -1; /* no information available */ in iowarrior_ioctl()
593 /* the MaxPower is stored in units of 2mA to make it fit into a byte-value */ in iowarrior_ioctl()
594 info.power = cfg_descriptor->bMaxPower * 2; in iowarrior_ioctl()
599 retval = -EFAULT; in iowarrior_ioctl()
604 retval = -ENOTTY; in iowarrior_ioctl()
609 mutex_unlock(&dev->mutex); in iowarrior_ioctl()
628 pr_err("%s - error, can't find device for minor %d\n", in iowarrior_open()
630 return -ENODEV; in iowarrior_open()
635 return -ENODEV; in iowarrior_open()
637 mutex_lock(&dev->mutex); in iowarrior_open()
639 /* Only one process can open each device, no sharing. */ in iowarrior_open()
640 if (dev->opened) { in iowarrior_open()
641 retval = -EBUSY; in iowarrior_open()
646 if ((retval = usb_submit_urb(dev->int_in_urb, GFP_KERNEL)) < 0) { in iowarrior_open()
647 dev_err(&interface->dev, "Error %d while submitting URB\n", retval); in iowarrior_open()
648 retval = -EFAULT; in iowarrior_open()
652 ++dev->opened; in iowarrior_open()
654 file->private_data = dev; in iowarrior_open()
658 mutex_unlock(&dev->mutex); in iowarrior_open()
670 dev = file->private_data; in iowarrior_release()
672 return -ENODEV; in iowarrior_release()
674 dev_dbg(&dev->interface->dev, "minor %d\n", dev->minor); in iowarrior_release()
677 mutex_lock(&dev->mutex); in iowarrior_release()
679 if (dev->opened <= 0) { in iowarrior_release()
680 retval = -ENODEV; /* close called more than once */ in iowarrior_release()
681 mutex_unlock(&dev->mutex); in iowarrior_release()
683 dev->opened = 0; /* we're closing now */ in iowarrior_release()
685 if (dev->present) { in iowarrior_release()
688 pending read-/write-ops. in iowarrior_release()
690 usb_kill_urb(dev->int_in_urb); in iowarrior_release()
691 wake_up_interruptible(&dev->read_wait); in iowarrior_release()
692 wake_up_interruptible(&dev->write_wait); in iowarrior_release()
693 mutex_unlock(&dev->mutex); in iowarrior_release()
696 mutex_unlock(&dev->mutex); in iowarrior_release()
705 struct iowarrior *dev = file->private_data; in iowarrior_poll()
708 if (!dev->present) in iowarrior_poll()
711 poll_wait(file, &dev->read_wait, wait); in iowarrior_poll()
712 poll_wait(file, &dev->write_wait, wait); in iowarrior_poll()
714 if (!dev->present) in iowarrior_poll()
717 if (read_index(dev) != -1) in iowarrior_poll()
720 if (atomic_read(&dev->write_busy) < MAX_WRITES_IN_FLIGHT) in iowarrior_poll()
737 .read = iowarrior_read,
761 /*---------------------------------*/
763 /*---------------------------------*/
776 int retval = -ENOMEM; in iowarrior_probe()
784 mutex_init(&dev->mutex); in iowarrior_probe()
786 atomic_set(&dev->intr_idx, 0); in iowarrior_probe()
787 atomic_set(&dev->read_idx, 0); in iowarrior_probe()
788 atomic_set(&dev->overflow_flag, 0); in iowarrior_probe()
789 init_waitqueue_head(&dev->read_wait); in iowarrior_probe()
790 atomic_set(&dev->write_busy, 0); in iowarrior_probe()
791 init_waitqueue_head(&dev->write_wait); in iowarrior_probe()
793 dev->udev = udev; in iowarrior_probe()
794 dev->interface = usb_get_intf(interface); in iowarrior_probe()
796 iface_desc = interface->cur_altsetting; in iowarrior_probe()
797 dev->product_id = le16_to_cpu(udev->descriptor.idProduct); in iowarrior_probe()
799 init_usb_anchor(&dev->submitted); in iowarrior_probe()
801 res = usb_find_last_int_in_endpoint(iface_desc, &dev->int_in_endpoint); in iowarrior_probe()
803 dev_err(&interface->dev, "no interrupt-in endpoint found\n"); in iowarrior_probe()
808 if ((dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) || in iowarrior_probe()
809 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56AM) || in iowarrior_probe()
810 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28) || in iowarrior_probe()
811 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28L) || in iowarrior_probe()
812 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW100)) { in iowarrior_probe()
814 &dev->int_out_endpoint); in iowarrior_probe()
816 dev_err(&interface->dev, "no interrupt-out endpoint found\n"); in iowarrior_probe()
823 dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint); in iowarrior_probe()
829 if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { in iowarrior_probe()
830 switch (dev->product_id) { in iowarrior_probe()
833 dev->report_size = 7; in iowarrior_probe()
838 dev->report_size = 4; in iowarrior_probe()
842 dev->report_size = 12; in iowarrior_probe()
848 dev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); in iowarrior_probe()
849 if (!dev->int_in_urb) in iowarrior_probe()
851 dev->int_in_buffer = kmalloc(dev->report_size, GFP_KERNEL); in iowarrior_probe()
852 if (!dev->int_in_buffer) in iowarrior_probe()
854 usb_fill_int_urb(dev->int_in_urb, dev->udev, in iowarrior_probe()
855 usb_rcvintpipe(dev->udev, in iowarrior_probe()
856 dev->int_in_endpoint->bEndpointAddress), in iowarrior_probe()
857 dev->int_in_buffer, dev->report_size, in iowarrior_probe()
859 dev->int_in_endpoint->bInterval); in iowarrior_probe()
861 dev->read_queue = in iowarrior_probe()
862 kmalloc_array(dev->report_size + 1, MAX_INTERRUPT_BUFFER, in iowarrior_probe()
864 if (!dev->read_queue) in iowarrior_probe()
866 /* Get the serial-number of the chip */ in iowarrior_probe()
867 memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); in iowarrior_probe()
868 usb_string(udev, udev->descriptor.iSerialNumber, dev->chip_serial, in iowarrior_probe()
869 sizeof(dev->chip_serial)); in iowarrior_probe()
870 if (strlen(dev->chip_serial) != 8) in iowarrior_probe()
871 memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); in iowarrior_probe()
874 if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { in iowarrior_probe()
880 /* allow device read and ioctl */ in iowarrior_probe()
881 dev->present = 1; in iowarrior_probe()
889 dev_err(&interface->dev, "Not able to get a minor for this device.\n"); in iowarrior_probe()
893 dev->minor = interface->minor; in iowarrior_probe()
896 dev_info(&interface->dev, "IOWarrior product=0x%x, serial=%s interface=%d " in iowarrior_probe()
897 "now attached to iowarrior%d\n", dev->product_id, dev->chip_serial, in iowarrior_probe()
898 iface_desc->desc.bInterfaceNumber, dev->minor - IOWARRIOR_MINOR_BASE); in iowarrior_probe()
917 mutex_lock(&dev->mutex); in iowarrior_disconnect()
919 /* prevent device read, write and ioctl */ in iowarrior_disconnect()
920 dev->present = 0; in iowarrior_disconnect()
922 if (dev->opened) { in iowarrior_disconnect()
924 so we only shutdown read-/write-ops going on. in iowarrior_disconnect()
927 usb_kill_urb(dev->int_in_urb); in iowarrior_disconnect()
928 usb_kill_anchored_urbs(&dev->submitted); in iowarrior_disconnect()
929 wake_up_interruptible(&dev->read_wait); in iowarrior_disconnect()
930 wake_up_interruptible(&dev->write_wait); in iowarrior_disconnect()
931 mutex_unlock(&dev->mutex); in iowarrior_disconnect()
933 /* no process is using the device, cleanup now */ in iowarrior_disconnect()
934 mutex_unlock(&dev->mutex); in iowarrior_disconnect()