📄 t500usb.c
字号:
/* * ------------------------------------------------------ * Epson BA-T500 USB driver - 0.1 * * Author: Cedar Peng (cedar.peng@gmail.com) * * History: * * 2007_04_16 - 0.1 - Modified the Linux USB Skeleton drirver to * satisfied BA-T500USB requirement. * * ------------------------------------------------------ * USB Skeleton driver - 0.7 * * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * * This driver is to be used as a skeleton driver to be able to create a * USB driver quickly. The design of it is based on the usb-serial and * dc2xx drivers. * * Thanks to Oliver Neukum and David Brownell for their help in debugging * this driver. * * TODO: * - fix urb->status race condition in write sequence * - move minor_table to a dynamic list. * * History: * * 2002_02_12 - 0.7 - zero out dev in probe function for devices that do * not have both a bulk in and bulk out endpoint. * Thanks to Holger Waechtler for the fix. * 2001_11_05 - 0.6 - fix minor locking problem in t500u_disconnect. * Thanks to Pete Zaitcev for the fix. * 2001_09_04 - 0.5 - fix devfs bug in t500u_disconnect. Thanks to wim delvaux * 2001_08_21 - 0.4 - more small bug fixes. * 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel * 2001_05_24 - 0.2 - bug fixes based on review from linux-usb-devel people * 2001_05_01 - 0.1 - first version * */#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/fcntl.h>#include <linux/module.h>#include <linux/spinlock.h>#include <linux/list.h>#include <linux/smp_lock.h>#include <linux/devfs_fs_kernel.h>#include <linux/usb.h>#ifdef CONFIG_USB_DEBUG static int debug = 1;#else static int debug;#endif/* Version Information */#define DRIVER_VERSION "v0.1"#define DRIVER_AUTHOR "Cedar Peng, cedar.peng@gmail.com"#define DRIVER_DESC "Epson BA-T500USB driver"/* Module paramaters */MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Debug enabled or not");/* Define these values to match your device */#define USB_T500U_VENDOR_ID 0x04b8#define USB_T500U_PRODUCT_ID 0x0202/* table of devices that work with this driver */// If you have many devices, you could expand this table.static struct usb_device_id t500u_table [] = { { USB_DEVICE(USB_T500U_VENDOR_ID, USB_T500U_PRODUCT_ID) }, { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, t500u_table);/* Get a minor range for your devices from the usb maintainer */#define USB_T500U_MINOR_BASE 200 /* we can have up to this number of device plugged in at once */#define MAX_DEVICES 8/* Structure to hold all of our device specific stuff */struct usb_t500u { struct usb_device * udev; /* save off the usb device pointer */ struct usb_interface * interface; /* the interface for this device */ devfs_handle_t devfs; /* devfs device node */ unsigned char minor; /* the starting minor number for this device */ unsigned char num_ports; /* the number of ports this device has */ char num_interrupt_in; /* number of interrupt in endpoints we have */ char num_bulk_in; /* number of bulk in endpoints we have */ char num_bulk_out; /* number of bulk out endpoints we have */ unsigned char * bulk_in_buffer; /* the buffer to receive data */ int bulk_in_size; /* the size of the receive buffer */ __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ unsigned char * bulk_out_buffer; /* the buffer to send data */ int bulk_out_size; /* the size of the send buffer */ struct urb * write_urb; /* the urb used to send data */ __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ struct tq_struct tqueue; /* task queue for line discipline waking up */ int open_count; /* number of times this port has been opened */ struct semaphore sem; /* locks this structure */};/* the global usb devfs handle */extern devfs_handle_t usb_devfs_handle;/* local function prototypes */static ssize_t t500u_read (struct file *file, char *buffer, size_t count, loff_t *ppos);static ssize_t t500u_write (struct file *file, const char *buffer, size_t count, loff_t *ppos);static int t500u_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int t500u_open (struct inode *inode, struct file *file);static int t500u_release (struct inode *inode, struct file *file); static void * t500u_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);static void t500u_disconnect (struct usb_device *dev, void *ptr);static void t500u_write_bulk_callback (struct urb *urb);/* array of pointers to our devices that are currently connected */static struct usb_t500u *minor_table[MAX_DEVICES];/* lock to protect the minor_table structure */static DECLARE_MUTEX (minor_table_mutex);/* * File operations needed when we register this driver. * This assumes that this driver NEEDS file operations, * of course, which means that the driver is expected * to have a node in the /dev directory. If the USB * device were for a network interface then the driver * would use "struct net_driver" instead, and a serial * device would use "struct tty_driver". */static struct file_operations t500u_fops = { /* * The owner field is part of the module-locking * mechanism. The idea is that the kernel knows * which module to increment the use-counter of * BEFORE it calls the device's open() function. * This also means that the kernel can decrement * the use-counter again before calling release() * or should the open() function fail. * * Not all device structures have an "owner" field * yet. "struct file_operations" and "struct net_device" * do, while "struct tty_driver" does not. If the struct * has an "owner" field, then initialize it to the value * THIS_MODULE and the kernel will handle all module * locking for you automatically. Otherwise, you must * increment the use-counter in the open() function * and decrement it again in the release() function * yourself. */ owner: THIS_MODULE, read: t500u_read, write: t500u_write, ioctl: t500u_ioctl, open: t500u_open, release: t500u_release,}; /* usb specific object needed to register this driver with the usb subsystem */static struct usb_driver t500u_driver = { name: "t500usb", probe: t500u_probe, disconnect: t500u_disconnect, fops: &t500u_fops, minor: USB_T500U_MINOR_BASE, id_table: t500u_table,};/** * usb_t500u_debug_data */static inline void usb_t500u_debug_data (const char *function, int size, const unsigned char *data){ int i; if (!debug) return; printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", function, size); for (i = 0; i < size; ++i) { printk ("%.2x ", data[i]); } printk ("\n");}/** * t500u_delete */static inline void t500u_delete (struct usb_t500u *dev){ minor_table[dev->minor] = NULL; if (dev->bulk_in_buffer != NULL) kfree (dev->bulk_in_buffer); if (dev->bulk_out_buffer != NULL) kfree (dev->bulk_out_buffer); if (dev->write_urb != NULL) usb_free_urb (dev->write_urb); kfree (dev);}/** * t500u_open */static int t500u_open (struct inode *inode, struct file *file){ struct usb_t500u *dev = NULL; int subminor; int retval = 0; subminor = MINOR (inode->i_rdev) - USB_T500U_MINOR_BASE; if ((subminor < 0) || (subminor >= MAX_DEVICES)) { return -ENODEV; } /* Increment our usage count for the module. * This is redundant here, because "struct file_operations" * has an "owner" field. This line is included here soley as * a reference for drivers using lesser structures... ;-) */ MOD_INC_USE_COUNT; /* lock our minor table and get our local data for this minor */ down (&minor_table_mutex); dev = minor_table[subminor]; if (dev == NULL) { up (&minor_table_mutex); MOD_DEC_USE_COUNT; return -ENODEV; } /* lock this device */ down (&dev->sem); /* unlock the minor table */ up (&minor_table_mutex); /* increment our usage count for the driver */ ++dev->open_count; /* save our object in the file's private structure */ file->private_data = dev; /* unlock this device */ up (&dev->sem); return retval;}/** * t500u_release */static int t500u_release (struct inode *inode, struct file *file){ struct usb_t500u *dev; int retval = 0; dev = (struct usb_t500u *)file->private_data; if (dev == NULL) { return -ENODEV; } /* lock our minor table */ down (&minor_table_mutex); /* lock our device */ down (&dev->sem); if (dev->open_count <= 0) { retval = -ENODEV; goto exit_not_opened; } if (dev->udev == NULL) { /* the device was unplugged before the file was released */ up (&dev->sem); t500u_delete (dev); up (&minor_table_mutex); MOD_DEC_USE_COUNT; return 0; } /* decrement our usage count for the device */ --dev->open_count; if (dev->open_count <= 0) { /* shutdown any bulk writes that might be going on */ usb_unlink_urb (dev->write_urb); dev->open_count = 0; } /* decrement our usage count for the module */ MOD_DEC_USE_COUNT;exit_not_opened: up (&dev->sem); up (&minor_table_mutex); return retval;}/** * t500u_read */static ssize_t t500u_read (struct file *file, char *buffer, size_t count, loff_t *ppos){ struct usb_t500u *dev; int retval = 0; dev = (struct usb_t500u *)file->private_data; /* lock this object */ down (&dev->sem);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -