Example #1
0
/**
 *	usb_alphatrack_disconnect
 *
 *	Called by the usb core when the device is removed from the system.
 */
static void usb_alphatrack_disconnect(struct usb_interface *intf)
{
	struct usb_alphatrack *dev;
	int minor;

	mutex_lock(&disconnect_mutex);

	dev = usb_get_intfdata(intf);
	usb_set_intfdata(intf, NULL);

	down(&dev->sem);

	minor = intf->minor;

	/* give back our minor */
	usb_deregister_dev(intf, &usb_alphatrack_class);

	/* if the device is not opened, then we clean up right now */
	if (!dev->open_count) {
		up(&dev->sem);
		usb_alphatrack_delete(dev);
	} else {
		dev->intf = NULL;
		up(&dev->sem);
	}

	atomic_set(&dev->writes_pending, 0);
	mutex_unlock(&disconnect_mutex);

	dev_info(&intf->dev, "Alphatrack Surface #%d now disconnected\n",
		 (minor - USB_ALPHATRACK_MINOR_BASE));
}
Example #2
0
/**
 *	usb_alphatrack_release
 */
static int usb_alphatrack_release(struct inode *inode, struct file *file)
{
	struct usb_alphatrack *dev;
	int retval = 0;

	dev = file->private_data;

	if (dev == NULL) {
		retval = -ENODEV;
		goto exit;
	}

	if (down_interruptible(&dev->sem)) {
		retval = -ERESTARTSYS;
		goto exit;
	}

	if (dev->open_count != 1) {
		retval = -ENODEV;
		goto unlock_exit;
	}

	if (dev->intf == NULL) {
		/* the device was unplugged before the file was released */
		up(&dev->sem);
		/* unlock here as usb_alphatrack_delete frees dev */
		usb_alphatrack_delete(dev);
		retval = -ENODEV;
		goto exit;
	}

	/* wait until write transfer is finished */
	if (dev->interrupt_out_busy)
		wait_event_interruptible_timeout(dev->write_wait,
						 !dev->interrupt_out_busy,
						 2 * HZ);
	usb_alphatrack_abort_transfers(dev);
	dev->open_count = 0;

unlock_exit:
	up(&dev->sem);

exit:
	return retval;
}
Example #3
0
static int usb_alphatrack_release(struct inode *inode, struct file *file)
{
	struct usb_alphatrack *dev;
	int retval = 0;

	dev = file->private_data;

	if (dev == NULL) {
		retval = -ENODEV;
		goto exit;
	}

	if (down_interruptible(&dev->sem)) {
		retval = -ERESTARTSYS;
		goto exit;
	}

	if (dev->open_count != 1) {
		retval = -ENODEV;
		goto unlock_exit;
	}

	if (dev->intf == NULL) {
		
		up(&dev->sem);
		
		usb_alphatrack_delete(dev);
		retval = -ENODEV;
		goto exit;
	}

	
	if (dev->interrupt_out_busy)
		wait_event_interruptible_timeout(dev->write_wait,
						 !dev->interrupt_out_busy,
						 2 * HZ);
	usb_alphatrack_abort_transfers(dev);
	dev->open_count = 0;

unlock_exit:
	up(&dev->sem);

exit:
	return retval;
}
Example #4
0
/**
 *	usb_alphatrack_probe
 *
 *	Called by the usb core when a new device is connected that it thinks
 *	this driver might be interested in.
 */
