Beispiel #1
0
/**
 *	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);
}