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 <greg@kroah.com>
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 /*--------------*/
116 inter->desc.bInterfaceNumber, buf, size, in usb_get_report()
131 intf->cur_altsetting->desc.bInterfaceNumber, buf, in usb_set_report()
135 /*---------------------*/
137 /*---------------------*/
159 struct iowarrior *dev = urb->context; in iowarrior_callback()
164 int status = urb->status; in iowarrior_callback()
171 case -ECONNRESET: in iowarrior_callback()
172 case -ENOENT: in iowarrior_callback()
173 case -ESHUTDOWN: in iowarrior_callback()
179 intr_idx = atomic_read(&dev->intr_idx); in iowarrior_callback()
181 aux_idx = (intr_idx == 0) ? (MAX_INTERRUPT_BUFFER - 1) : (intr_idx - 1); in iowarrior_callback()
182 read_idx = atomic_read(&dev->read_idx); in iowarrior_callback()
186 && (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0)) { in iowarrior_callback()
188 offset = aux_idx * (dev->report_size + 1); in iowarrior_callback()
190 (dev->read_queue + offset, urb->transfer_buffer, in iowarrior_callback()
191 dev->report_size)) { in iowarrior_callback()
198 aux_idx = (intr_idx == (MAX_INTERRUPT_BUFFER - 1)) ? 0 : (intr_idx + 1); in iowarrior_callback()
202 atomic_set(&dev->read_idx, read_idx); in iowarrior_callback()
203 atomic_set(&dev->overflow_flag, 1); in iowarrior_callback()
207 offset = intr_idx * (dev->report_size + 1); in iowarrior_callback()
208 memcpy(dev->read_queue + offset, urb->transfer_buffer, in iowarrior_callback()
209 dev->report_size); in iowarrior_callback()
210 *(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++; in iowarrior_callback()
212 atomic_set(&dev->intr_idx, aux_idx); in iowarrior_callback()
213 /* tell the blocking read about the new data */ in iowarrior_callback()
214 wake_up_interruptible(&dev->read_wait); in iowarrior_callback()
219 dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d\n", in iowarrior_callback()
225 * USB Callback handler for write-ops
230 int status = urb->status; in iowarrior_write_callback()
232 dev = urb->context; in iowarrior_write_callback()
235 !(status == -ENOENT || in iowarrior_write_callback()
236 status == -ECONNRESET || status == -ESHUTDOWN)) { in iowarrior_write_callback()
237 dev_dbg(&dev->interface->dev, in iowarrior_write_callback()
241 usb_free_coherent(urb->dev, urb->transfer_buffer_length, in iowarrior_write_callback()
242 urb->transfer_buffer, urb->transfer_dma); in iowarrior_write_callback()
243 /* tell a waiting writer the interrupt-out-pipe is available again */ in iowarrior_write_callback()
244 atomic_dec(&dev->write_busy); in iowarrior_write_callback()
245 wake_up_interruptible(&dev->write_wait); in iowarrior_write_callback()
253 dev_dbg(&dev->interface->dev, "minor %d\n", dev->minor); in iowarrior_delete()
254 kfree(dev->int_in_buffer); in iowarrior_delete()
255 usb_free_urb(dev->int_in_urb); in iowarrior_delete()
256 kfree(dev->read_queue); in iowarrior_delete()
257 usb_put_intf(dev->interface); in iowarrior_delete()
261 /*---------------------*/
263 /*---------------------*/
269 read_idx = atomic_read(&dev->read_idx); in read_index()
270 intr_idx = atomic_read(&dev->intr_idx); in read_index()
272 return (read_idx == intr_idx ? -1 : read_idx); in read_index()
285 dev = file->private_data; in iowarrior_read()
288 if (!dev || !dev->present) in iowarrior_read()
289 return -ENODEV; in iowarrior_read()
291 dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n", in iowarrior_read()
292 dev->minor, count); in iowarrior_read()
294 /* read count must be packet size (+ time stamp) */ in iowarrior_read()
295 if ((count != dev->report_size) in iowarrior_read()
296 && (count != (dev->report_size + 1))) in iowarrior_read()
297 return -EINVAL; in iowarrior_read()
299 /* repeat until no buffer overrun in callback handler occur */ in iowarrior_read()
301 atomic_set(&dev->overflow_flag, 0); in iowarrior_read()
302 if ((read_idx = read_index(dev)) == -1) { in iowarrior_read()
304 if (file->f_flags & O_NONBLOCK) in iowarrior_read()
305 return -EAGAIN; in iowarrior_read()
308 int r = wait_event_interruptible(dev->read_wait, in iowarrior_read()
309 (!dev->present in iowarrior_read()
313 -1)); in iowarrior_read()
316 return -ERESTART; in iowarrior_read()
318 if (!dev->present) { in iowarrior_read()
320 return -ENODEV; in iowarrior_read()
322 if (read_idx == -1) { in iowarrior_read()
329 offset = read_idx * (dev->report_size + 1); in iowarrior_read()
330 if (copy_to_user(buffer, dev->read_queue + offset, count)) { in iowarrior_read()
331 return -EFAULT; in iowarrior_read()
333 } while (atomic_read(&dev->overflow_flag)); in iowarrior_read()
336 atomic_set(&dev->read_idx, read_idx); in iowarrior_read()
352 dev = file->private_data; in iowarrior_write()
354 mutex_lock(&dev->mutex); in iowarrior_write()
356 if (!dev->present) { in iowarrior_write()
357 retval = -ENODEV; in iowarrior_write()
360 dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n", in iowarrior_write()
361 dev->minor, count); in iowarrior_write()
368 if (count != dev->report_size) { in iowarrior_write()
369 retval = -EINVAL; in iowarrior_write()
372 switch (dev->product_id) { in iowarrior_write()
384 retval = usb_set_report(dev->interface, 2, 0, buf, count); in iowarrior_write()
393 if (atomic_read(&dev->write_busy) == MAX_WRITES_IN_FLIGHT) { in iowarrior_write()
395 if (file->f_flags & O_NONBLOCK) { in iowarrior_write()
396 retval = -EAGAIN; in iowarrior_write()
399 retval = wait_event_interruptible(dev->write_wait, in iowarrior_write()
400 (!dev->present || (atomic_read (&dev-> write_busy) < MAX_WRITES_IN_FLIGHT))); in iowarrior_write()
403 retval = -ERESTART; in iowarrior_write()
406 if (!dev->present) { in iowarrior_write()
408 retval = -ENODEV; in iowarrior_write()
411 if (!dev->opened) { in iowarrior_write()
413 retval = -ENODEV; in iowarrior_write()
418 atomic_inc(&dev->write_busy); in iowarrior_write()
421 retval = -ENOMEM; in iowarrior_write()
424 buf = usb_alloc_coherent(dev->udev, dev->report_size, in iowarrior_write()
425 GFP_KERNEL, &int_out_urb->transfer_dma); in iowarrior_write()
427 retval = -ENOMEM; in iowarrior_write()
428 dev_dbg(&dev->interface->dev, in iowarrior_write()
432 usb_fill_int_urb(int_out_urb, dev->udev, in iowarrior_write()
433 usb_sndintpipe(dev->udev, in iowarrior_write()
434 dev->int_out_endpoint->bEndpointAddress), in iowarrior_write()
435 buf, dev->report_size, in iowarrior_write()
437 dev->int_out_endpoint->bInterval); in iowarrior_write()
438 int_out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; in iowarrior_write()
440 retval = -EFAULT; in iowarrior_write()
443 usb_anchor_urb(int_out_urb, &dev->submitted); in iowarrior_write()
446 dev_dbg(&dev->interface->dev, in iowarrior_write()
448 retval, atomic_read(&dev->write_busy)); in iowarrior_write()
457 /* what do we have here ? An unsupported Product-ID ? */ in iowarrior_write()
458 dev_err(&dev->interface->dev, "%s - not supported for product=0x%x\n", in iowarrior_write()
459 __func__, dev->product_id); in iowarrior_write()
460 retval = -EFAULT; in iowarrior_write()
464 usb_free_coherent(dev->udev, dev->report_size, buf, in iowarrior_write()
465 int_out_urb->transfer_dma); in iowarrior_write()
469 atomic_dec(&dev->write_busy); in iowarrior_write()
470 wake_up_interruptible(&dev->write_wait); in iowarrior_write()
472 mutex_unlock(&dev->mutex); in iowarrior_write()
486 int io_res; /* checks for bytes read/written and copy_to/from_user results */ in iowarrior_ioctl()
488 dev = file->private_data; in iowarrior_ioctl()
490 return -ENODEV; in iowarrior_ioctl()
492 buffer = kzalloc(dev->report_size, GFP_KERNEL); in iowarrior_ioctl()
494 return -ENOMEM; in iowarrior_ioctl()
496 mutex_lock(&dev->mutex); in iowarrior_ioctl()
499 if (!dev->present) { in iowarrior_ioctl()
500 retval = -ENODEV; in iowarrior_ioctl()
504 dev_dbg(&dev->interface->dev, "minor %d, cmd 0x%.4x, arg %ld\n", in iowarrior_ioctl()
505 dev->minor, cmd, arg); in iowarrior_ioctl()
511 if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 || in iowarrior_ioctl()
512 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24SAG || in iowarrior_ioctl()
513 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 || in iowarrior_ioctl()
514 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 || in iowarrior_ioctl()
515 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) { in iowarrior_ioctl()
518 dev->report_size); in iowarrior_ioctl()
520 retval = -EFAULT; in iowarrior_ioctl()
522 io_res = usb_set_report(dev->interface, 2, 0, in iowarrior_ioctl()
524 dev->report_size); in iowarrior_ioctl()
529 retval = -EINVAL; in iowarrior_ioctl()
530 dev_err(&dev->interface->dev, in iowarrior_ioctl()
532 dev->product_id); in iowarrior_ioctl()
537 io_res = usb_get_report(dev->udev, in iowarrior_ioctl()
538 dev->interface->cur_altsetting, 1, 0, in iowarrior_ioctl()
539 buffer, dev->report_size); in iowarrior_ioctl()
543 io_res = copy_to_user(user_buffer, buffer, dev->report_size); in iowarrior_ioctl()
545 retval = -EFAULT; in iowarrior_ioctl()
553 struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc; in iowarrior_ioctl()
557 info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); in iowarrior_ioctl()
558 info.product = dev->product_id; in iowarrior_ioctl()
559 info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice); in iowarrior_ioctl()
562 info.speed = dev->udev->speed; in iowarrior_ioctl()
563 info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber; in iowarrior_ioctl()
564 info.report_size = dev->report_size; in iowarrior_ioctl()
566 /* serial number string has been read earlier 8 chars or empty string */ in iowarrior_ioctl()
567 memcpy(info.serial, dev->chip_serial, in iowarrior_ioctl()
568 sizeof(dev->chip_serial)); in iowarrior_ioctl()
570 info.power = -1; /* no information available */ in iowarrior_ioctl()
572 /* the MaxPower is stored in units of 2mA to make it fit into a byte-value */ in iowarrior_ioctl()
573 info.power = cfg_descriptor->bMaxPower * 2; in iowarrior_ioctl()
578 retval = -EFAULT; in iowarrior_ioctl()
583 retval = -ENOTTY; in iowarrior_ioctl()
588 mutex_unlock(&dev->mutex); in iowarrior_ioctl()
607 pr_err("%s - error, can't find device for minor %d\n", in iowarrior_open()
609 return -ENODEV; in iowarrior_open()
614 return -ENODEV; in iowarrior_open()
616 mutex_lock(&dev->mutex); in iowarrior_open()
618 /* Only one process can open each device, no sharing. */ in iowarrior_open()
619 if (dev->opened) { in iowarrior_open()
620 retval = -EBUSY; in iowarrior_open()
625 if ((retval = usb_submit_urb(dev->int_in_urb, GFP_KERNEL)) < 0) { in iowarrior_open()
626 dev_err(&interface->dev, "Error %d while submitting URB\n", retval); in iowarrior_open()
627 retval = -EFAULT; in iowarrior_open()
631 ++dev->opened; in iowarrior_open()
633 file->private_data = dev; in iowarrior_open()
637 mutex_unlock(&dev->mutex); in iowarrior_open()
649 dev = file->private_data; in iowarrior_release()
651 return -ENODEV; in iowarrior_release()
653 dev_dbg(&dev->interface->dev, "minor %d\n", dev->minor); in iowarrior_release()
656 mutex_lock(&dev->mutex); in iowarrior_release()
658 if (dev->opened <= 0) { in iowarrior_release()
659 retval = -ENODEV; /* close called more than once */ in iowarrior_release()
660 mutex_unlock(&dev->mutex); in iowarrior_release()
662 dev->opened = 0; /* we're closing now */ in iowarrior_release()
664 if (dev->present) { in iowarrior_release()
667 pending read-/write-ops. in iowarrior_release()
669 usb_kill_urb(dev->int_in_urb); in iowarrior_release()
670 wake_up_interruptible(&dev->read_wait); in iowarrior_release()
671 wake_up_interruptible(&dev->write_wait); in iowarrior_release()
672 mutex_unlock(&dev->mutex); in iowarrior_release()
675 mutex_unlock(&dev->mutex); in iowarrior_release()
684 struct iowarrior *dev = file->private_data; in iowarrior_poll()
687 if (!dev->present) in iowarrior_poll()
690 poll_wait(file, &dev->read_wait, wait); in iowarrior_poll()
691 poll_wait(file, &dev->write_wait, wait); in iowarrior_poll()
693 if (!dev->present) in iowarrior_poll()
696 if (read_index(dev) != -1) in iowarrior_poll()
699 if (atomic_read(&dev->write_busy) < MAX_WRITES_IN_FLIGHT) in iowarrior_poll()
716 .read = iowarrior_read,
740 /*---------------------------------*/
742 /*---------------------------------*/
755 int retval = -ENOMEM; in iowarrior_probe()
763 mutex_init(&dev->mutex); in iowarrior_probe()
765 atomic_set(&dev->intr_idx, 0); in iowarrior_probe()
766 atomic_set(&dev->read_idx, 0); in iowarrior_probe()
767 atomic_set(&dev->overflow_flag, 0); in iowarrior_probe()
768 init_waitqueue_head(&dev->read_wait); in iowarrior_probe()
769 atomic_set(&dev->write_busy, 0); in iowarrior_probe()
770 init_waitqueue_head(&dev->write_wait); in iowarrior_probe()
772 dev->udev = udev; in iowarrior_probe()
773 dev->interface = usb_get_intf(interface); in iowarrior_probe()
775 iface_desc = interface->cur_altsetting; in iowarrior_probe()
776 dev->product_id = le16_to_cpu(udev->descriptor.idProduct); in iowarrior_probe()
778 init_usb_anchor(&dev->submitted); in iowarrior_probe()
780 res = usb_find_last_int_in_endpoint(iface_desc, &dev->int_in_endpoint); in iowarrior_probe()
782 dev_err(&interface->dev, "no interrupt-in endpoint found\n"); in iowarrior_probe()
787 if ((dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) || in iowarrior_probe()
788 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56AM) || in iowarrior_probe()
789 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28) || in iowarrior_probe()
790 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28L) || in iowarrior_probe()
791 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW100)) { in iowarrior_probe()
793 &dev->int_out_endpoint); in iowarrior_probe()
795 dev_err(&interface->dev, "no interrupt-out endpoint found\n"); in iowarrior_probe()
802 dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint); in iowarrior_probe()
808 if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { in iowarrior_probe()
809 switch (dev->product_id) { in iowarrior_probe()
812 dev->report_size = 7; in iowarrior_probe()
817 dev->report_size = 4; in iowarrior_probe()
821 dev->report_size = 13; in iowarrior_probe()
827 dev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); in iowarrior_probe()
828 if (!dev->int_in_urb) in iowarrior_probe()
830 dev->int_in_buffer = kmalloc(dev->report_size, GFP_KERNEL); in iowarrior_probe()
831 if (!dev->int_in_buffer) in iowarrior_probe()
833 usb_fill_int_urb(dev->int_in_urb, dev->udev, in iowarrior_probe()
834 usb_rcvintpipe(dev->udev, in iowarrior_probe()
835 dev->int_in_endpoint->bEndpointAddress), in iowarrior_probe()
836 dev->int_in_buffer, dev->report_size, in iowarrior_probe()
838 dev->int_in_endpoint->bInterval); in iowarrior_probe()
840 dev->read_queue = in iowarrior_probe()
841 kmalloc_array(dev->report_size + 1, MAX_INTERRUPT_BUFFER, in iowarrior_probe()
843 if (!dev->read_queue) in iowarrior_probe()
845 /* Get the serial-number of the chip */ in iowarrior_probe()
846 memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); in iowarrior_probe()
847 usb_string(udev, udev->descriptor.iSerialNumber, dev->chip_serial, in iowarrior_probe()
848 sizeof(dev->chip_serial)); in iowarrior_probe()
849 if (strlen(dev->chip_serial) != 8) in iowarrior_probe()
850 memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); in iowarrior_probe()
853 if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { in iowarrior_probe()
859 /* allow device read and ioctl */ in iowarrior_probe()
860 dev->present = 1; in iowarrior_probe()
868 dev_err(&interface->dev, "Not able to get a minor for this device.\n"); in iowarrior_probe()
872 dev->minor = interface->minor; in iowarrior_probe()
875 dev_info(&interface->dev, "IOWarrior product=0x%x, serial=%s interface=%d " in iowarrior_probe()
876 "now attached to iowarrior%d\n", dev->product_id, dev->chip_serial, in iowarrior_probe()
877 iface_desc->desc.bInterfaceNumber, dev->minor - IOWARRIOR_MINOR_BASE); in iowarrior_probe()
893 int minor = dev->minor; in iowarrior_disconnect()
897 mutex_lock(&dev->mutex); in iowarrior_disconnect()
899 /* prevent device read, write and ioctl */ in iowarrior_disconnect()
900 dev->present = 0; in iowarrior_disconnect()
902 if (dev->opened) { in iowarrior_disconnect()
904 so we only shutdown read-/write-ops going on. in iowarrior_disconnect()
907 usb_kill_urb(dev->int_in_urb); in iowarrior_disconnect()
908 usb_kill_anchored_urbs(&dev->submitted); in iowarrior_disconnect()
909 wake_up_interruptible(&dev->read_wait); in iowarrior_disconnect()
910 wake_up_interruptible(&dev->write_wait); in iowarrior_disconnect()
911 mutex_unlock(&dev->mutex); in iowarrior_disconnect()
913 /* no process is using the device, cleanup now */ in iowarrior_disconnect()
914 mutex_unlock(&dev->mutex); in iowarrior_disconnect()
918 dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n", in iowarrior_disconnect()
919 minor - IOWARRIOR_MINOR_BASE); in iowarrior_disconnect()