?? usb-skeleton.c
字號:
/* * USB Skeleton driver - 0.6 * * 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: * * 2001_11_05 - 0.6 - fix minor locking problem in skel_disconnect. * Thanks to Pete Zaitcev for the fix. * 2001_09_04 - 0.5 - fix devfs bug in skel_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/* Use our own dbg macro */#undef dbg#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0)/* Version Information */#define DRIVER_VERSION "v0.4"#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com"#define DRIVER_DESC "USB Skeleton Driver"/* Module paramaters */MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Debug enabled or not");/* Define these values to match your device */#define USB_SKEL_VENDOR_ID 0xfff0#define USB_SKEL_PRODUCT_ID 0xfff0/* table of devices that work with this driver */static struct usb_device_id skel_table [] = { { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, skel_table);/* Get a minor range for your devices from the usb maintainer */#define USB_SKEL_MINOR_BASE 200 /* we can have up to this number of device plugged in at once */#define MAX_DEVICES 16/* Structure to hold all of our device specific stuff */struct usb_skel { 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 skel_read (struct file *file, char *buffer, size_t count, loff_t *ppos);static ssize_t skel_write (struct file *file, const char *buffer, size_t count, loff_t *ppos);static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int skel_open (struct inode *inode, struct file *file);static int skel_release (struct inode *inode, struct file *file); static void * skel_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);static void skel_disconnect (struct usb_device *dev, void *ptr);static void skel_write_bulk_callback (struct urb *urb);/* array of pointers to our devices that are currently connected */static struct usb_skel *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 skel_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: skel_read, write: skel_write, ioctl: skel_ioctl, open: skel_open, release: skel_release,}; /* usb specific object needed to register this driver with the usb subsystem */static struct usb_driver skel_driver = { name: "skeleton", probe: skel_probe, disconnect: skel_disconnect, fops: &skel_fops, minor: USB_SKEL_MINOR_BASE, id_table: skel_table,};/** * usb_skel_debug_data */static inline void usb_skel_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");}/** * skel_delete */static inline void skel_delete (struct usb_skel *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);}/** * skel_open */static int skel_open (struct inode *inode, struct file *file){ struct usb_skel *dev = NULL; int subminor; int retval = 0; dbg(__FUNCTION__); subminor = MINOR (inode->i_rdev) - USB_SKEL_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;}/** * skel_release */static int skel_release (struct inode *inode, struct file *file){ struct usb_skel *dev; int retval = 0; dev = (struct usb_skel *)file->private_data; if (dev == NULL) { dbg (__FUNCTION__ " - object is NULL"); return -ENODEV; } dbg(__FUNCTION__ " - minor %d", dev->minor); /* lock our minor table */ down (&minor_table_mutex); /* lock our device */ down (&dev->sem); if (dev->open_count <= 0) { dbg (__FUNCTION__ " - device not opened"); retval = -ENODEV; goto exit_not_opened; } if (dev->udev == NULL) { /* the device was unplugged before the file was released */ up (&dev->sem); skel_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;}/** * skel_read */static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t *ppos){ struct usb_skel *dev; int retval = 0; dev = (struct usb_skel *)file->private_data;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -