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

📄 adutux.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
				dev->read_buffer_primary = tmp;				dev->secondary_head = 0;				dev->secondary_tail = dev->read_buffer_length;				dev->read_buffer_length = 0;				spin_unlock_irqrestore(&dev->buflock, flags);				/* we have a free buffer so use it */				should_submit = 1;			} else {				/* even the primary was empty - we may need to do IO */				if (!dev->read_urb_finished) {					/* somebody is doing IO */					spin_unlock_irqrestore(&dev->buflock, flags);					dbg(2," %s : submitted already", __FUNCTION__);				} else {					/* we must initiate input */					dbg(2," %s : initiate input", __FUNCTION__);					dev->read_urb_finished = 0;					spin_unlock_irqrestore(&dev->buflock, flags);					usb_fill_int_urb(dev->interrupt_in_urb,dev->udev,							 usb_rcvintpipe(dev->udev,							 		dev->interrupt_in_endpoint->bEndpointAddress),							 dev->interrupt_in_buffer,							 le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),							 adu_interrupt_in_callback,							 dev,							 dev->interrupt_in_endpoint->bInterval);					retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);					if (retval) {						dev->read_urb_finished = 1;						if (retval == -ENOMEM) {							retval = bytes_read ? bytes_read : -ENOMEM;						}						dbg(2," %s : submit failed", __FUNCTION__);						goto exit;					}				}				/* we wait for I/O to complete */				set_current_state(TASK_INTERRUPTIBLE);				add_wait_queue(&dev->read_wait, &wait);				spin_lock_irqsave(&dev->buflock, flags);				if (!dev->read_urb_finished) {					spin_unlock_irqrestore(&dev->buflock, flags);					timeout = schedule_timeout(COMMAND_TIMEOUT);				} else {					spin_unlock_irqrestore(&dev->buflock, flags);					set_current_state(TASK_RUNNING);				}				remove_wait_queue(&dev->read_wait, &wait);				if (timeout <= 0) {					dbg(2," %s : timeout", __FUNCTION__);					retval = bytes_read ? bytes_read : -ETIMEDOUT;					goto exit;				}				if (signal_pending(current)) {					dbg(2," %s : signal pending", __FUNCTION__);					retval = bytes_read ? bytes_read : -EINTR;					goto exit;				}			}		}	}	retval = bytes_read;	/* if the primary buffer is empty then use it */	spin_lock_irqsave(&dev->buflock, flags);	if (should_submit && dev->read_urb_finished) {		dev->read_urb_finished = 0;		spin_unlock_irqrestore(&dev->buflock, flags);		usb_fill_int_urb(dev->interrupt_in_urb,dev->udev,				 usb_rcvintpipe(dev->udev,				 		dev->interrupt_in_endpoint->bEndpointAddress),				dev->interrupt_in_buffer,				le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),				adu_interrupt_in_callback,				dev,				dev->interrupt_in_endpoint->bInterval);		if (usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL) != 0)			dev->read_urb_finished = 1;		/* we ignore failure */	} else {		spin_unlock_irqrestore(&dev->buflock, flags);	}exit:	/* unlock the device */	mutex_unlock(&dev->mtx);	dbg(2," %s : leave, return value %d", __FUNCTION__, retval);	return retval;}static ssize_t adu_write(struct file *file, const __user char *buffer,			 size_t count, loff_t *ppos){	DECLARE_WAITQUEUE(waita, current);	struct adu_device *dev;	size_t bytes_written = 0;	size_t bytes_to_write;	size_t buffer_size;	unsigned long flags;	int retval;	dbg(2," %s : enter, count = %Zd", __FUNCTION__, count);	dev = file->private_data;	retval = mutex_lock_interruptible(&dev->mtx);	if (retval)		goto exit_nolock;	/* verify that the device wasn't unplugged */	if (dev->udev == NULL) {		retval = -ENODEV;		err("No device or device unplugged %d", retval);		goto exit;	}	/* verify that we actually have some data to write */	if (count == 0) {		dbg(1," %s : write request of 0 bytes", __FUNCTION__);		goto exit;	}	while (count > 0) {		add_wait_queue(&dev->write_wait, &waita);		set_current_state(TASK_INTERRUPTIBLE);		spin_lock_irqsave(&dev->buflock, flags);		if (!dev->out_urb_finished) {			spin_unlock_irqrestore(&dev->buflock, flags);			mutex_unlock(&dev->mtx);			if (signal_pending(current)) {				dbg(1," %s : interrupted", __FUNCTION__);				set_current_state(TASK_RUNNING);				retval = -EINTR;				goto exit_onqueue;			}			if (schedule_timeout(COMMAND_TIMEOUT) == 0) {				dbg(1, "%s - command timed out.", __FUNCTION__);				retval = -ETIMEDOUT;				goto exit_onqueue;			}			remove_wait_queue(&dev->write_wait, &waita);			retval = mutex_lock_interruptible(&dev->mtx);			if (retval) {				retval = bytes_written ? bytes_written : retval;				goto exit_nolock;			}			dbg(4," %s : in progress, count = %Zd", __FUNCTION__, count);		} else {			spin_unlock_irqrestore(&dev->buflock, flags);			set_current_state(TASK_RUNNING);			remove_wait_queue(&dev->write_wait, &waita);			dbg(4," %s : sending, count = %Zd", __FUNCTION__, count);			/* write the data into interrupt_out_buffer from userspace */			buffer_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);			bytes_to_write = count > buffer_size ? buffer_size : count;			dbg(4," %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd",			    __FUNCTION__, buffer_size, count, bytes_to_write);			if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write) != 0) {				retval = -EFAULT;				goto exit;			}			/* send off the urb */			usb_fill_int_urb(				dev->interrupt_out_urb,				dev->udev,				usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAddress),				dev->interrupt_out_buffer,				bytes_to_write,				adu_interrupt_out_callback,				dev,				dev->interrupt_out_endpoint->bInterval);			dev->interrupt_out_urb->actual_length = bytes_to_write;			dev->out_urb_finished = 0;			retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);			if (retval < 0) {				dev->out_urb_finished = 1;				err("Couldn't submit interrupt_out_urb %d", retval);				goto exit;			}			buffer += bytes_to_write;			count -= bytes_to_write;			bytes_written += bytes_to_write;		}	}	mutex_unlock(&dev->mtx);	return bytes_written;exit:	mutex_unlock(&dev->mtx);exit_nolock:	dbg(2," %s : leave, return value %d", __FUNCTION__, retval);	return retval;exit_onqueue:	remove_wait_queue(&dev->write_wait, &waita);	return retval;}/* file operations needed when we register this driver */static const struct file_operations adu_fops = {	.owner = THIS_MODULE,	.read  = adu_read,	.write = adu_write,	.open = adu_open,	.release = adu_release,};/* * 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 adu_class = {	.name = "usb/adutux%d",	.fops = &adu_fops,	.minor_base = ADU_MINOR_BASE,};/** * adu_probe * * Called by the usb core when a new device is connected that it thinks * this driver might be interested in. */static int adu_probe(struct usb_interface *interface,		     const struct usb_device_id *id){	struct usb_device *udev = interface_to_usbdev(interface);	struct adu_device *dev = NULL;	struct usb_host_interface *iface_desc;	struct usb_endpoint_descriptor *endpoint;	int retval = -ENODEV;	int in_end_size;	int out_end_size;	int i;	dbg(2," %s : enter", __FUNCTION__);	if (udev == NULL) {		dev_err(&interface->dev, "udev is NULL.\n");		goto exit;	}	/* allocate memory for our device state and intialize it */	dev = kzalloc(sizeof(struct adu_device), GFP_KERNEL);	if (dev == NULL) {		dev_err(&interface->dev, "Out of memory\n");		retval = -ENOMEM;		goto exit;	}	mutex_init(&dev->mtx);	spin_lock_init(&dev->buflock);	dev->udev = udev;	init_waitqueue_head(&dev->read_wait);	init_waitqueue_head(&dev->write_wait);	iface_desc = &interface->altsetting[0];	/* 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(&interface->dev, "interrupt in endpoint not found\n");		goto error;	}	if (dev->interrupt_out_endpoint == NULL) {		dev_err(&interface->dev, "interrupt out endpoint not found\n");		goto error;	}	in_end_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);	out_end_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);	dev->read_buffer_primary = kmalloc((4 * in_end_size), GFP_KERNEL);	if (!dev->read_buffer_primary) {		dev_err(&interface->dev, "Couldn't allocate read_buffer_primary\n");		retval = -ENOMEM;		goto error;	}	/* debug code prime the buffer */	memset(dev->read_buffer_primary, 'a', in_end_size);	memset(dev->read_buffer_primary + in_end_size, 'b', in_end_size);	memset(dev->read_buffer_primary + (2 * in_end_size), 'c', in_end_size);	memset(dev->read_buffer_primary + (3 * in_end_size), 'd', in_end_size);	dev->read_buffer_secondary = kmalloc((4 * in_end_size), GFP_KERNEL);	if (!dev->read_buffer_secondary) {		dev_err(&interface->dev, "Couldn't allocate read_buffer_secondary\n");		retval = -ENOMEM;		goto error;	}	/* debug code prime the buffer */	memset(dev->read_buffer_secondary, 'e', in_end_size);	memset(dev->read_buffer_secondary + in_end_size, 'f', in_end_size);	memset(dev->read_buffer_secondary + (2 * in_end_size), 'g', in_end_size);	memset(dev->read_buffer_secondary + (3 * in_end_size), 'h', in_end_size);	dev->interrupt_in_buffer = kmalloc(in_end_size, GFP_KERNEL);	if (!dev->interrupt_in_buffer) {		dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n");		goto error;	}	/* debug code prime the buffer */	memset(dev->interrupt_in_buffer, 'i', in_end_size);	dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);	if (!dev->interrupt_in_urb) {		dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n");		goto error;	}	dev->interrupt_out_buffer = kmalloc(out_end_size, GFP_KERNEL);	if (!dev->interrupt_out_buffer) {		dev_err(&interface->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(&interface->dev, "Couldn't allocate interrupt_out_urb\n");		goto error;	}	if (!usb_string(udev, udev->descriptor.iSerialNumber, dev->serial_number,			sizeof(dev->serial_number))) {		dev_err(&interface->dev, "Could not retrieve serial number\n");		goto error;	}	dbg(2," %s : serial_number=%s", __FUNCTION__, dev->serial_number);	/* we can register the device now, as it is ready */	usb_set_intfdata(interface, dev);	retval = usb_register_dev(interface, &adu_class);	if (retval) {		/* something prevented us from registering this driver */		dev_err(&interface->dev, "Not able to get a minor for this device.\n");		usb_set_intfdata(interface, NULL);		goto error;	}	dev->minor = interface->minor;	/* let the user know what node this device is now attached to */	dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d\n",		 udev->descriptor.idProduct, dev->serial_number,		 (dev->minor - ADU_MINOR_BASE));exit:	dbg(2," %s : leave, return value %p (dev)", __FUNCTION__, dev);	return retval;error:	adu_delete(dev);	return retval;}/** * adu_disconnect * * Called by the usb core when the device is removed from the system. */static void adu_disconnect(struct usb_interface *interface){	struct adu_device *dev;	int minor;	dbg(2," %s : enter", __FUNCTION__);	dev = usb_get_intfdata(interface);	mutex_lock(&dev->mtx);	/* not interruptible */	dev->udev = NULL;	/* poison */	minor = dev->minor;	usb_deregister_dev(interface, &adu_class);	mutex_unlock(&dev->mtx);	mutex_lock(&adutux_mutex);	usb_set_intfdata(interface, NULL);	/* if the device is not opened, then we clean up right now */	dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);	if (!dev->open_count)		adu_delete(dev);	mutex_unlock(&adutux_mutex);	dev_info(&interface->dev, "ADU device adutux%d now disconnected\n",		 (minor - ADU_MINOR_BASE));	dbg(2," %s : leave", __FUNCTION__);}/* usb specific object needed to register this driver with the usb subsystem */static struct usb_driver adu_driver = {	.name = "adutux",	.probe = adu_probe,	.disconnect = adu_disconnect,	.id_table = device_table,};static int __init adu_init(void){	int result;	dbg(2," %s : enter", __FUNCTION__);	/* register this driver with the USB subsystem */	result = usb_register(&adu_driver);	if (result < 0) {		err("usb_register failed for the "__FILE__" driver. "		    "Error number %d", result);		goto exit;	}	info("adutux " DRIVER_DESC " " DRIVER_VERSION);	info("adutux is an experimental driver. Use at your own risk");exit:	dbg(2," %s : leave, return value %d", __FUNCTION__, result);	return result;}static void __exit adu_exit(void){	dbg(2," %s : enter", __FUNCTION__);	/* deregister this driver with the USB subsystem */	usb_deregister(&adu_driver);	dbg(2," %s : leave", __FUNCTION__);}module_init(adu_init);module_exit(adu_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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