⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ldusb.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/** *	ld_usb_poll */static unsigned int ld_usb_poll(struct file *file, poll_table *wait){	struct ld_usb *dev;	unsigned int mask = 0;	dev = file->private_data;	poll_wait(file, &dev->read_wait, wait);	poll_wait(file, &dev->write_wait, wait);	if (dev->ring_head != dev->ring_tail)		mask |= POLLIN | POLLRDNORM;	if (!dev->interrupt_out_busy)		mask |= POLLOUT | POLLWRNORM;	return mask;}/** *	ld_usb_read */static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,			   loff_t *ppos){	struct ld_usb *dev;	size_t *actual_buffer;	size_t bytes_to_read;	int retval = 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;	}	/* wait for data */	if (dev->ring_head == dev->ring_tail) {		if (file->f_flags & O_NONBLOCK) {			retval = -EAGAIN;			goto unlock_exit;		}		retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);		if (retval < 0)			goto unlock_exit;	}	/* actual_buffer contains actual_length + interrupt_in_buffer */	actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_tail*(sizeof(size_t)+dev->interrupt_in_endpoint_size));	bytes_to_read = min(count, *actual_buffer);	if (bytes_to_read < *actual_buffer)		dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n",			 *actual_buffer-bytes_to_read);	/* copy one interrupt_in_buffer from ring_buffer into userspace */	if (copy_to_user(buffer, actual_buffer+1, bytes_to_read)) {		retval = -EFAULT;		goto unlock_exit;	}	dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;	retval = bytes_to_read;unlock_exit:	/* unlock the device */	up(&dev->sem);exit:	return retval;}/** *	ld_usb_write */static ssize_t ld_usb_write(struct file *file, const char __user *buffer,			    size_t count, loff_t *ppos){	struct ld_usb *dev;	size_t bytes_to_write;	int retval = 0;	dev = file->private_data;	/* verify that we actually have some data to write */	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;	}	/* wait until previous transfer is finished */	if (dev->interrupt_out_busy) {		if (file->f_flags & O_NONBLOCK) {			retval = -EAGAIN;			goto unlock_exit;		}		retval = wait_event_interruptible(dev->write_wait, !dev->interrupt_out_busy);		if (retval < 0) {			goto unlock_exit;		}	}	/* write the data into interrupt_out_buffer from userspace */	bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);	if (bytes_to_write < count)		dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write);	dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __FUNCTION__, count, bytes_to_write);	if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {		retval = -EFAULT;		goto unlock_exit;	}	if (dev->interrupt_out_endpoint == NULL) {		/* try HID_REQ_SET_REPORT=9 on control_endpoint instead of interrupt_out_endpoint */		retval = usb_control_msg(interface_to_usbdev(dev->intf),					 usb_sndctrlpipe(interface_to_usbdev(dev->intf), 0),					 9,					 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,					 1 << 8, 0,					 dev->interrupt_out_buffer,					 bytes_to_write,					 USB_CTRL_SET_TIMEOUT * HZ);		if (retval < 0)			err("Couldn't submit HID_REQ_SET_REPORT %d\n", retval);		goto unlock_exit;	}	/* send off the urb */	usb_fill_int_urb(dev->interrupt_out_urb,			 interface_to_usbdev(dev->intf),			 usb_sndintpipe(interface_to_usbdev(dev->intf),					dev->interrupt_out_endpoint->bEndpointAddress),			 dev->interrupt_out_buffer,			 bytes_to_write,			 ld_usb_interrupt_out_callback,			 dev,			 dev->interrupt_out_interval);	dev->interrupt_out_busy = 1;	wmb();	retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);	if (retval) {		dev->interrupt_out_busy = 0;		err("Couldn't submit interrupt_out_urb %d\n", retval);		goto unlock_exit;	}	retval = bytes_to_write;unlock_exit:	/* unlock the device */	up(&dev->sem);exit:	return retval;}/* file operations needed when we register this driver */static struct file_operations ld_usb_fops = {	.owner =	THIS_MODULE,	.read  =	ld_usb_read,	.write =	ld_usb_write,	.open =		ld_usb_open,	.release =	ld_usb_release,	.poll =		ld_usb_poll,};/* * usb class driver info in order to get a minor number from the usb core, * and to have the device registered with devfs and the driver core */static struct usb_class_driver ld_usb_class = {	.name =		"ldusb%d",	.fops =		&ld_usb_fops,	.minor_base =	USB_LD_MINOR_BASE,};/** *	ld_usb_probe * *	Called by the usb core when a new device is connected that it thinks *	this driver might be interested in. */static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *id){	struct usb_device *udev = interface_to_usbdev(intf);	struct ld_usb *dev = NULL;	struct usb_host_interface *iface_desc;	struct usb_endpoint_descriptor *endpoint;	char *buffer;	int i;	int retval = -ENOMEM;	/* allocate memory for our device state and intialize it */	dev = kmalloc(sizeof(*dev), GFP_KERNEL);	if (dev == NULL) {		dev_err(&intf->dev, "Out of memory\n");		goto exit;	}	memset(dev, 0x00, sizeof(*dev));	init_MUTEX(&dev->sem);	dev->intf = intf;	init_waitqueue_head(&dev->read_wait);	init_waitqueue_head(&dev->write_wait);	/* workaround for early firmware versions on fast computers */	if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VENDOR_ID_LD) &&	    ((le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_CASSY) ||	     (le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_COM3LAB)) &&	    (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x103)) {		buffer = kmalloc(256, GFP_KERNEL);		if (buffer == NULL) {			dev_err(&intf->dev, "Couldn't allocate string buffer\n");			goto error;		}		/* usb_string makes SETUP+STALL to leave always ControlReadLoop */		usb_string(udev, 255, buffer, 256);		kfree(buffer);	}	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 (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {			dev->interrupt_in_endpoint = endpoint;		}		if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) &&		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {			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);	dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL);	if (!dev->ring_buffer) {		dev_err(&intf->dev, "Couldn't allocate ring_buffer\n");		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->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;	dev->interrupt_out_buffer = kmalloc(write_buffer_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->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);	retval = usb_register_dev(intf, &ld_usb_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, "LD USB Device #%d now attached to major %d minor %d\n",		(intf->minor - USB_LD_MINOR_BASE), USB_MAJOR, intf->minor);exit:	return retval;error:	ld_usb_delete(dev);	return retval;}/** *	ld_usb_disconnect * *	Called by the usb core when the device is removed from the system. */static void ld_usb_disconnect(struct usb_interface *intf){	struct ld_usb *dev;	int minor;	down(&disconnect_sem);	dev = usb_get_intfdata(intf);	usb_set_intfdata(intf, NULL);	down(&dev->sem);	minor = intf->minor;	/* give back our minor */	usb_deregister_dev(intf, &ld_usb_class);	/* if the device is not opened, then we clean up right now */	if (!dev->open_count) {		up(&dev->sem);		ld_usb_delete(dev);	} else {		dev->intf = NULL;		up(&dev->sem);	}	up(&disconnect_sem);	dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",		 (minor - USB_LD_MINOR_BASE));}/* usb specific object needed to register this driver with the usb subsystem */static struct usb_driver ld_usb_driver = {	.owner =	THIS_MODULE,	.name =		"ldusb",	.probe =	ld_usb_probe,	.disconnect =	ld_usb_disconnect,	.id_table =	ld_usb_table,};/** *	ld_usb_init */static int __init ld_usb_init(void){	int retval;	/* register this driver with the USB subsystem */	retval = usb_register(&ld_usb_driver);	if (retval)		err("usb_register failed for the "__FILE__" driver. Error number %d\n", retval);	return retval;}/** *	ld_usb_exit */static void __exit ld_usb_exit(void){	/* deregister this driver with the USB subsystem */	usb_deregister(&ld_usb_driver);}module_init(ld_usb_init);module_exit(ld_usb_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -