必威体育Betway必威体育官网
当前位置:首页 > IT技术

简析USB 骨架程序-usb-skeleton.c

时间:2019-10-02 14:13:21来源:IT技术作者:seo实验室小编阅读:74次「手机版」
 

module_device_table

kernel open source\drivers\USB\usb-skeleton.c 提供了一个最基础的USB驱动程序实例,即USB骨架程序。

USB 骨架程序的 usb_driver 结构体

static struct usb_driver skel_driver = {
	.name =		"skeleton",
	.probe =	skel_probe,
	.disconnect =	skel_disconnect,
	.suspend =	skel_suspend,
	.resume =	skel_resume,
	.pre_reset =	skel_pre_reset,
	.post_reset =	skel_post_reset,
	.id_table =	skel_table,
	.supports_autosuspend = 1,
};

上面代码中[ .id_table = skel_table, ]定义了该驱动程序支持的设备列表数组skel_table[],代码如下:

/* table of devices that work with this driver */
static const struct usb_device_id skel_table[] = {
	{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
	{ }					/* Terminating entry */
};
module_device_table(usb, skel_table);
MODULE_DEVICE_TABLE 宏定义作用详解->MODULE_DEVICE_TABLE

   对上面 usb_driver 的注册与注销发生在USB骨架程序的模块加载与卸载函数内,分别调用了 usb_register()和usb_deregister()函数。这两个函数使用快捷宏 module_usb_driver 实现->快捷宏module_usb_driver

module_usb_driver(skel_driver);
usb_driver 的注册与注销发生在USB骨架程序的模块加载与卸载函数内,分别调用了 usb_register()和usb_deregister()函数。
这两个函数使用快捷宏 module_usb_driver 实现,该宏在 include/linux/usb.h 中:

#define usb_register(driver) \
	usb_register_driver(driver, THIS_MODULE, Kbuild_MODNAME)

void usb_deregister(struct usb_driver *driver)
{
	pr_info("%s: deregistering interface driver %s\n",
			usbcore_name, driver->name);

	usb_remove_newid_files(driver);
	driver_unregister(&driver->drvwrap.driver);
	usb_free_dynids(driver);
}
export_symbol_GPL(usb_deregister);


#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
	return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
	__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);

#define module_usb_driver(__usb_driver) \
	module_driver(__usb_driver, usb_register, \
       usb_deregister)

   在 usb_probe 成员函数中,根据 usb_interface 成员寻找第一个批量输入和批量输出端点,并将端点地址、缓冲区等信息存入为USB骨架程序定义的 usb_skel 结构体中,并将 usb_skel 实例指针传入 usb_set_intfdata() 中以作为usb接口的私有数据,最后注册USB设备,代码清单如下:

static int skel_probe(struct usb_interface *interface,
		      const struct usb_device_id *id)
{
	……
	/* allocate memory for our device state and initialize it */
	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	……
	dev->udev = usb_get_dev(interface_to_usbdev(interface));
	dev->interface = interface;

	/* set up the endpoint information */
	/* use only the first bulk-in and bulk-out endpoints */
	iface_desc = interface->cur_altsetting;
	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
		endpoint = &iface_desc->endpoint[i].desc;

		if (!dev->bulk_in_endpointAddr &&
		    usb_endpoint_is_bulk_in(endpoint)) {
			/* we found a bulk in endpoint */
			buffer_size = usb_endpoint_maxp(endpoint);
			dev->bulk_in_size = buffer_size;
			dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
			dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
			if (!dev->bulk_in_buffer)
				goto ERROR;
			dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
			if (!dev->bulk_in_urb)
				goto error;
		}

		if (!dev->bulk_out_endpointAddr &&
		    usb_endpoint_is_bulk_out(endpoint)) {
			/* we found a bulk out endpoint */
			dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
		}
	}
	if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
		dev_err(&interface->dev,
			"Could not find both bulk-in and bulk-out endpoints\n");
		goto error;
	}

	/* save our data pointer in this interface device */
	usb_set_intfdata(interface, dev);

	/* we can register the device now, as it is ready */
	retval = usb_register_dev(interface, &skel_class);
	……
	return 0;
	……
}

usb_skel 结构体可以被看作一个私有数据结构,定义如下:

/* Structure to hold all of our device specific stuff */
struct usb_skel {
	struct usb_device	*udev;			/* the usb device for this device */
	struct usb_interface	*interface;		/* the interface for this device */
	struct semaphore	limit_sem;		/* limiting the number of writes in progress */
	struct usb_anchor	submitted;		/* in case we need to retract our submissions */
	struct urb		*bulk_in_urb;		/* the urb to read data with */
	unsigned char           *bulk_in_buffer;	/* the buffer to receive data */
	size_t			bulk_in_size;		/* the size of the receive buffer */
	size_t			bulk_in_filled;		/* number of bytes in the buffer */
	size_t			bulk_in_copied;		/* already copied to user space */
	__u8			bulk_in_endpointAddr;	/* the address of the bulk in endpoint */
	__u8			bulk_out_endpointAddr;	/* the address of the bulk out endpoint */
	int			errors;			/* the last request tanked */
	bool			ongoing_read;		/* a read is going on */
	spinlock_t		err_lock;		/* lock for errors */
	struct kref		kref;
	struct mutex		io_mutex;		/* synchronize I/O with disconnect */
	wait_queue_head_t	bulk_in_wait;		/* to wait for an ongoing read */
};

断开函数会完成与probe() 相反的工作,设置接口数据为NULL,注销USB设备,代码如下:

