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 /*--------------*/
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()
281 dev = file->private_data; in iowarrior_read()
284 if (!dev || !dev->present) in iowarrior_read()
285 return -ENODEV; in iowarrior_read()
287 dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n", in iowarrior_read()
288 dev->minor, count); in iowarrior_read()
290 /* read count must be packet size (+ time stamp) */ in iowarrior_read()
291 if ((count != dev->report_size) in iowarrior_read()
292 && (count != (dev->report_size + 1))) in iowarrior_read()
293 return -EINVAL; in iowarrior_read()
295 /* repeat until no buffer overrun in callback handler occur */ in iowarrior_read()
297 atomic_set(&dev->overflow_flag, 0); in iowarrior_read()
298 if ((read_idx = read_index(dev)) == -1) { in iowarrior_read()
300 if (file->f_flags & O_NONBLOCK) in iowarrior_read()
301 return -EAGAIN; in iowarrior_read()
304 int r = wait_event_interruptible(dev->read_wait, in iowarrior_read()
305 (!dev->present in iowarrior_read()
309 -1)); in iowarrior_read()
312 return -ERESTART; in iowarrior_read()
314 if (!dev->present) { in iowarrior_read()
316 return -ENODEV; in iowarrior_read()
318 if (read_idx == -1) { in iowarrior_read()
325 offset = read_idx * (dev->report_size + 1); in iowarrior_read()
326 if (copy_to_user(buffer, dev->read_queue + offset, count)) { in iowarrior_read()
327 return -EFAULT; in iowarrior_read()
329 } while (atomic_read(&dev->overflow_flag)); in iowarrior_read()
332 atomic_set(&dev->read_idx, read_idx); in iowarrior_read()
348 dev = file->private_data; in iowarrior_write()
350 mutex_lock(&dev->mutex); in iowarrior_write()
352 if (!dev->present) { in iowarrior_write()
353 retval = -ENODEV; in iowarrior_write()
356 dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n", in iowarrior_write()
357 dev->minor, count); in iowarrior_write()
364 if (count != dev->report_size) { in iowarrior_write()
365 retval = -EINVAL; in iowarrior_write()
368 switch (dev->product_id) { in iowarrior_write()
380 retval = usb_set_report(dev->interface, 2, 0, buf, count); in iowarrior_write()
389 if (atomic_read(&dev->write_busy) == MAX_WRITES_IN_FLIGHT) { in iowarrior_write()
391 if (file->f_flags & O_NONBLOCK) { in iowarrior_write()
392 retval = -EAGAIN; in iowarrior_write()
395 retval = wait_event_interruptible(dev->write_wait, in iowarrior_write()
396 (!dev->present || (atomic_read (&dev-> write_busy) < MAX_WRITES_IN_FLIGHT))); in iowarrior_write()
399 retval = -ERESTART; in iowarrior_write()
402 if (!dev->present) { in iowarrior_write()
404 retval = -ENODEV; in iowarrior_write()
407 if (!dev->opened) { in iowarrior_write()
409 retval = -ENODEV; in iowarrior_write()
414 atomic_inc(&dev->write_busy); in iowarrior_write()
417 retval = -ENOMEM; in iowarrior_write()
420 buf = usb_alloc_coherent(dev->udev, dev->report_size, in iowarrior_write()
421 GFP_KERNEL, &int_out_urb->transfer_dma); in iowarrior_write()
423 retval = -ENOMEM; in iowarrior_write()
424 dev_dbg(&dev->interface->dev, in iowarrior_write()
428 usb_fill_int_urb(int_out_urb, dev->udev, in iowarrior_write()
429 usb_sndintpipe(dev->udev, in iowarrior_write()
430 dev->int_out_endpoint->bEndpointAddress), in iowarrior_write()
431 buf, dev->report_size, in iowarrior_write()
433 dev->int_out_endpoint->bInterval); in iowarrior_write()
434 int_out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; in iowarrior_write()
436 retval = -EFAULT; in iowarrior_write()
439 usb_anchor_urb(int_out_urb, &dev->submitted); in iowarrior_write()
442 dev_dbg(&dev->interface->dev, in iowarrior_write()
444 retval, atomic_read(&dev->write_busy)); in iowarrior_write()
453 /* what do we have here ? An unsupported Product-ID ? */ in iowarrior_write()
454 dev_err(&dev->interface->dev, "%s - not supported for product=0x%x\n", in iowarrior_write()
455 __func__, dev->product_id); in iowarrior_write()
456 retval = -EFAULT; in iowarrior_write()
460 usb_free_coherent(dev->udev, dev->report_size, buf, in iowarrior_write()
461 int_out_urb->transfer_dma); in iowarrior_write()
465 atomic_dec(&dev->write_busy); in iowarrior_write()
466 wake_up_interruptible(&dev->write_wait); in iowarrior_write()
468 mutex_unlock(&dev->mutex); in iowarrior_write()
482 int io_res; /* checks for bytes read/written and copy_to/from_user results */ in iowarrior_ioctl()
484 dev = file->private_data; in iowarrior_ioctl()
486 return -ENODEV; in iowarrior_ioctl()
488 buffer = kzalloc(dev->report_size, GFP_KERNEL); in iowarrior_ioctl()
490 return -ENOMEM; in iowarrior_ioctl()
492 mutex_lock(&dev->mutex); in iowarrior_ioctl()
495 if (!dev->present) { in iowarrior_ioctl()
496 retval = -ENODEV; in iowarrior_ioctl()
500 dev_dbg(&dev->interface->dev, "minor %d, cmd 0x%.4x, arg %ld\n", in iowarrior_ioctl()
501 dev->minor, cmd, arg); in iowarrior_ioctl()
506 if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 || in iowarrior_ioctl()
507 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24SAG || in iowarrior_ioctl()
508 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 || in iowarrior_ioctl()
509 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 || in iowarrior_ioctl()
510 dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) { in iowarrior_ioctl()
513 dev->report_size); in iowarrior_ioctl()
515 retval = -EFAULT; in iowarrior_ioctl()
517 io_res = usb_set_report(dev->interface, 2, 0, in iowarrior_ioctl()
519 dev->report_size); in iowarrior_ioctl()
524 retval = -EINVAL; in iowarrior_ioctl()
525 dev_err(&dev->interface->dev, in iowarrior_ioctl()
527 dev->product_id); in iowarrior_ioctl()
532 io_res = usb_get_report(dev->udev, in iowarrior_ioctl()
533 dev->interface->cur_altsetting, 1, 0, in iowarrior_ioctl()
534 buffer, dev->report_size); in iowarrior_ioctl()
538 io_res = copy_to_user(user_buffer, buffer, dev->report_size); in iowarrior_ioctl()
540 retval = -EFAULT; in iowarrior_ioctl()
548 struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc; in iowarrior_ioctl()
552 info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); in iowarrior_ioctl()
553 info.product = dev->product_id; in iowarrior_ioctl()
554 info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice); in iowarrior_ioctl()
557 info.speed = dev->udev->speed; in iowarrior_ioctl()
558 info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber; in iowarrior_ioctl()
559 info.report_size = dev->report_size; in iowarrior_ioctl()
561 /* serial number string has been read earlier 8 chars or empty string */ in iowarrior_ioctl()
562 memcpy(info.serial, dev->chip_serial, in iowarrior_ioctl()
563 sizeof(dev->chip_serial)); in iowarrior_ioctl()
565 info.power = -1; /* no information available */ in iowarrior_ioctl()
567 /* the MaxPower is stored in units of 2mA to make it fit into a byte-value */ in iowarrior_ioctl()
568 info.power = cfg_descriptor->bMaxPower * 2; in iowarrior_ioctl()
573 retval = -EFAULT; in iowarrior_ioctl()
578 retval = -ENOTTY; in iowarrior_ioctl()
583 mutex_unlock(&dev->mutex); in iowarrior_ioctl()
602 pr_err("%s - error, can't find device for minor %d\n", in iowarrior_open()
604 return -ENODEV; in iowarrior_open()
609 return -ENODEV; in iowarrior_open()
611 mutex_lock(&dev->mutex); in iowarrior_open()
613 /* Only one process can open each device, no sharing. */ in iowarrior_open()
614 if (dev->opened) { in iowarrior_open()
615 retval = -EBUSY; in iowarrior_open()
620 if ((retval = usb_submit_urb(dev->int_in_urb, GFP_KERNEL)) < 0) { in iowarrior_open()
621 dev_err(&interface->dev, "Error %d while submitting URB\n", retval); in iowarrior_open()
622 retval = -EFAULT; in iowarrior_open()
626 ++dev->opened; in iowarrior_open()
628 file->private_data = dev; in iowarrior_open()
632 mutex_unlock(&dev->mutex); in iowarrior_open()
644 dev = file->private_data; in iowarrior_release()
646 return -ENODEV; in iowarrior_release()
648 dev_dbg(&dev->interface->dev, "minor %d\n", dev->minor); in iowarrior_release()
651 mutex_lock(&dev->mutex); in iowarrior_release()
653 if (dev->opened <= 0) { in iowarrior_release()
654 retval = -ENODEV; /* close called more than once */ in iowarrior_release()
655 mutex_unlock(&dev->mutex); in iowarrior_release()
657 dev->opened = 0; /* we're closing now */ in iowarrior_release()
659 if (dev->present) { in iowarrior_release()
662 pending read-/write-ops. in iowarrior_release()
664 usb_kill_urb(dev->int_in_urb); in iowarrior_release()
665 wake_up_interruptible(&dev->read_wait); in iowarrior_release()
666 wake_up_interruptible(&dev->write_wait); in iowarrior_release()
667 mutex_unlock(&dev->mutex); in iowarrior_release()
670 mutex_unlock(&dev->mutex); in iowarrior_release()
679 struct iowarrior *dev = file->private_data; in iowarrior_poll()
682 if (!dev->present) in iowarrior_poll()
685 poll_wait(file, &dev->read_wait, wait); in iowarrior_poll()
686 poll_wait(file, &dev->write_wait, wait); in iowarrior_poll()
688 if (!dev->present) in iowarrior_poll()
691 if (read_index(dev) != -1) in iowarrior_poll()
694 if (atomic_read(&dev->write_busy) < MAX_WRITES_IN_FLIGHT) in iowarrior_poll()
711 .read = iowarrior_read,
735 /*---------------------------------*/
737 /*---------------------------------*/
750 int retval = -ENOMEM; in iowarrior_probe()
758 mutex_init(&dev->mutex); in iowarrior_probe()
760 atomic_set(&dev->intr_idx, 0); in iowarrior_probe()
761 atomic_set(&dev->read_idx, 0); in iowarrior_probe()
762 atomic_set(&dev->overflow_flag, 0); in iowarrior_probe()
763 init_waitqueue_head(&dev->read_wait); in iowarrior_probe()
764 atomic_set(&dev->write_busy, 0); in iowarrior_probe()
765 init_waitqueue_head(&dev->write_wait); in iowarrior_probe()
767 dev->udev = udev; in iowarrior_probe()
768 dev->interface = usb_get_intf(interface); in iowarrior_probe()
770 iface_desc = interface->cur_altsetting; in iowarrior_probe()
771 dev->product_id = le16_to_cpu(udev->descriptor.idProduct); in iowarrior_probe()
773 init_usb_anchor(&dev->submitted); in iowarrior_probe()
775 res = usb_find_last_int_in_endpoint(iface_desc, &dev->int_in_endpoint); in iowarrior_probe()
777 dev_err(&interface->dev, "no interrupt-in endpoint found\n"); in iowarrior_probe()
782 if ((dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) || in iowarrior_probe()
783 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56AM) || in iowarrior_probe()
784 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28) || in iowarrior_probe()
785 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28L) || in iowarrior_probe()
786 (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW100)) { in iowarrior_probe()
788 &dev->int_out_endpoint); in iowarrior_probe()
790 dev_err(&interface->dev, "no interrupt-out endpoint found\n"); in iowarrior_probe()
797 dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint); in iowarrior_probe()
803 if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { in iowarrior_probe()
804 switch (dev->product_id) { in iowarrior_probe()
807 dev->report_size = 7; in iowarrior_probe()
812 dev->report_size = 4; in iowarrior_probe()
816 dev->report_size = 12; in iowarrior_probe()
822 dev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); in iowarrior_probe()
823 if (!dev->int_in_urb) in iowarrior_probe()
825 dev->int_in_buffer = kmalloc(dev->report_size, GFP_KERNEL); in iowarrior_probe()
826 if (!dev->int_in_buffer) in iowarrior_probe()
828 usb_fill_int_urb(dev->int_in_urb, dev->udev, in iowarrior_probe()
829 usb_rcvintpipe(dev->udev, in iowarrior_probe()
830 dev->int_in_endpoint->bEndpointAddress), in iowarrior_probe()
831 dev->int_in_buffer, dev->report_size, in iowarrior_probe()
833 dev->int_in_endpoint->bInterval); in iowarrior_probe()
835 dev->read_queue = in iowarrior_probe()
836 kmalloc_array(dev->report_size + 1, MAX_INTERRUPT_BUFFER, in iowarrior_probe()
838 if (!dev->read_queue) in iowarrior_probe()
840 /* Get the serial-number of the chip */ in iowarrior_probe()
841 memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); in iowarrior_probe()
842 usb_string(udev, udev->descriptor.iSerialNumber, dev->chip_serial, in iowarrior_probe()
843 sizeof(dev->chip_serial)); in iowarrior_probe()
844 if (strlen(dev->chip_serial) != 8) in iowarrior_probe()
845 memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); in iowarrior_probe()
848 if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { in iowarrior_probe()
854 /* allow device read and ioctl */ in iowarrior_probe()
855 dev->present = 1; in iowarrior_probe()
863 dev_err(&interface->dev, "Not able to get a minor for this device.\n"); in iowarrior_probe()
867 dev->minor = interface->minor; in iowarrior_probe()
870 dev_info(&interface->dev, "IOWarrior product=0x%x, serial=%s interface=%d " in iowarrior_probe()
871 "now attached to iowarrior%d\n", dev->product_id, dev->chip_serial, in iowarrior_probe()
872 iface_desc->desc.bInterfaceNumber, dev->minor - IOWARRIOR_MINOR_BASE); in iowarrior_probe()
888 int minor = dev->minor; in iowarrior_disconnect()
892 mutex_lock(&dev->mutex); in iowarrior_disconnect()
894 /* prevent device read, write and ioctl */ in iowarrior_disconnect()
895 dev->present = 0; in iowarrior_disconnect()
897 if (dev->opened) { in iowarrior_disconnect()
899 so we only shutdown read-/write-ops going on. in iowarrior_disconnect()
902 usb_kill_urb(dev->int_in_urb); in iowarrior_disconnect()
903 usb_kill_anchored_urbs(&dev->submitted); in iowarrior_disconnect()
904 wake_up_interruptible(&dev->read_wait); in iowarrior_disconnect()
905 wake_up_interruptible(&dev->write_wait); in iowarrior_disconnect()
906 mutex_unlock(&dev->mutex); in iowarrior_disconnect()
908 /* no process is using the device, cleanup now */ in iowarrior_disconnect()
909 mutex_unlock(&dev->mutex); in iowarrior_disconnect()
913 dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n", in iowarrior_disconnect()
914 minor - IOWARRIOR_MINOR_BASE); in iowarrior_disconnect()