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()
394 if (atomic_read(&dev->write_busy) == MAX_WRITES_IN_FLIGHT) { in iowarrior_write()
396 if (file->f_flags & O_NONBLOCK) { in iowarrior_write()
397 retval = -EAGAIN; in iowarrior_write()
400 retval = wait_event_interruptible(dev->write_wait, in iowarrior_write()
401 (!dev->present || (atomic_read (&dev-> write_busy) < MAX_WRITES_IN_FLIGHT))); in iowarrior_write()
404 retval = -ERESTART; in iowarrior_write()
407 if (!dev->present) { in iowarrior_write()
409 retval = -ENODEV; in iowarrior_write()
412 if (!dev->opened) { in iowarrior_write()
414 retval = -ENODEV; in iowarrior_write()
419 atomic_inc(&dev->write_busy); in iowarrior_write()
422 retval = -ENOMEM; in iowarrior_write()
425 buf = usb_alloc_coherent(dev->udev, dev->report_size, in iowarrior_write()
426 GFP_KERNEL, &int_out_urb->transfer_dma); in iowarrior_write()
428 retval = -ENOMEM; in iowarrior_write()
429 dev_dbg(&dev->interface->dev, in iowarrior_write()
433 usb_fill_int_urb(int_out_urb, dev->udev, in iowarrior_write()
434 usb_sndintpipe(dev->udev, in iowarrior_write()
435 dev->int_out_endpoint->bEndpointAddress), in iowarrior_write()
436 buf, dev->report_size, in iowarrior_write()
438 dev->int_out_endpoint->bInterval); in iowarrior_write()
439 int_out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; in iowarrior_write()
441 retval = -EFAULT; in iowarrior_write()
444 usb_anchor_urb(int_out_urb, &dev->submitted); in iowarrior_write()
447 dev_dbg(&dev->interface->dev, in iowarrior_write()
449 retval, atomic_read(&dev->write_busy)); in iowarrior_write()
459 /* what do we have here ? An unsupported Product-ID ? */ in iowarrior_write()
460 dev_err(&dev->interface->dev, "%s - not supported for product=0x%x\n", in iowarrior_write()
461 __func__, dev->product_id); in iowarrior_write()
462 retval = -EFAULT; in iowarrior_write()
467 usb_free_coherent(dev->udev, dev->report_size, buf, in iowarrior_write()
468 int_out_urb->transfer_dma); in iowarrior_write()
472 atomic_dec(&dev->write_busy); in iowarrior_write()
473 wake_up_interruptible(&dev->write_wait); in iowarrior_write()
475 mutex_unlock(&dev->mutex); in iowarrior_write()
489 int io_res; /* checks for bytes read/written and copy_to/from_user results */ in iowarrior_ioctl()
491 dev = file->private_data; in iowarrior_ioctl()
493 return -ENODEV; in iowarrior_ioctl()
495 buffer = kzalloc(dev->report_size, GFP_KERNEL); in iowarrior_ioctl()
497 return -ENOMEM; in iowarrior_ioctl()
499 mutex_lock(&dev->mutex); in iowarrior_ioctl()
502 if (!dev->present) { in iowarrior_ioctl()
503 retval = -ENODEV; in iowarrior_ioctl()
507 dev_dbg(&dev->interface->dev, "minor %d, cmd 0x%.4x, arg %ld\n", in iowarrior_ioctl()
508 dev->minor, cmd, arg); in iowarrior_ioctl()
514 if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 || in iowarrior_ioctl()
515 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24SAG || in iowarrior_ioctl()
516 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 || in iowarrior_ioctl()
517 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 || in iowarrior_ioctl()
518 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) { in iowarrior_ioctl()
521 dev->report_size); in iowarrior_ioctl()
523 retval = -EFAULT; in iowarrior_ioctl()
525 io_res = usb_set_report(dev->interface, 2, 0, in iowarrior_ioctl()
527 dev->report_size); in iowarrior_ioctl()
532 retval = -EINVAL; in iowarrior_ioctl()
533 dev_err(&dev->interface->dev, in iowarrior_ioctl()
535 dev->product_id); in iowarrior_ioctl()
540 io_res = usb_get_report(dev->udev, in iowarrior_ioctl()
541 dev->interface->cur_altsetting, 1, 0, in iowarrior_ioctl()
542 buffer, dev->report_size); in iowarrior_ioctl()
546 io_res = copy_to_user(user_buffer, buffer, dev->report_size); in iowarrior_ioctl()
548 retval = -EFAULT; in iowarrior_ioctl()
556 struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc; in iowarrior_ioctl()
560 info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); in iowarrior_ioctl()
561 info.product = dev->product_id; in iowarrior_ioctl()
562 info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice); in iowarrior_ioctl()
565 info.speed = dev->udev->speed; in iowarrior_ioctl()
566 info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber; in iowarrior_ioctl()
567 info.report_size = dev->report_size; in iowarrior_ioctl()
569 /* serial number string has been read earlier 8 chars or empty string */ in iowarrior_ioctl()
570 memcpy(info.serial, dev->chip_serial, in iowarrior_ioctl()
571 sizeof(dev->chip_serial)); in iowarrior_ioctl()
573 info.power = -1; /* no information available */ in iowarrior_ioctl()
575 /* the MaxPower is stored in units of 2mA to make it fit into a byte-value */ in iowarrior_ioctl()
576 info.power = cfg_descriptor->bMaxPower * 2; in iowarrior_ioctl()
581 retval = -EFAULT; in iowarrior_ioctl()
586 retval = -ENOTTY; in iowarrior_ioctl()
591 mutex_unlock(&dev->mutex); in iowarrior_ioctl()
610 pr_err("%s - error, can't find device for minor %d\n", in iowarrior_open()
612 return -ENODEV; in iowarrior_open()
617 return -ENODEV; in iowarrior_open()
619 mutex_lock(&dev->mutex); in iowarrior_open()
621 /* Only one process can open each device, no sharing. */ in iowarrior_open()
622 if (dev->opened) { in iowarrior_open()
623 retval = -EBUSY; in iowarrior_open()
628 if ((retval = usb_submit_urb(dev->int_in_urb, GFP_KERNEL)) < 0) { in iowarrior_open()
629 dev_err(&interface->dev, "Error %d while submitting URB\n", retval); in iowarrior_open()
630 retval = -EFAULT; in iowarrior_open()
634 ++dev->opened; in iowarrior_open()
636 file->private_data = dev; in iowarrior_open()
640 mutex_unlock(&dev->mutex); in iowarrior_open()
652 dev = file->private_data; in iowarrior_release()
654 return -ENODEV; in iowarrior_release()
656 dev_dbg(&dev->interface->dev, "minor %d\n", dev->minor); in iowarrior_release()
659 mutex_lock(&dev->mutex); in iowarrior_release()
661 if (dev->opened <= 0) { in iowarrior_release()
662 retval = -ENODEV; /* close called more than once */ in iowarrior_release()
663 mutex_unlock(&dev->mutex); in iowarrior_release()
665 dev->opened = 0; /* we're closing now */ in iowarrior_release()
667 if (dev->present) { in iowarrior_release()
670 pending read-/write-ops. in iowarrior_release()
672 usb_kill_urb(dev->int_in_urb); in iowarrior_release()
673 wake_up_interruptible(&dev->read_wait); in iowarrior_release()
674 wake_up_interruptible(&dev->write_wait); in iowarrior_release()
675 mutex_unlock(&dev->mutex); in iowarrior_release()
678 mutex_unlock(&dev->mutex); in iowarrior_release()
687 struct iowarrior *dev = file->private_data; in iowarrior_poll()
690 if (!dev->present) in iowarrior_poll()
693 poll_wait(file, &dev->read_wait, wait); in iowarrior_poll()
694 poll_wait(file, &dev->write_wait, wait); in iowarrior_poll()
696 if (!dev->present) in iowarrior_poll()
699 if (read_index(dev) != -1) in iowarrior_poll()
702 if (atomic_read(&dev->write_busy) < MAX_WRITES_IN_FLIGHT) in iowarrior_poll()
719 .read = iowarrior_read,
743 /*---------------------------------*/
745 /*---------------------------------*/
758 int retval = -ENOMEM; in iowarrior_probe()
766 mutex_init(&dev->mutex); in iowarrior_probe()
768 atomic_set(&dev->intr_idx, 0); in iowarrior_probe()
769 atomic_set(&dev->read_idx, 0); in iowarrior_probe()
770 atomic_set(&dev->overflow_flag, 0); in iowarrior_probe()
771 init_waitqueue_head(&dev->read_wait); in iowarrior_probe()
772 atomic_set(&dev->write_busy, 0); in iowarrior_probe()
773 init_waitqueue_head(&dev->write_wait); in iowarrior_probe()
775 dev->udev = udev; in iowarrior_probe()
776 dev->interface = usb_get_intf(interface); in iowarrior_probe()
778 iface_desc = interface->cur_altsetting; in iowarrior_probe()
779 dev->product_id = le16_to_cpu(udev->descriptor.idProduct); in iowarrior_probe()
781 init_usb_anchor(&dev->submitted); in iowarrior_probe()
783 res = usb_find_last_int_in_endpoint(iface_desc, &dev->int_in_endpoint); in iowarrior_probe()
785 dev_err(&interface->dev, "no interrupt-in endpoint found\n"); in iowarrior_probe()
790 if ((dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) || in iowarrior_probe()
791 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56AM) || in iowarrior_probe()
792 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28) || in iowarrior_probe()
793 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28L) || in iowarrior_probe()
794 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW100)) { in iowarrior_probe()
796 &dev->int_out_endpoint); in iowarrior_probe()
798 dev_err(&interface->dev, "no interrupt-out endpoint found\n"); in iowarrior_probe()
805 dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint); in iowarrior_probe()
811 if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { in iowarrior_probe()
812 switch (dev->product_id) { in iowarrior_probe()
815 dev->report_size = 7; in iowarrior_probe()
820 dev->report_size = 4; in iowarrior_probe()
824 dev->report_size = 13; in iowarrior_probe()
830 dev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); in iowarrior_probe()
831 if (!dev->int_in_urb) in iowarrior_probe()
833 dev->int_in_buffer = kmalloc(dev->report_size, GFP_KERNEL); in iowarrior_probe()
834 if (!dev->int_in_buffer) in iowarrior_probe()
836 usb_fill_int_urb(dev->int_in_urb, dev->udev, in iowarrior_probe()
837 usb_rcvintpipe(dev->udev, in iowarrior_probe()
838 dev->int_in_endpoint->bEndpointAddress), in iowarrior_probe()
839 dev->int_in_buffer, dev->report_size, in iowarrior_probe()
841 dev->int_in_endpoint->bInterval); in iowarrior_probe()
843 dev->read_queue = in iowarrior_probe()
844 kmalloc_array(dev->report_size + 1, MAX_INTERRUPT_BUFFER, in iowarrior_probe()
846 if (!dev->read_queue) in iowarrior_probe()
848 /* Get the serial-number of the chip */ in iowarrior_probe()
849 memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); in iowarrior_probe()
850 usb_string(udev, udev->descriptor.iSerialNumber, dev->chip_serial, in iowarrior_probe()
851 sizeof(dev->chip_serial)); in iowarrior_probe()
852 if (strlen(dev->chip_serial) != 8) in iowarrior_probe()
853 memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); in iowarrior_probe()
856 if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { in iowarrior_probe()
862 /* allow device read and ioctl */ in iowarrior_probe()
863 dev->present = 1; in iowarrior_probe()
871 dev_err(&interface->dev, "Not able to get a minor for this device.\n"); in iowarrior_probe()
875 dev->minor = interface->minor; in iowarrior_probe()
878 dev_info(&interface->dev, "IOWarrior product=0x%x, serial=%s interface=%d " in iowarrior_probe()
879 "now attached to iowarrior%d\n", dev->product_id, dev->chip_serial, in iowarrior_probe()
880 iface_desc->desc.bInterfaceNumber, dev->minor - IOWARRIOR_MINOR_BASE); in iowarrior_probe()
896 int minor = dev->minor; in iowarrior_disconnect()
900 mutex_lock(&dev->mutex); in iowarrior_disconnect()
902 /* prevent device read, write and ioctl */ in iowarrior_disconnect()
903 dev->present = 0; in iowarrior_disconnect()
905 if (dev->opened) { in iowarrior_disconnect()
907 so we only shutdown read-/write-ops going on. in iowarrior_disconnect()
910 usb_kill_urb(dev->int_in_urb); in iowarrior_disconnect()
911 usb_kill_anchored_urbs(&dev->submitted); in iowarrior_disconnect()
912 wake_up_interruptible(&dev->read_wait); in iowarrior_disconnect()
913 wake_up_interruptible(&dev->write_wait); in iowarrior_disconnect()
914 mutex_unlock(&dev->mutex); in iowarrior_disconnect()
916 /* no process is using the device, cleanup now */ in iowarrior_disconnect()
917 mutex_unlock(&dev->mutex); in iowarrior_disconnect()
921 dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n", in iowarrior_disconnect()
922 minor - IOWARRIOR_MINOR_BASE); in iowarrior_disconnect()