static int usb_alphatrack_probe(struct usb_interface *intf,
				const struct usb_device_id *id)
{
	struct usb_device *udev = interface_to_usbdev(intf);
	struct usb_alphatrack *dev = NULL;
	struct usb_host_interface *iface_desc;
	struct usb_endpoint_descriptor *endpoint;
	int i;
	int true_size;
	int retval = -ENOMEM;

	/* allocate memory for our device state and intialize it */

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (dev == NULL) {
		dev_err(&intf->dev, "Out of memory\n");
		goto exit;
	}
	init_MUTEX(&dev->sem);
	dev->intf = intf;
	init_waitqueue_head(&dev->read_wait);
	init_waitqueue_head(&dev->write_wait);

	iface_desc = intf->cur_altsetting;

	/* set up the endpoint information */
	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
		endpoint = &iface_desc->endpoint[i].desc;

		if (usb_endpoint_is_int_in(endpoint))
			dev->interrupt_in_endpoint = endpoint;

		if (usb_endpoint_is_int_out(endpoint))
			dev->interrupt_out_endpoint = endpoint;
	}
	if (dev->interrupt_in_endpoint == NULL) {
		dev_err(&intf->dev, "Interrupt in endpoint not found\n");
		goto error;
	}
	if (dev->interrupt_out_endpoint == NULL)
		dev_warn(&intf->dev,
			 "Interrupt out endpoint not found"
			 "(using control endpoint instead)\n");

	dev->interrupt_in_endpoint_size =
	    le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);

	if (dev->interrupt_in_endpoint_size != 64)
		dev_warn(&intf->dev, "Interrupt in endpoint size is not 64!\n");

	if (ring_buffer_size == 0)
		ring_buffer_size = RING_BUFFER_SIZE;

	true_size = min(ring_buffer_size, RING_BUFFER_SIZE);

	/* FIXME - there are more usb_alloc routines for dma correctness.
	   Needed? */
	dev->ring_buffer =
	    kmalloc((true_size * sizeof(struct alphatrack_icmd)), GFP_KERNEL);

	if (!dev->ring_buffer) {
		dev_err(&intf->dev,
			"Couldn't allocate input ring_buffer of size %d\n",
			true_size);
		goto error;
	}

	dev->interrupt_in_buffer =
	    kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL);

	if (!dev->interrupt_in_buffer) {
		dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n");
		goto error;
	}
	dev->oldi_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL);
	if (!dev->oldi_buffer) {
		dev_err(&intf->dev, "Couldn't allocate old buffer\n");
		goto error;
	}
	dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!dev->interrupt_in_urb) {
		dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n");
		goto error;
	}

	dev->interrupt_out_endpoint_size =
	    dev->interrupt_out_endpoint ? le16_to_cpu(dev->
						      interrupt_out_endpoint->
						      wMaxPacketSize) : udev->
	    descriptor.bMaxPacketSize0;

	if (dev->interrupt_out_endpoint_size != 64)
		dev_warn(&intf->dev,
			 "Interrupt out endpoint size is not 64!)\n");

	if (write_buffer_size == 0)
		write_buffer_size = WRITE_BUFFER_SIZE;
	true_size = min(write_buffer_size, WRITE_BUFFER_SIZE);

	dev->interrupt_out_buffer =
	    kmalloc(true_size * dev->interrupt_out_endpoint_size, GFP_KERNEL);

	if (!dev->interrupt_out_buffer) {
		dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n");
		goto error;
	}

	dev->write_buffer =
	    kmalloc(sizeof(struct alphatrack_ocmd) * true_size, GFP_KERNEL);

	if (!dev->write_buffer) {
		dev_err(&intf->dev, "Couldn't allocate write_buffer \n");
		goto error;
	}

	dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!dev->interrupt_out_urb) {
		dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n");
		goto error;
	}
	dev->interrupt_in_interval =
	    min_interrupt_in_interval >
	    dev->interrupt_in_endpoint->
	    bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->
	    bInterval;
	if (dev->interrupt_out_endpoint)
		dev->interrupt_out_interval =
		    min_interrupt_out_interval >
		    dev->interrupt_out_endpoint->
		    bInterval ? min_interrupt_out_interval : dev->
		    interrupt_out_endpoint->bInterval;

	/* we can register the device now, as it is ready */
	usb_set_intfdata(intf, dev);

	atomic_set(&dev->writes_pending, 0);
	retval = usb_register_dev(intf, &usb_alphatrack_class);
	if (retval) {
		/* something prevented us from registering this driver */
		dev_err(&intf->dev,
			"Not able to get a minor for this device.\n");
		usb_set_intfdata(intf, NULL);
		goto error;
	}

	/* let the user know what node this device is now attached to */
	dev_info(&intf->dev,
		 "Alphatrack Device #%d now attached to major %d minor %d\n",
		 (intf->minor - USB_ALPHATRACK_MINOR_BASE), USB_MAJOR,
		 intf->minor);

exit:
	return retval;

error:
	usb_alphatrack_delete(dev);

	return retval;
}