static void skel_disconnect(struct usb_interface *interface)
{
	struct usb_skel *dev;
	int minor = interface->minor;

	dev = usb_get_intfdata(interface);
	usb_set_intfdata(interface, NULL);

	/* give back our minor */
	usb_deregister_dev(interface, &skel_class);

	/* prevent more I/O from starting */
	mutex_lock(&dev->io_mutex);
	dev->interface = NULL;
	mutex_unlock(&dev->io_mutex);

	usb_kill_anchored_urbs(&dev->submitted);

	/* decrement our usage count */
	kref_put(&dev->kref, skel_delete);

	dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor);
}

   usb_probe()函数中的 usb_register_dev(interface, &skel_class)中的第二个参数包含字符设备的 file_operation 结构体指针,而这个结构体的成员也是USB字符设备的另一个组成部分。代码如下:

static const struct file_operations skel_fops = {
	.owner =	THIS_MODULE,
	.read =		skel_read,
	.write =	skel_write,
	.open =		skel_open,
	.release =	skel_release,
	.flush =	skel_flush,
	.llseek =	noop_llseek,
};

   skel_open()函数实现的非常简单,根据 usb_driver 和次设备号通过 usb_find_interface() 获得USB接口,之后通过 usb_get_intfdata()获得接口的私有数据并赋予 file->private_data,代码如下:

static int skel_open(struct inode *inode, struct file *file)
{
	struct usb_skel *dev;
	struct usb_interface *interface;
	int subminor;
	int retval = 0;

	subminor = iminor(inode);

	interface = usb_find_interface(&skel_driver, subminor);
	……
	dev = usb_get_intfdata(interface);
	……
	retval = usb_autopm_get_interface(interface);
	if (retval)
		goto exit;

	/* increment our usage count for the device */
	kref_get(&dev->kref);

	/* save our object in the file's private structure */
	file->private_data = dev;

exit:
	return retval;
}
        由于skel_open()中并未申请资源,所以skel_release()函数只需要减少一些引用计数即可。

贯穿读写函数函数的时URB结构体,在 skel_write() 函数中进行了URB的分配(调用usb_alloc_urb()),初始化(调用usb_fill_bluk_urb())和提交(调用usb_submit_urb()),代码如下:

static ssize_t skel_write(struct file *file, const char *user_buffer,
			  size_t count, loff_t *ppos)
{
	struct usb_skel *dev;
	int retval = 0;
	struct urb *urb = NULL;
	char *buf = NULL;
	size_t writesize = min(count, (size_t)MAX_TRANSFER);

	dev = file->private_data;
	……
	spin_lock_irq(&dev->err_lock);
	retval = dev->errors;
	……
	spin_unlock_irq(&dev->err_lock);
	……
	/* create a urb, and a buffer for it, and copy the data to the urb */
	urb = usb_alloc_urb(0, GFP_KERNEL);
	……
	buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL,
				 &urb->transfer_dma);
	……
	if (copy_from_user(buf, user_buffer, writesize)) {
		retval = -EFAULT;
		goto error;
	}

	/* this lock makes sure we don't submit URBs to gone devices */
	mutex_lock(&dev->io_mutex);
	……
	/* initialize the urb properly */
	usb_fill_bulk_urb(urb, dev->udev,
			  usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
			  buf, writesize, skel_write_bulk_callback, dev);
	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
	usb_anchor_urb(urb, &dev->submitted);

	/* send the data out the bulk port */
	retval = usb_submit_urb(urb, GFP_KERNEL);
	mutex_unlock(&dev->io_mutex);
	……
	usb_free_urb(urb);

	return writesize;
	……
}

   在写函数中发起的URB结束后,在 usb_fill_bulk_urb() 函数中填入的完成函数 skel_write_bulk_callback() 将会被调用,进行urb->status的判断,代码如下:

static void skel_write_bulk_callback(struct urb *urb)
{
	struct usb_skel *dev;

	dev = urb->context;

	/* sync/async unlink faults aren't errors */
	if (urb->status) {
		if (!(urb->status == -ENOENT ||
		    urb->status == -ECONNRESET ||
		    urb->status == -ESHUTDOWN))
			dev_err(&dev->interface->dev,
				"%s - nonzero write bulk status received: %d\n",
				__func__, urb->status);

		spin_lock(&dev->err_lock);
		dev->errors = urb->status;
		spin_unlock(&dev->err_lock);
	}

	/* free up our allocated buffer */
	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
			  urb->transfer_buffer, urb->transfer_dma);
	up(&dev->limit_sem);
}

相关阅读

默认打开USB调试功能

http://blog.csdn.net/pfgmylove/article/details/16985159

usb key 开发(二)

usb key 开发(二) 唯一ID 和 出厂编码 不一样 //推荐加密方案:生成随机数,让锁做加密运算,同时在程序中使用算法代码做同样的加密运算

前置USB接口不能使用的解决

朋友刚装的电脑,采用微星K7N2-DETRL-L主板,装的WinXP系统。电脑买回来后发现USB闪存或USB摄像头接在前置USB接口上不能用,表现为插上

STM32 USB-DFU说明

一:CUBEMAX配置 1.USB驱动选择 2.引脚一览 3.USB配置 #define FLASH_DESC_STR "@InternalFlash /0x08000000/03*016Ka,01*01

USB复合装置(Composite Device)

USB复合装置(Composite Device) 平台:NuMicro 在USB Specification Revision 2.0定义USB复合装置(Composite Device)为「具有多个

分享到:

栏目导航

推荐阅读

热门阅读