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

📄 legousbtower.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	return mask;}/** *	tower_llseek */static loff_t tower_llseek (struct file *file, loff_t off, int whence){	return -ESPIPE;		/* unseekable */}/** *	tower_read */static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, loff_t *ppos){	struct lego_usb_tower *dev;	size_t bytes_to_read;	int i;	int retval = 0;	unsigned long timeout = 0;	dbg(2, "%s: enter, count = %Zd", __FUNCTION__, count);	dev = (struct lego_usb_tower *)file->private_data;	/* lock this object */	if (down_interruptible (&dev->sem)) {		retval = -ERESTARTSYS;		goto exit;	}	/* verify that the device wasn't unplugged */	if (dev->udev == NULL) {		retval = -ENODEV;		err("No device or device unplugged %d", retval);		goto unlock_exit;	}	/* verify that we actually have some data to read */	if (count == 0) {		dbg(1, "%s: read request of 0 bytes", __FUNCTION__);		goto unlock_exit;	}	if (read_timeout) {		timeout = jiffies + read_timeout * HZ / 1000;	}	/* wait for data */	tower_check_for_read_packet (dev);	while (dev->read_packet_length == 0) {		if (file->f_flags & O_NONBLOCK) {			retval = -EAGAIN;			goto unlock_exit;		}		retval = wait_event_interruptible_timeout(dev->read_wait, dev->interrupt_in_done, dev->packet_timeout_jiffies);		if (retval < 0) {			goto unlock_exit;		}		/* reset read timeout during read or write activity */		if (read_timeout		    && (dev->read_buffer_length || dev->interrupt_out_busy)) {			timeout = jiffies + read_timeout * HZ / 1000;		}		/* check for read timeout */		if (read_timeout && time_after (jiffies, timeout)) {			retval = -ETIMEDOUT;			goto unlock_exit;		}		tower_check_for_read_packet (dev);	}	/* copy the data from read_buffer into userspace */	bytes_to_read = min(count, dev->read_packet_length);	if (copy_to_user (buffer, dev->read_buffer, bytes_to_read)) {		retval = -EFAULT;		goto unlock_exit;	}	spin_lock_irq (&dev->read_buffer_lock);	dev->read_buffer_length -= bytes_to_read;	dev->read_packet_length -= bytes_to_read;	for (i=0; i<dev->read_buffer_length; i++) {		dev->read_buffer[i] = dev->read_buffer[i+bytes_to_read];	}	spin_unlock_irq (&dev->read_buffer_lock);	retval = bytes_to_read;unlock_exit:	/* unlock the device */	up (&dev->sem);exit:	dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);	return retval;}/** *	tower_write */static ssize_t tower_write (struct file *file, const char __user *buffer, size_t count, loff_t *ppos){	struct lego_usb_tower *dev;	size_t bytes_to_write;	int retval = 0;	dbg(2, "%s: enter, count = %Zd", __FUNCTION__, count);	dev = (struct lego_usb_tower *)file->private_data;	/* lock this object */	if (down_interruptible (&dev->sem)) {		retval = -ERESTARTSYS;		goto exit;	}	/* verify that the device wasn't unplugged */	if (dev->udev == NULL) {		retval = -ENODEV;		err("No device or device unplugged %d", retval);		goto unlock_exit;	}	/* verify that we actually have some data to write */	if (count == 0) {		dbg(1, "%s: write request of 0 bytes", __FUNCTION__);		goto unlock_exit;	}	/* wait until previous transfer is finished */	while (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) {			goto unlock_exit;		}	}	/* write the data into interrupt_out_buffer from userspace */	bytes_to_write = min(count, write_buffer_size);	dbg(4, "%s: count = %Zd, bytes_to_write = %Zd", __FUNCTION__, count, bytes_to_write);	if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write)) {		retval = -EFAULT;		goto unlock_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,			 tower_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", retval);		goto unlock_exit;	}	retval = bytes_to_write;unlock_exit:	/* unlock the device */	up (&dev->sem);exit:	dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);	return retval;}/** *	tower_interrupt_in_callback */static void tower_interrupt_in_callback (struct urb *urb, struct pt_regs *regs){	struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;	int retval;	dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);	lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);	if (urb->status) {		if (urb->status == -ENOENT ||		    urb->status == -ECONNRESET ||		    urb->status == -ESHUTDOWN) {			goto exit;		} else {			dbg(1, "%s: nonzero status received: %d", __FUNCTION__, urb->status);			goto resubmit; /* maybe we can recover */		}	}	if (urb->actual_length > 0) {		spin_lock (&dev->read_buffer_lock);		if (dev->read_buffer_length + urb->actual_length < read_buffer_size) {			memcpy (dev->read_buffer + dev->read_buffer_length,				dev->interrupt_in_buffer,				urb->actual_length);			dev->read_buffer_length += urb->actual_length;			dev->read_last_arrival = jiffies;			dbg(3, "%s: received %d bytes", __FUNCTION__, urb->actual_length);		} else {			printk(KERN_WARNING "%s: read_buffer overflow, %d bytes dropped", __FUNCTION__, urb->actual_length);		}		spin_unlock (&dev->read_buffer_lock);	}resubmit:	/* resubmit if we're still running */	if (dev->interrupt_in_running && dev->udev) {		retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC);		if (retval) {			err("%s: usb_submit_urb failed (%d)", __FUNCTION__, retval);		}	}exit:	dev->interrupt_in_done = 1;	wake_up_interruptible (&dev->read_wait);	lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);	dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);}/** *	tower_interrupt_out_callback */static void tower_interrupt_out_callback (struct urb *urb, struct pt_regs *regs){	struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;	dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);	lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);	/* sync/async unlink faults aren't errors */	if (urb->status && !(urb->status == -ENOENT ||			     urb->status == -ECONNRESET ||			     urb->status == -ESHUTDOWN)) {		dbg(1, "%s - nonzero write bulk status received: %d",		    __FUNCTION__, urb->status);	}	dev->interrupt_out_busy = 0;	wake_up_interruptible(&dev->write_wait);	lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);	dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);}/** *	tower_probe * *	Called by the usb core when a new device is connected that it thinks *	this driver might be interested in. */static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id){	struct usb_device *udev = interface_to_usbdev(interface);	struct lego_usb_tower *dev = NULL;	struct usb_host_interface *iface_desc;	struct usb_endpoint_descriptor* endpoint;	struct tower_reset_reply reset_reply;	struct tower_get_version_reply get_version_reply;	int i;	int retval = -ENOMEM;	int result;	dbg(2, "%s: enter", __FUNCTION__);	if (udev == NULL) {		info ("udev is NULL.");	}	/* See if the device offered us matches what we can accept */	if ((udev->descriptor.idVendor != LEGO_USB_TOWER_VENDOR_ID) ||	    (udev->descriptor.idProduct != LEGO_USB_TOWER_PRODUCT_ID)) {		return -ENODEV;	}	/* allocate memory for our device state and intialize it */	dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL);	if (dev == NULL) {		err ("Out of memory");		goto exit;	}	init_MUTEX (&dev->sem);	dev->udev = udev;	dev->open_count = 0;	dev->read_buffer = NULL;	dev->read_buffer_length = 0;	dev->read_packet_length = 0;	spin_lock_init (&dev->read_buffer_lock);	dev->packet_timeout_jiffies = packet_timeout * HZ / 1000;	dev->read_last_arrival = jiffies;	init_waitqueue_head (&dev->read_wait);	init_waitqueue_head (&dev->write_wait);	dev->interrupt_in_buffer = NULL;	dev->interrupt_in_endpoint = NULL;	dev->interrupt_in_urb = NULL;	dev->interrupt_in_running = 0;	dev->interrupt_in_done = 0;	dev->interrupt_out_buffer = NULL;	dev->interrupt_out_endpoint = NULL;	dev->interrupt_out_urb = NULL;	dev->interrupt_out_busy = 0;	iface_desc = interface->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) {		err("interrupt in endpoint not found");		goto error;	}	if (dev->interrupt_out_endpoint == NULL) {		err("interrupt out endpoint not found");		goto error;	}	dev->read_buffer = kmalloc (read_buffer_size, GFP_KERNEL);	if (!dev->read_buffer) {		err("Couldn't allocate read_buffer");		goto error;	}	dev->interrupt_in_buffer = kmalloc (dev->interrupt_in_endpoint->wMaxPacketSize, GFP_KERNEL);	if (!dev->interrupt_in_buffer) {		err("Couldn't allocate interrupt_in_buffer");		goto error;	}	dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);	if (!dev->interrupt_in_urb) {		err("Couldn't allocate interrupt_in_urb");		goto error;	}	dev->interrupt_out_buffer = kmalloc (write_buffer_size, GFP_KERNEL);	if (!dev->interrupt_out_buffer) {		err("Couldn't allocate interrupt_out_buffer");		goto error;	}	dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);	if (!dev->interrupt_out_urb) {		err("Couldn't allocate interrupt_out_urb");		goto error;	}	dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval;	dev->interrupt_out_interval = interrupt_out_interval ? interrupt_out_interval : dev->interrupt_out_endpoint->bInterval;	/* we can register the device now, as it is ready */	usb_set_intfdata (interface, dev);	retval = usb_register_dev (interface, &tower_class);	if (retval) {		/* something prevented us from registering this driver */		err ("Not able to get a minor for this device.");		usb_set_intfdata (interface, NULL);		goto error;	}	dev->minor = interface->minor;	/* let the user know what node this device is now attached to */	info ("LEGO USB Tower #%d now attached to major %d minor %d", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), USB_MAJOR, dev->minor);	/* reset the tower */	result = usb_control_msg (udev,				  usb_rcvctrlpipe(udev, 0),				  LEGO_USB_TOWER_REQUEST_RESET,				  USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,				  0,				  0,				  &reset_reply,				  sizeof(reset_reply),				  HZ);	if (result < 0) {		err("LEGO USB Tower reset control request failed");		retval = result;		goto error;	}	/* get the firmware version and log it */	result = usb_control_msg (udev,				  usb_rcvctrlpipe(udev, 0),				  LEGO_USB_TOWER_REQUEST_GET_VERSION,				  USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,				  0,				  0,				  &get_version_reply,				  sizeof(get_version_reply),				  HZ);	if (result < 0) {		err("LEGO USB Tower get version control request failed");		retval = result;		goto error;	}	info("LEGO USB Tower firmware version is %d.%d build %d",	     get_version_reply.major,	     get_version_reply.minor,	     le16_to_cpu(get_version_reply.build_no));exit:	dbg(2, "%s: leave, return value 0x%.8lx (dev)", __FUNCTION__, (long) dev);	return retval;error:	tower_delete(dev);	return retval;}/** *	tower_disconnect * *	Called by the usb core when the device is removed from the system. */static void tower_disconnect (struct usb_interface *interface){	struct lego_usb_tower *dev;	int minor;	dbg(2, "%s: enter", __FUNCTION__);	down (&disconnect_sem);	dev = usb_get_intfdata (interface);	usb_set_intfdata (interface, NULL);	down (&dev->sem);	minor = dev->minor;	/* give back our minor */	usb_deregister_dev (interface, &tower_class);	/* if the device is not opened, then we clean up right now */	if (!dev->open_count) {		up (&dev->sem);		tower_delete (dev);	} else {		dev->udev = NULL;		up (&dev->sem);	}	up (&disconnect_sem);	info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));	dbg(2, "%s: leave", __FUNCTION__);}/** *	lego_usb_tower_init */static int __init lego_usb_tower_init(void){	int result;	int retval = 0;	dbg(2, "%s: enter", __FUNCTION__);	/* register this driver with the USB subsystem */	result = usb_register(&tower_driver);	if (result < 0) {		err("usb_register failed for the "__FILE__" driver. Error number %d", result);		retval = -1;		goto exit;	}	info(DRIVER_DESC " " DRIVER_VERSION);exit:	dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);	return retval;}/** *	lego_usb_tower_exit */static void __exit lego_usb_tower_exit(void){	dbg(2, "%s: enter", __FUNCTION__);	/* deregister this driver with the USB subsystem */	usb_deregister (&tower_driver);	dbg(2, "%s: leave", __FUNCTION__);}module_init (lego_usb_tower_init);module_exit (lego_usb_tower_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endif

⌨️ 快捷键说明

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