/** * usb_alphatrack_read */ static ssize_t usb_alphatrack_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct usb_alphatrack *dev; int retval = 0; int c = 0; dev = file->private_data; /* verify that we actually have some data to read */ if (count == 0) goto exit; /* lock this object */ if (down_interruptible(&dev->sem)) { retval = -ERESTARTSYS; goto exit; } /* verify that the device wasn't unplugged */ if (dev->intf == NULL) { retval = -ENODEV; err("No device or device unplugged %d\n", retval); goto unlock_exit; } while (dev->ring_head == dev->ring_tail) { if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; goto unlock_exit; } dev->interrupt_in_done = 0 ; retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done); if (retval < 0) { goto unlock_exit; } } alphatrack_ocmd_info(&dev->intf->dev, &(*dev->ring_buffer)[dev->ring_tail].cmd, "%s", ": copying to userspace"); c = 0; while((c < count) && (dev->ring_tail != dev->ring_head)) { if (copy_to_user(&buffer[c], &(*dev->ring_buffer)[dev->ring_tail], INPUT_CMD_SIZE)) { retval = -EFAULT; goto unlock_exit; } dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size; c+=INPUT_CMD_SIZE; dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __func__,dev->ring_head,dev->ring_tail); } retval = c; unlock_exit: /* unlock the device */ up(&dev->sem); exit: return retval; }
static void usb_alphatrack_interrupt_in_callback(struct urb *urb) { struct usb_alphatrack *dev = urb->context; unsigned int next_ring_head; int retval = -1; if (urb->status) { if (urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN) { goto exit; } else { dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n", __func__, urb->status); goto resubmit; /* maybe we can recover */ } } if (urb->actual_length != INPUT_CMD_SIZE) { dev_warn(&dev->intf->dev, "Urb length was %d bytes!!" "Do something intelligent \n", urb->actual_length); } else { alphatrack_ocmd_info(&dev->intf->dev, &(*dev->ring_buffer)[dev->ring_tail].cmd, "%s", "bla"); if (memcmp (dev->interrupt_in_buffer, dev->oldi_buffer, INPUT_CMD_SIZE) == 0) { goto resubmit; } memcpy(dev->oldi_buffer, dev->interrupt_in_buffer, INPUT_CMD_SIZE); #if SUPPRESS_EXTRA_OFFLINE_EVENTS if (dev->offline == 2 && dev->interrupt_in_buffer[1] == 0xff) goto resubmit; if (dev->offline == 1 && dev->interrupt_in_buffer[1] == 0xff) { dev->offline = 2; goto resubmit; } /* Always pass one offline event up the stack */ if (dev->offline > 0 && dev->interrupt_in_buffer[1] != 0xff) dev->offline = 0; if (dev->offline == 0 && dev->interrupt_in_buffer[1] == 0xff) dev->offline = 1; #endif dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __func__, dev->ring_head, dev->ring_tail); next_ring_head = (dev->ring_head + 1) % ring_buffer_size; if (next_ring_head != dev->ring_tail) { memcpy(&((*dev->ring_buffer)[dev->ring_head]), dev->interrupt_in_buffer, urb->actual_length); dev->ring_head = next_ring_head; retval = 0; memset(dev->interrupt_in_buffer, 0, urb->actual_length); } else { dev_warn(&dev->intf->dev, "Ring buffer overflow, %d bytes dropped\n", urb->actual_length); memset(dev->interrupt_in_buffer, 0, urb->actual_length); } } resubmit: /* resubmit if we're still running */ if (dev->interrupt_in_running && dev->intf) { retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); if (retval) dev_err(&dev->intf->dev, "usb_submit_urb failed (%d)\n", retval); } exit: dev->interrupt_in_done = 1; wake_up_interruptible(&dev->read_wait); }