「Linux下USB驱动详解」

1. USB驱动基础知识

在深入探究Linux下USB驱动前,我们有必要先梳理一下USB驱动的基础知识。USB的英文全称是Universal Serial Bus,中文译作通用串行总线。它是一种计算机外部设备连接标准,被广泛地应用于鼠标、键盘、打印机、手机等设备中。

USB是一种序列化接口,它连接的设备可以是低带宽(1.5Mbps)的从设备,也可以是全速设备(12Mbps)、高速设备(480Mbps)、超高速设备(5Gbps)等。

Linux内核中,USB驱动被分为两类:

USB核心驱动(usbcore):负责USB设备的探测、枚举和配置。

USB设备驱动:负责具体的USB设备类型的驱动和操作。

对于Linux下的USB驱动,我们需要掌握下面的一些概念:

USB设备描述符:包含了关于USB设备的描述信息。

USB接口描述符:描述了USB设备的一个特定接口。

USB端点描述符:描述了一个USB接口的端点,并包含了描述端点方向、类型、传输大小等方面的信息。

USB传输:根据端点描述符中的信息,进行USB数据的传输。

USB控制传输:使用特殊的USB控制命令进行数据传输。

2. USB驱动框架

Linux内核中,USB驱动采用了一种面向对象的编程方式,即将USB设备和USB驱动都分成多个不同的层级:

2.1. USB设备层

USB设备层表示了具体的USB设备,它由三个部分组成:

USB设备驱动(usb_device_driver):负责探测和匹配设备。

USB设备(usb_device):表示一个具体的USB设备,包含了设备描述符、接口描述符等信息。

USB接口(usb_interface):表示一个具体的USB设备接口,包含了一个或多个USB端点。

2.2. USB核心层

USB核心层负责枚举和控制所有已接入设备,这个层次的主要结构体有:

USB总线(usb_bus):表示一个具体的USB总线。

USB控制器(usb_hcd):代表一个具体的USB控制器,负责物理层面的定义和控制。

USB主机(usb_host):表示一个具体的USB主机,其中包含了一个或多个USB总线。

2.3. USB驱动层

USB驱动层负责具体的处理逻辑,对外提供一系列函数和接口,包括设备的打开、关闭、读写操作等等,具体的结构体有:

USB驱动(usb_driver):表示一个具体的USB驱动,负责设备的操作和处理。

USB请求块(urb):表示一个USB传输请求,包括传输的方向、长度、缓冲区等信息。

USB文件操作结构体(file_operations):表示针对USB设备的文件操作,如打开、读写等。

3. USB驱动开发

在Linux下进行USB驱动开发,需要了解一些基本的驱动接口,包括:

usb_register_driver():注册一个USB设备驱动。

usb_deregister_driver():注销一个USB设备驱动。

usb_register_dev():注册一个USB设备,创建一个字符设备节点。

usb_deregister_dev():注销一个USB设备,销毁相应的字符设备节点。

usb_submit_urb():向USB设备发送一个传输请求。

usb_unlink_urb():停止一个传输请求的传输。

usb_alloc_urb():分配一个传输请求。

usb_free_urb():释放一个传输请求。

下面是一个简单的示例代码,演示了如何实现一个USB设备的读操作:

static int my_usb_open(struct inode *i, struct file *f)

{

struct usb_interface *iface;

struct my_usb_data *devdata;

iface = usb_find_interface(&my_usb_driver, iminor(i));

if (!iface)

return -ENODEV;

devdata = kmalloc(sizeof(struct my_usb_data), GFP_KERNEL);

if (!devdata)

return -ENOMEM;

f->private_data = devdata;

return 0;

}

static int my_usb_read(struct file *f, char __user *buf, size_t count, loff_t *offp)

{

struct my_usb_data *devdata = f->private_data;

int retval;

struct urb *urb;

u8 endpoint = usb_rcvbulkpipe(devdata->udev, devdata->incoming_ep);

urb = usb_alloc_urb(0, GFP_KERNEL);

if (urb == NULL)

return -ENOMEM;

usb_fill_bulk_urb(urb, devdata->udev, endpoint,

devdata->buffer, devdata->buffer_size,

my_usb_read_complete, devdata);

retval = usb_submit_urb(urb, GFP_KERNEL);

if (retval)

usb_free_urb(urb);

else

wait_for_completion(&devdata->done);

/* 将读取到的数据拷贝到用户空间 */

if (*offp >= devdata->buffer_size)

return 0;

if (count > devdata->buffer_size - *offp)

count = devdata->buffer_size - *offp;

if (copy_to_user(buf, devdata->buffer + *offp, count))

return -EFAULT;

*offp += count;

return count;

}

static int my_usb_release(struct inode *i, struct file *f)

{

struct my_usb_data *devdata = f->private_data;

kfree(devdata);

return 0;

}

static struct file_operations my_usb_fops = {

owner: THIS_MODULE,

open: my_usb_open,

read: my_usb_read,

release: my_usb_release,

};

static struct usb_class_driver my_usb_class = {

name: "my_usb",

fops: &my_usb_fops,

minor_base: 0,

};

static struct usb_device_id my_usb_table[] = {

{ USB_DEVICE(ID_VENDOR, ID_PRODUCT) },

{ }

};

MODULE_DEVICE_TABLE(usb, my_usb_table);

static int my_usb_probe(struct usb_interface *interface, const struct usb_device_id *id)

{

struct usb_device *udev;

struct my_usb_data *devdata;

u8 incoming_ep, outgoing_ep;

int retval;

udev = interface_to_usbdev(interface);

incoming_ep = usb_endpoint_num(&intf->altsetting[0].endpoint[0].desc);

outgoing_ep = usb_endpoint_num(&intf->altsetting[0].endpoint[1].desc);

devdata = kmalloc(sizeof(struct my_usb_data), GFP_KERNEL);

devdata->udev = udev;

devdata->incoming_ep = incoming_ep;

devdata->outgoing_ep = outgoing_ep;

interface->dev.driver_data = devdata;

retval = usb_register_dev(interface, &my_usb_class);

if (retval)

return retval;

usb_set_intfdata(interface, devdata);

return 0;

}

static void my_usb_disconnect(struct usb_interface *interface)

{

struct my_usb_data *devdata;

devdata = usb_get_intfdata(interface);

usb_deregister_dev(interface, &my_usb_class);

kfree(devdata);

}

static struct usb_driver my_usb_driver = {

name: "my_usb",

probe: my_usb_probe,

disconnect: my_usb_disconnect,

id_table: my_usb_table,

};

module_usb_driver(my_usb_driver);

4. 总结

本文对Linux下USB驱动进行了详细的讲解,包括USB驱动的基础知识、USB驱动框架、USB驱动的开发等方面。希望读者能够通过本文的学习,对Linux下USB驱动的开发有更加深入的了解。

操作系统标签