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

📄 myudisk.c

📁 linux下的U盘驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * My UDisk driver - 0.1 * * TODO: *	- fix urb->status race condition in write sequence *	- move minor_table to a dynamic list. * * History: * * 2008_01_9 - 0.1 - zero out dev in probe function for devices that do *  */#define __KERNEL__#define MODULE#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>#define MAJOR_NR		42		// 定义主设备号#define DEVICE_NAME		"myudisk"		// 定义设备名#define DEVICE_NR(device)	(MINOR(device))		#define DEVICE_ON(device)#define DEVICE_OFF(device)#define DEVICE_NO_RANDOM#include <linux/blk.h>#define MYUDISK_SECTOR_BITS	9	/* 2**9 byte hardware sector */#define MYUDISK_BLOCK_SIZE	1024	/* block size */	//定义了一个块的大小,以字节为单位#define MYUDISK_TOTAL_SIZE	2048	/* size in blocks */	//定义了这个虚拟盘的容量,以块为单位/* the storage pool *///static char *myudisk_storage;		//这个指针是全局变量,指向用于虚拟盘的内存//static int myudisk_sectorsize = 1 << MYUDISK_SECTOR_BITS;//static int myudisk_blocksize = MYUDISK_BLOCK_SIZE;static int myudisk_size ;static int myudisk_readahead = 4;#define CONFIG_USB_DEBUG#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__ "(%s): " format "\n" , __FUNCTION__, ## arg); } while (0)/* Version Information */#define DRIVER_VERSION "v0.1"#define DRIVER_AUTHOR "Wen Yan Jun, yjwen@nudt.edu.cn"#define DRIVER_DESC "My UDisk Driver"/* Module paramaters */MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Debug enabled or not");/* Define these values to match your device */#define MY_UDISK_VENDOR_ID	0x58f#define MY_UDISK_PRODUCT_ID	0x9380/* table of devices that work with this driver */static struct usb_device_id myudisk_table [] = {	{ USB_DEVICE(MY_UDISK_VENDOR_ID, MY_UDISK_PRODUCT_ID) },	{ }					/* Terminating entry */};MODULE_DEVICE_TABLE (usb, myudisk_table);/* Get a minor range for your devices from the usb maintainer */#define MY_UDISK_MINOR_BASE	192	/* 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 my_udisk {	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;//////////////////////////////////////////////////////////////////////////////////////////////////////#define MAX_COMMAND_SIZE    16#define MU_BULK_BUFFER_LEN	4096	/* if the blocksize is larger than the buffer len, data transform will fail. *//* transport return codes */ #define MYUDISK_TRANSPORT_GOOD	  0   /* Transport good, command good	  */#define MYUDISK_TRANSPORT_FAILED  1   /* Transport good, command failed   */#define MYUDISK_TRANSPORT_ERROR   2   /* Transport bad (i.e. device dead) */#define MYUDISK_TRANSPORT_ABORTED 3   /* Transport aborted                */#define SCSI_DATA_UNKNOWN       0#define SCSI_DATA_WRITE         1#define SCSI_DATA_READ          2#define SCSI_DATA_NONE          3static inline void myudisk_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");}struct cmnd_struct {		unsigned char 		cmnd[MAX_COMMAND_SIZE]; 	unsigned char 		cmd_len;			unsigned char 		sc_data_direction;	/* direction of data transfer */	unsigned  		data_payload_size;	/* data payload size */	unsigned  		data_payload_actualSize;/* data payload size actually xfered */	__u32			tag;			/* used for cbw */};#define MYUDISK_TIMEOUT 	HZ*10#define MYUDISK_STRING_LEN 	32#define SUCCESS         	0x2002#define FAILED          	0x2003/* command block wrapper */struct bulk_cb_wrap {	__u32	Signature;		/* contains 'USBC' */	__u32	Tag;			/* unique per command id */	__u32	DataTransferLength;	/* size of data */	__u8	Flags;			/* direction in bit 0 */	__u8	Lun;			/* LUN normally 0 */	__u8	Length;			/* of of the CDB */	__u8	CDB[16];		/* max command */};#define MU_BULK_CB_WRAP_LEN	31#define MU_BULK_CB_SIGN		0x43425355	/*spells out USBC */#define MU_BULK_FLAG_IN		1#define MU_BULK_FLAG_OUT	0/* bulk-only class specific requests */#define MU_BULK_RESET_REQUEST	0xff#define MU_BULK_GET_MAX_LUN	0xfe/* command status wrapper */struct bulk_cs_wrap {	__u32	Signature;		/* should = 'USBS' */	__u32	Tag;			/* same as original command */	__u32	Residue;		/* amount not transferred */	__u8	Status;			/* see below */	__u8	Filler[18];};#define MU_BULK_CS_WRAP_LEN	13#define MU_BULK_CS_SIGN		0x53425355	/* spells out 'USBS' *//* This is for Olympus Camedia digital cameras */#define MU_BULK_CS_OLYMPUS_SIGN	0x55425355	/* spells out 'USBU' */#define MU_BULK_STAT_OK		0#define MU_BULK_STAT_FAIL	1#define MU_BULK_STAT_PHASE	2/* bulk-only class specific requests */#define MU_BULK_RESET_REQUEST	0xff#define MU_BULK_GET_MAX_LUN	0xfe__u32 myudisk_soft ,SECTOR_num,BLOCK_num;unsigned long PARTION_offset;static int myudisk_hard = 1 << MYUDISK_SECTOR_BITS;/*********************************************************************** * USB mass storage device related functions ***********************************************************************///////////////////////////////////////////////////////////////////////////////////////////////////////* local function prototypes */static int myudisk_ioctl		(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int myudisk_open		(struct inode *inode, struct file *file);static int myudisk_release		(struct inode *inode, struct file *file);	static void * myudisk_probe	(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);static void myudisk_disconnect	(struct usb_device *dev, void *ptr);static void myudisk_write_bulk_callback	(struct urb *urb);extern int myudisk_Bulk_transport(struct usb_device *udev, struct usb_interface *interface,                                  struct cmnd_struct *cs,                                   unsigned char *bulk_buffer, int bulk_size,                                  __u8 bulk_in_endpointAddr, __u8 bulk_out_endpointAddr);unsigned int myudisk_transfer_length(struct cmnd_struct *ud);int myudisk_Bulk_reset(struct usb_device *udev, struct usb_interface *interface,                        __u8 bulk_in_endpointAddr, __u8 bulk_out_endpointAddr);/* array of pointers to our devices that are currently connected */static struct my_udisk		*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 block_device_operations myudisk_fops = {	ioctl:		myudisk_ioctl,	open:		myudisk_open,	release:	myudisk_release,};      /* usb specific object needed to register this driver with the usb subsystem */static struct usb_driver myudisk_driver = {	name:		"myudisk",	probe:		myudisk_probe,	disconnect:	myudisk_disconnect,	fops:		NULL,	minor:		MY_UDISK_MINOR_BASE,	id_table:	myudisk_table,};/** *	my_udisk_debug_data */static inline void my_udisk_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");}/** *	myudisk_delete */static inline void myudisk_delete (struct my_udisk *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);}/** *	myudisk_open */static int myudisk_open (struct inode *inode, struct file *file){	struct my_udisk *dev = NULL;	int subminor;	int retval = 0;		dbg("myudisk_open()");	subminor = MINOR (inode->i_rdev); 		//- MY_UDISK_MINOR_BASE;	if ((subminor < 0) ||	    (subminor >= MAX_DEVICES)) {		return -ENODEV;	}	//MOD_INC_USE_COUNT;	/* lock our minor table and get our local data for this minor */	down (&minor_table_mutex);	dev = minor_table[subminor];	dbg("minor: %d, dev:%p", subminor, dev);	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;	dbg("file: %p, dev:%p", file, dev);	/* unlock this device */	up (&dev->sem);	dbg("The dev is not NULL\n");	return retval;}/** *	myudisk_release */static int myudisk_release (struct inode *inode, struct file *file){	struct my_udisk *dev;	int subminor;	int retval = 0;	dbg("inode: %p, file: %p", inode, file);		subminor = MINOR (inode->i_rdev); 		//- MY_UDISK_MINOR_BASE;	if ((subminor < 0) ||	    (subminor >= MAX_DEVICES)) {		return -ENODEV;	}	/* lock our minor table */	down (&minor_table_mutex);	dev = minor_table[subminor];	if (dev == NULL) {		up (&minor_table_mutex);		dbg("object is NULL");		return -ENODEV;	}	dbg("subminor= %d, dev=%p, dev->minor= %d", subminor, dev, dev->minor);	/* lock our device */	down (&dev->sem);	if (0) { //dev->open_count <= 0) {		dbg("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);		myudisk_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;}/** *	myudisk_ioctl */static int myudisk_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	unsigned int minor;		dbg("enter myudisk_ioctl()");	if (!inode || !inode->i_rdev) 			return -EINVAL;	minor = MINOR(inode->i_rdev);	switch (cmd) {		case BLKFLSBUF: {	//将缓冲写回存储区的操作			/* flush buffers */			dbg("ioctl: BLKFLSBUF\n");			/* deny all but root */			if (!capable(CAP_SYS_ADMIN))				return -EACCES;			fsync_dev(inode->i_rdev);			invalidate_buffers(inode->i_rdev);			break;		}    case BLKGETSIZE: {	//得到设备容量的操作			/* return device size */			dbg("ioctl: BLKGETSIZE\n");			dbg("ioctl: BLKGETSIZE = %u\n",myudisk_size);			if (!arg)				return -EINVAL;			return put_user(SECTOR_num, (long *) arg);		}				case BLKRASET: {	//设置设备预读值的操作			/* set read ahead value */			int tmp;			dbg("ioctl: BLKRASET\n");			if (get_user(tmp, (long *)arg))				return -EINVAL;			if (tmp > 0xff)				return -EINVAL;			read_ahead[MAJOR_NR] = tmp;			return 0;		}		case BLKRAGET: {	//得到设备预读值的操作			/* return read ahead value */			dbg("ioctl: BLKRAGET\n");			if (!arg)				return -EINVAL;			return put_user(read_ahead[MAJOR_NR], (long *)arg);		}		case BLKSSZGET: {	//得到设备块大小的操作			/* return block size */			dbg("ioctl: BLKSSZGET\n");			if (!arg)				return -EINVAL;			return put_user(myudisk_hard, (long *)arg);		}		default: {		//其他操作			dbg("ioctl wanted %u\n", cmd);			return -ENOTTY;		}	}	dbg(" exit myudisk_ioctl()");	return 0;		struct my_udisk *dev;	dev = (struct my_udisk *)file->private_data;	/* lock this object */	down (&dev->sem);	/* verify that the device wasn't unplugged */	if (dev->udev == NULL) {		up (&dev->sem);		return -ENODEV;	}	dbg(" - minor %d, cmd 0x%.4x, arg %ld", 	    dev->minor, cmd, arg);	/* fill in your device specific stuff here */	

⌨️ 快捷键说明

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