USB-serial驱动分析(usb转串口)

转自:http://blog.csdn.net/istone107/article/details/8123482 

在linux 内核中,有一个叫 usbserial 的模块可用作 usb modem 的驱动并能良好的工作, 所以详细

的分析下 usbserial 模块的源码(2.6.31)。对于那些仅仅是用 USB 来通信, 在上层可看作 tty 设备, 不属
于任何 USB 设备类型, 没有什么流控等的普通 USB 设备来说都可以使用这个 generic 驱动来作为设

备驱动程序。


该驱动中,修改默认的 idVendor 和 idProduct 如下:
static __u16 vendor  = 0x1286;
static __u16 product = 0x4e31;

首先, 当然是要知道 usbserial 模块由哪些文件编译而成,这样才能有目的性的去分析其代码,
而要知道其组成当然是去其目录下看 Makefile,它位于内核源码目录下的./drivers/usb/serial/下
obj-$(CONFIG_USB_SERIAL) += usbserial.o
usbserial-obj-$(CONFIG_USB_SERIAL_CONSOLE)  += console.o
usbserial-obj-$(CONFIG_USB_EZUSB)        += ezusb.o
usbserial-objs    := usb-serial.o generic.o bus.o $(usbserial-obj-y)
obj-$(CONFIG_USB_SERIAL_AIRCABLE)        += aircable.o
obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o
……
内核配置中有:
CONFIG_USB_SERIAL=y
CONFIG_USB_SERIAL_GENERIC=y
CONFIG_USB_SERIAL_OPTION=y (linux 2.6中usb modem 驱 动 程 序 , 因 为 usb-serial generic驱动程序读写速度不能满足 3G Modem 的要求)

重点的几个文件有:usb-serial.c、generic.c、usb.c 和 option.c


该模块的原理及整体结构:

1、跟应用层交互的是一个 tty 设备,也就是说该模块把 USB 设备映射成一个 tty 设备(即在/dev/目录下为该 USB 设备创建一个tty 设备文件),然后用于可以用 minicom 之类的串口工具来打开。

对于发送过程:tty 设备文件在获取了用户要求发送的数据之后传递到下层 usbserial 模块的核心层,而该核心层就是将数据打包成 USB 格式的数据并由 USB 通信发送到设备端去    。

对于接收过程:usbserial 模块会在该设备打开时就启动一个 urb 在那等待设备端发数据过来,收到数据后就 push 到上层 tty 设备的缓冲中去,而 tty 设备在收到数据后就会给用户,或直接显示在 minicom 之类的工具上。


1. USB-SERIAL 设备注册
从 module_init(usb_serial_init);开始
注:文中标有 [0] [1] [2] [3]。。。 的地方表示函数或变量的相关位置。
static int __init usb_serial_init(void)
{
int i;
int result;
//按照 tty “ 驱动结构,先创建  tty_driver”对象
usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
if (!usb_serial_tty_driver)
return -ENOMEM;
/* Initialize our global data,at most 254 驱动共支持 254个设备 */
for (i = 0; i < SERIAL_TTY_MINORS; ++i)
serial_table[i] = NULL; 
//注册总线  usb-serial”,之后的很多驱动及设备都注册在该总线上
result = bus_register(&usb_serial_bus_type);
if (result) {
printk(KERN_ERR "usb-serial: %s - registering bus driver "
       "failed\n", __func__);
goto exit_bus;
}
// 初始化  tty_driver”对象
usb_serial_tty_driver->owner = THIS_MODULE;
usb_serial_tty_driver->driver_name = "usbserial";
usb_serial_tty_driver->name =      "ttyUSB";
usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
usb_serial_tty_driver->minor_start = 0;
……
//设置 tty_driver 操作函数 fops
tty_set_operations(usb_serial_tty_driver, &serial_ops [11] );
//注册 tty 驱动
result = tty_register_driver(usb_serial_tty_driver);
if (result) {
printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n",       __func__);
goto exit_reg_driver;
}
/* register the USB driver */
result = usb_register(&usb_serial_driver [0] );//注册 usb 接口驱动,因为没有id_table不支持什么设备,所以仅仅是被其他函数调用
if (result < 0) {
printk(KERN_ERR "usb-serial: %s - usb_register failed\n",
       __func__);
goto exit_tty;
}

/* register the generic driver, if we should */
result = usb_serial_generic_register [1] (debug); //很重要,注册 generic 驱动
if (result < 0) {
printk(KERN_ERR "usb-serial: %s - registering generic "
       "driver failed\n", __func__);
goto exit_generic;
}
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return result;
exit_generic:
usb_deregister(&usb_serial_driver);
……
return result;
}
usb_serial_driver 的定义如下:
/* Driver structure we register with the USB core */
static struct usb_driver usb_serial_driver  = {
.name = "usbserial",
.probe =  usb_serial_probe,
.disconnect =  usb_serial_disconnect,
.suspend =       usb_serial_suspend,
.resume =usb_serial_resume,
.no_dynamic_id =   1,//不支持动态
};
usb_serial_init 在最后调用 usb_serial_generic_register 来注册 generic 驱动。
int usb_serial_generic_register(int _debug)
{
int retval = 0;debug = _debug;
#ifdef CONFIG_USB_SERIAL_GENERIC
generic_device_ids[0].idVendor = vendor;  //保存 idVendor
generic_device_ids[0].idProduct = product;  //保存 idProduct

generic_device_ids[0].match_flags =      //匹配类型
USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
/* register our generic driver with ourselves */
retval = usb_serial_register(&usb_serial_generic_device);// usb_serial_generic_device 结构体是之后用到的主要的 struct
if (retval)
goto exit;
//  注 册 该generic_driver” 的 目 的 是 , 当 设 备 插 入 系 统 时 , 通 过 generic_driver  的generic_probe来匹配设备
retval = usb_register (&generic_driver [4] );
if (retval)
usb_serial_deregister(&usb_serial_generic_device);
exit:
#endif
return retval;
}
struct usb_serial_generic_device 定义如下:
struct usb_serial_driver usb_serial_generic_device [2]  = {
.driver = {
.owner =  THIS_MODULE,
.name = "generic",
},
.id_table = generic_device_ids, //支持的设备列表,支持动态匹配
.usb_driver =          &generic_driver [4] ,
.num_ports =          1,
.disconnect =          usb_serial_generic_disconnect,
.release =        usb_serial_generic_release,
.throttle =        usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
.resume =        usb_serial_generic_resume,

};


接下来分析 usb_serial_register 函数。
int usb_serial_register [3]  (struct usb_serial_driver *driver)
{
/* must be called with BKL held */
int retval;if (usb_disabled())
return -ENODEV;
fixup_generic(driver);
if (!driver->description)
driver->description = driver->driver.name;
/* Add this device to our list of devices 添加到驱动列表*/
list_add(&driver->driver_list, &usb_serial_driver_list);
// 注册驱动到usb-serial总线上
retval = usb_serial_bus_register(driver);

if (retval) {
printk(KERN_ERR "usb-serial: problem %d when registering "
       "driver %s\n", retval, driver->description);
list_del(&driver->driver_list);
} else
printk(KERN_INFO "USB Serial support registered for %s\n",
driver->description);
return retval;

}


最后 usb_serial_generic_register()函数注册了一个 generic_driver 驱动。
static struct usb_driver generic_driver [4]  = {
.name = "usbserial_generic",
.probe =  generic_probe [5] ,//重要的匹配函数
.disconnect =  usb_serial_disconnect,
.id_table =       generic_serial_ids, //有用--仅定义driver_info
.no_dynamic_id =   1, //不支持动态匹配

};


整个初始化过程,乍一看一下子注册了几个驱动程序, 几个驱动列表,有的支持动态匹配有的
不支持,感觉很复杂,其实注册 generic_driver 驱动主要是为了注册一个 generic_probe 函数,而该
函数将会在设备连上系统后被调用以来匹配设备。除此之外该驱动没什么用,而在这个初始化函数
中把 vendor,product 都保存在了 generic_device_ids 里, 因此可以肯定以后的匹配将用这个设备列表,
而不是 generic_serial_ids,说的更直白些 generic_serial_ids 其实根本也没什么用。真正有用的是

usb_serial_generic_device 驱动。


接下来看看重要的匹配函数 generic_probe。如果接入系统的设备的 vendor 和 product 与我们驱动
支持的设备列表匹配,就继续匹配。
static int generic_probe(struct usb_interface *interface, const struct usb_device_id *id){
const struct usb_device_id *id_pattern;
id_pattern = usb_match_id(interface, generic_device_ids); //generic_device_ids已经被初始化
if (id_pattern != NULL)//对比设定的ID信息与usb读取出来的是否一致
return usb_serial_probe(interface, id); //继续匹配,寻找其和合适的驱动。调用的usb_serial_driver是之前注册到总线的一函数
return -ENODEV;
}
usb_serial_probe 函数很长,也是核心的匹配函数。
int usb_serial_probe (struct usb_interface *interface,const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(interface);
struct usb_serial *serial = NULL;
struct usb_serial_port *port;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
struct usb_serial_driver *type = NULL;
int retval;
……
int num_ports = 0;
int max_endpoints;
lock_kernel(); /* guard against unloading a serial driver module */
type = search_serial_device(interface);// “ 获取该设备匹配的驱动,  struct usb_serial_driver *type”
if (!type) {
unlock_kernel();
dbg("none matched");
return -ENODEV;
}
// “ 为该设备创建一个  usb_serial”对象
serial = create_serial(dev, interface, type);
if (!serial) {
unlock_kernel();
dev_err(&interface->dev, "%s - out of memory\n", __func__);
return -ENOMEM;

}/* if this device type has a probe function, call it */


if (type->probe) {  //“type->probe”未定义,不执行
const struct usb_device_id *id;
if (!try_module_get(type->driver.owner)) {
unlock_kernel();
dev_err(&interface->dev,
"module get failed, exiting\n");
kfree(serial);
return -EIO;
}
id = get_iface_id(type, interface);
retval = type->probe(serial, id);
module_put(type->driver.owner);
if (retval) {
unlock_kernel();
dbg("sub driver rejected device");
kfree(serial);
return retval;
}
}
/*  “ 以上代码主要是创建一个  usb_serial”的对象,用于保存该设备的详细信息,一般的
驱动程序都会为自己匹配的设备创建一个描用于描述该设备的对象,在以后的所有操作
中如读写等都会直接从这个对象里获取相应的信息。
*/
/* descriptor matches, let's find the endpoints needed */
/* check out the endpoints */
iface_desc = interface->cur_altsetting;  //设备接口的当前设置
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
//检查当前接口的端点类型,并保存,对于 usb-serial generic 设备,常见的端点只有 bulk out 或 bulk in 端点
if (usb_endpoint_is_bulk_in(endpoint)) {
/* we found a bulk in endpoint */
dbg("found bulk in on endpoint %d", i);
bulk_in_endpoint[num_bulk_in] = endpoint;
++num_bulk_in;
}
if (usb_endpoint_is_bulk_out(endpoint)) {
/* we found a bulk out endpoint */
dbg("found bulk out on endpoint %d", i);
bulk_out_endpoint[num_bulk_out] = endpoint;++num_bulk_out;
}
if (usb_endpoint_is_int_in(endpoint)) {
/* we found a interrupt in endpoint */
dbg("found interrupt in on endpoint %d", i);
interrupt_in_endpoint[num_interrupt_in] = endpoint;
++num_interrupt_in;
}
if (usb_endpoint_is_int_out(endpoint)) {
/* we found an interrupt out endpoint */
dbg("found interrupt out on endpoint %d", i);
interrupt_out_endpoint[num_interrupt_out] = endpoint;
++num_interrupt_out;
}
}
#if   defined(CONFIG_USB_SERIAL_PL2303)   || defined(CONFIG_USB_SERIAL_PL2303_MODULE)  // 用于特定类型的设备
/* BEGIN HORRIBLE HACK FOR PL2303 */
/* this is needed due to the looney way its endpoints are set up */
if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
     (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
    ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
     (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
  ……
}
}
}
/* Now make sure the PL-2303 is configured correctly.
 * If not, give up now and hope this hack will work
 * properly during a later invocation of usb_serial_probe
 */
if (num_bulk_in == 0 || num_bulk_out == 0) {
unlock_kernel();
dev_info(&interface->dev,   "PL-2303   hack:   descriptors   matched   but   endpoints   did 
not\n");
kfree(serial);
return -ENODEV;
}
}
/* END HORRIBLE HACK FOR PL2303 */

#endif

#ifdef CONFIG_USB_SERIAL_GENERIC  
if (type == &usb_serial_generic_device) {  //通过以上分析,此处为真
num_ports = num_bulk_out;
if (num_ports == 0) {
unlock_kernel();
dev_err(&interface->dev,
    "Generic device with no bulk out, not allowed.\n");
kfree(serial);
return -EIO;
}
}
#endif
if (!num_ports) {  // “ 经过以上步骤,  num_ports”的值不为 0
/* if this device type has a calc_num_ports function, call it */
if (type->calc_num_ports) {//NULL
if (!try_module_get(type->driver.owner)) {
unlock_kernel();
dev_err(&interface->dev,
"module get failed, exiting\n");
kfree(serial);
return -EIO;
}
num_ports = type->calc_num_ports(serial);
module_put(type->driver.owner);
}
if (!num_ports)
num_ports = type->num_ports;
}
serial->num_ports = num_ports;  //"num_ports"=="num_bulk_out"
serial->num_bulk_in = num_bulk_in;
serial->num_bulk_out = num_bulk_out;
serial->num_interrupt_in = num_interrupt_in;
serial->num_interrupt_out = num_interrupt_out;
/* found all that we need */
dev_info(&interface->dev, "%s converter detected\n", type->description);//type->description=generic
/* create our ports, we need as many as the max endpoints */
/* we don't use num_ports here because some devices have more
   endpoint pairs than ports */
max_endpoints = max(num_bulk_in, num_bulk_out);
max_endpoints = max(max_endpoints, num_interrupt_in);
max_endpoints = max(max_endpoints, num_interrupt_out);
max_endpoints = max(max_endpoints, (int)serial->num_ports);serial->num_port_pointers = max_endpoints;
unlock_kernel();
dbg("%s - setting up %d port structures for this device",
__func__, max_endpoints);
// 用 struct usb_serial_port 来描述一个 tty 端口,每个端口都有自己的工作模式
for (i = 0; i < max_endpoints; ++i) {
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
if (!port)
goto probe_error;
//初始化
tty_port_init(&port->port);
port->port.ops = &serial_port_ops;
//将 usb_serial 对象保存到 usb_serial_port 中,便于通过 port 来访问 serial
port->serial = serial;
spin_lock_init(&port->lock);
mutex_init(&port->mutex);
//初始化工作队列,其在 serial_write 的回调函数中被调用
INIT_WORK(&port->work, usb_serial_port_work);
serial->port[i] = port;//一个serial包含若干个port
}
/* set up the endpoint information */
for (i = 0; i < num_bulk_in; ++i) {//in =to cpu,out =from cpu
//初始化 bulk in “ 端点,保存到  usb_serial_port”(port 对象中)
endpoint = bulk_in_endpoint[i];
port = serial->port[i];
port->read_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!port->read_urb) {
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
port->bulk_in_size = buffer_size;
port->bulk_in_endpointAddress = endpoint->bEndpointAddress; //端点地址
port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); //传输 buffer 的大小
if (!port->bulk_in_buffer) {
dev_err(&interface->dev,
"Couldn't allocate bulk_in_buffer\n");
goto probe_error;
}
//在将 urb 提交到 usb core 之前,初始化 urb
usb_fill_bulk_urb(port->read_urb, dev,
usb_rcvbulkpipe(dev,
endpoint->bEndpointAddress),
port->bulk_in_buffer, buffer_size,serial->type->read_bulk_callback, port);//读回调函数
}
for (i = 0; i < num_bulk_out; ++i) {
endpoint = bulk_out_endpoint[i];
port = serial->port[i];
port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!port->write_urb) {
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
port->bulk_out_size = buffer_size;
port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!port->bulk_out_buffer) {
dev_err(&interface->dev,
"Couldn't allocate bulk_out_buffer\n");
goto probe_error;
}
usb_fill_bulk_urb(port->write_urb, dev,
usb_sndbulkpipe(dev,
endpoint->bEndpointAddress),
port->bulk_out_buffer, buffer_size,
serial->type->write_bulk_callback, port);//写回调函数
}
if (serial->type->read_int_callback) { //对于 generic 驱动,read_int_callback 指针为空
for (i = 0; i < num_interrupt_in; ++i) {
endpoint = interrupt_in_endpoint[i];
port = serial->port[i];
port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!port->interrupt_in_urb) {
dev_err(&interface->dev,
"No free urbs available\n");
goto probe_error;
}
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
port->interrupt_in_endpointAddress =
endpoint->bEndpointAddress;
port->interrupt_in_buffer = kmalloc(buffer_size,
GFP_KERNEL);
if (!port->interrupt_in_buffer) {
dev_err(&interface->dev,
    "Couldn't allocate interrupt_in_buffer\n");
goto probe_error;}
usb_fill_int_urb(port->interrupt_in_urb, dev,
usb_rcvintpipe(dev,
endpoint->bEndpointAddress),
port->interrupt_in_buffer, buffer_size,
serial->type->read_int_callback, port,
endpoint->bInterval);
}
} else if (num_interrupt_in) {
dbg("the   device   claims   to   support   interrupt   in   transfers,   but   read_int_callback   is   not 
defined");
}
if (serial->type->write_int_callback) { //对于 generic 驱动,write_int_callback 指针为空
for (i = 0; i < num_interrupt_out; ++i) {
endpoint = interrupt_out_endpoint[i];
port = serial->port[i];
port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!port->interrupt_out_urb) {
dev_err(&interface->dev,
"No free urbs available\n");
goto probe_error;
}
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
port->interrupt_out_size = buffer_size;
port->interrupt_out_endpointAddress =
endpoint->bEndpointAddress;
port->interrupt_out_buffer = kmalloc(buffer_size,
GFP_KERNEL);
if (!port->interrupt_out_buffer) {
dev_err(&interface->dev,
  "Couldn't allocate interrupt_out_buffer\n");
goto probe_error;
}
usb_fill_int_urb(port->interrupt_out_urb, dev,
usb_sndintpipe(dev,
  endpoint->bEndpointAddress),
port->interrupt_out_buffer, buffer_size,
serial->type->write_int_callback, port,
endpoint->bInterval);
}
} else if (num_interrupt_out) {
dbg("the   device   claims   to   support   interrupt   out   transfers,   but   write_int_callback   is   not 
defined");

}/* if this device type has an attach function, call it */
if (type->attach) { //对于 generic 驱动,attach 指针为空
if (!try_module_get(type->driver.owner)) {
dev_err(&interface->dev,
"module get failed, exiting\n");
goto probe_error;
}
retval = type->attach(serial);
module_put(type->driver.owner);
if (retval < 0)
goto probe_error;
if (retval > 0) {
/* quietly accept this device, but don't bind to a
   serial port as it's about to disappear */
serial->num_ports = 0;
goto exit;
}
}

/* usbserial 模块总共支持 254 个设备, “ 它为每个设备都分配了一个  serial_table项  
用于保存  usb_serial”对象,方便以后直接通过 minor “号获取  usb_serial”对象
*/
if (get_free_serial(serial, num_ports, &minor) == NULL) {//serial->port[j++]->number = i.(serial_table[i]=serial)
dev_err(&interface->dev, "No more free serial devices\n");
goto probe_error;
}
serial->minor = minor;
/* register all of the individual ports with the driver core */
for (i = 0; i < num_ports; ++i) {
port = serial->port[i];
port->dev.parent = &interface->dev;
port->dev.driver = NULL;
port->dev.bus = &usb_serial_bus_type; // “ 指明了要注册到  usb-serial”总线
port->dev.release = &port_release;
dev_set_name(&port->dev, "ttyUSB%d", port->number); //设置端口名称
dbg ("%s - registering %s", __func__, dev_name(&port->dev));
port->dev_state = PORT_REGISTERING;
retval = device_register(&port->dev);  //注册
if (retval) {
dev_err(&port->dev, "Error registering port device, "
"continuing\n");
port->dev_state = PORT_UNREGISTERED;
} else {
port->dev_state = PORT_REGISTERED;}
}
usb_serial_console_init(debug, minor);
exit:
/* success */
//在 usb “ 设备接口描述符中保存  usb_serial”对象地址,便于以后调用
usb_set_intfdata(interface, serial); 
return 0;
probe_error:
for (i = 0; i < num_bulk_in; ++i) {
port = serial->port[i];
if (!port)
continue;
usb_free_urb(port->read_urb);
kfree(port->bulk_in_buffer);
}
……
/* free up any memory that we allocated */
for (i = 0; i < serial->num_port_pointers; ++i)
kfree(serial->port[i]);
kfree(serial);
return -EIO;
}
整个 probe 过程就结束了,或许你会奇怪,好像 usb_serial_bus 都没什么用,而且好像没看见这
个设备和初始化时的那个 tty_driver 绑定啊,不错,这个 probe 函数本身还没有作这些工作,我们接
着分析。

usb_serial_probe()函数在最后调用了 device_register(&port->dev);

把设备注册进了系统,在这个注册过程中,系统会再次为这个注册的设备进行 probe 过程。

int device_register [6]  (struct device *dev)
{
device_initialize(dev);
return device_add(dev);
}
Driver 的 probe 的调用顺序:
1 、device_add() :把 device 注册到相应的 bus 上去,并创建相应的 device file ,最后调用
bus_attach_device()函数;
2、bus_attach_device()调用 device_attach(dev);
3、device_attach() 调用 bus_for_each_drv() 遍历 bus 上的每个 driver ,当找到一个 driver 则用
__device_attach()来判断是否匹配;
4、__device_attach():直接调用 driver_probe_device(drv, dev);
5、driver_probe_device():首先如果 driver 所在总线有 match 函数则先调用这个 match 来匹配,如 不匹配则直接返回错误,否则接着调用 really_probe(dev,drv);

6、really_probe():先判断 dev 所在总线是否有 probe 函数,有则调用它来匹配,失败则返回,正确则成功。如果总线没有 probe 则判断 drv 是否有 probe 函数,有则调用并匹配它;

7、drv->probe():一般它是一类设备的 probe,在它里面它会调用具体某个 drv 的 probe 函数,这 个函数是在我们的驱动程序里面注册的。

device_register()里会调用 device_add()。

因此由 5 可知系统会先调用总线上的 match 函数来匹配。 

对于我们的总线就是 usb_serial_bus,它的 match 函数就是 usb_serial_device_match(),通过前面的
代码分析,知道设备和驱动都是注册在这条总线上的。
struct bus_type usb_serial_bus_type [7]  = {
.name = "usb-serial",
.match =  usb_serial_device_match [8] ,
.probe =  usb_serial_device_probe [9] ,
.remove =        usb_serial_device_remove,
.drv_attrs =     drv_attrs,
};
看看 usb_serial_device_match 函数。
static int usb_serial_device_match [8]  (struct device *dev,
struct device_driver *drv)
{
struct usb_serial_driver *driver;
const struct usb_serial_port *port;
/*
 * drivers are already assigned to ports in serial_probe so it's
 * a simple check here.
 */
port = to_usb_serial_port(dev); //获取 usb_serial_port 对象
if (!port)
return 0;
driver = to_usb_serial_driver(drv); //获取 usb_serial_driver 对象
if (driver == port->serial->type)//仅是判断struct usb_serial_device是否一致
return 1;
return 0;
}
接下来会调用总线的 probe 函数,就是 usb_serial_device_probe。
static int usb_serial_device_probe [9]  (struct device *dev)
{
struct usb_serial_driver *driver;
struct usb_serial_port *port;
int retval = 0;
int minor;port = to_usb_serial_port(dev);
if (!port) {
retval = -ENODEV;
goto exit;
}
if (port->dev_state != PORT_REGISTERING)
goto exit;
driver = port->serial->type;
if (driver->port_probe) {
retval = driver->port_probe(port);
if (retval)
goto exit;
}
retval = device_create_file(dev, &dev_attr_port_number);
if (retval) {
if (driver->port_remove)
retval = driver->port_remove(port);
goto exit;
}
minor = port->number;
tty_register_device(usb_serial_tty_driver, minor, dev); //此处将 tty_driver 和 device 绑定
dev_info(&port->serial->dev->dev, "%s converter now attached to ttyUSB%d\n", driver->description, minor);
exit:
return retval;
}
到了这一步该设备就和 tty_driver 绑定在了一起了,同时在/dev 目录下也创建了相应的设备文件

了,也就是说应用层可以使用这个设备了。

//

2. USB 设备设备匹配
USB 设备的匹配过程如下:
USB 设备都是通过插入上层 HUB 的一个 Port 来连入系统并进而被系统发现的,当 USB 设备插
入一个 HUB 时,该 HUB 的那个 port 的状态就会改变,从而系统就会知道这个改变,此时会调用
hub_port_connect_change()函数。
/* Handle physical or logical connection change events.
 * This routine is called when:
 *       a port connection-change occurs; *       a port enable-change occurs (often caused by EMI);
 *       usb_reset_and_verify_device() encounters changed descriptors (as from
 * a firmware download)
 * caller already locked the hub
 */
static void hub_port_connect_change(struct usb_hub *hub, int port1,
u16 portstatus, u16 portchange)
{
struct usb_device *hdev = hub->hdev;
struct device *hub_dev = hub->intfdev;
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
……
/* Run it through the hoops (find a driver, etc) */
if (!status) {
status = usb_new_device [10]  (udev);
if (status) {
spin_lock_irq(&device_state_lock);
hdev->children[port1-1] = NULL;
spin_unlock_irq(&device_state_lock);
}
}
……
}
“ 该函数创建一个  usb_device”的对象 udev,并初始化它,接着调用 usb_new_device()来获取这个
usb 设备的各种描述符并为每个 interface 找到对应的 driver。
int usb_new_device [10]  (struct usb_device *udev)
{
int err;
/* Increment the parent's count of unsuspended children */
if (udev->parent)
usb_autoresume_device(udev->parent);
usb_detect_quirks(udev); /* Determine quirks */
err = usb_configure_device(udev); /* detect & probe dev/intfs */
if (err < 0)
goto fail;
dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
udev->devnum, udev->bus->busnum,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
/* export the usbdev device-node for libusb */
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
/* Tell the world! */announce_device(udev);
/* Register the device.  The device driver is responsible
 * for configuring the device and invoking the add-device
 * notifier chain (used by usbfs and possibly others).
 */
err = device_add(&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
goto fail;
}
(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
return err;
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
usb_stop_pm(udev);
return err;
}
该函数首先调用 usb_get_configuration()来获取设备的各种描述符(设备描述符,配置描述符等),
接着调用 device_add()来把这个 USB 设备添加到 USB 系统中去,也就是在这个过程中系统回去为这

个设备找到相应的驱动。之后的流程同 Driver 的 probe 的调用流程一样。

//

3. USB-SERIAL 读写分析
要使用设备当然要先打开这个设备了,应用层调用 open 系统调用来打开这个设备,它最终会调 用我们 tty_driver 的 open 函数。
static struct tty_operations serial_ops [11]  = {
       .open =                 serial_open [12] ,
       .close =          serial_close,
       .write =          serial_write [17] ,
       .write_room =       serial_write_room,
       .ioctl =           serial_ioctl,
       .set_termios =        serial_set_termios,
       .throttle =              serial_throttle,
       .unthrottle =          serial_unthrottle,
       .break_ctl =           serial_break,
       .chars_in_buffer = serial_chars_in_buffer,
       .read_proc =          serial_read_proc,
       .tiocmget =            serial_tiocmget,
       .tiocmset =            serial_tiocmset,
};
首先看看 serial_open 函数。static int serial_open [12]  (struct tty_struct *tty, struct file *filp)
{
struct usb_serial *serial;
struct usb_serial_port *port;
unsigned int portNumber;
int retval = 0;
int first = 0;
dbg("%s", __func__);
/* get the serial object associated with this tty pointer */
serial = usb_serial_get_by_index(tty->index); //        “   获取  usb_serial”对象
if (!serial) {
tty->driver_data = NULL;
return -ENODEV;
}
mutex_lock(&serial->disc_mutex);
portNumber = tty->index - serial->minor;// ???
port = serial->port[portNumber]; //获取设备对应的 port 对象
if (!port || serial->disconnected)
retval = -ENODEV;
else
get_device(&port->dev);
……
++port->port.count; //打开次数
/* set up our port structure making the tty driver
 * remember our port object, and us it */
tty->driver_data = port;  //方便以后引用
tty_port_tty_set(&port->port, tty);
/* If the console is attached, the device is already open */
if (port->port.count == 1 && !port->console) {
first = 1;
/* lock this module before we call it
 * this may fail, which means we must bail out,
 * safe because we are called with BKL held */
if (!try_module_get(serial->type->driver.owner)) {
retval = -ENODEV;
goto bailout_mutex_unlock;
}
/* only call the device specific open if this
 * is the first time the port is opened */
//调用 usb_serial_driver 的 open 函数,及// usb_serial_generic_device.open = usb_serial_generic_open [13] ;
retval = serial->type->open(tty, port, filp); 
if (retval)
goto bailout_interface_put;
mutex_unlock(&serial->disc_mutex);
set_bit(ASYNCB_INITIALIZED, &port->port.flags);
}
mutex_unlock(&port->mutex);
……
/* Now do the correct tty layer semantics */
retval = tty_port_block_til_ready(&port->port, tty, filp);
if (retval == 0) {
if (!first)
usb_serial_put(serial);
return 0;
……
return retval;
}
接下来看看 usb_serial_generic_open 函数。
int usb_serial_generic_open [13]  (struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
{
struct usb_serial *serial = port->serial;
int result = 0;
unsigned long flags;
dbg("%s - port %d", __func__, port->number);
/* clear the throttle flags */
spin_lock_irqsave(&port->lock, flags);
port->throttled = 0;
port->throttle_req = 0;
spin_unlock_irqrestore(&port->lock, flags);
/* if we have a bulk endpoint, start reading from it */
 // 如果有 bulk in 的端点的话,就提交这个端点的 urb,即让系统开始在这个端点上接收来
自设备端发过来的数据,当数据收到后会调用 serial->type->read_bulk_callback 函数。
if (serial->num_bulk_in) {
/* Start reading from the device */
usb_fill_bulk_urb(port->read_urb, serial->dev,
   usb_rcvbulkpipe(serial->dev,
port->bulk_in_endpointAddress),
   port->read_urb->transfer_buffer,
   port->read_urb->transfer_buffer_length,
   ((serial->type->read_bulk_callback) ?     serial->type->read_bulk_callback :
     usb_serial_generic_read_bulk_callback [14] ), port);
//提交到 usb core,成功后执行回调函数 usb_serial_generic_read_bulk_callback
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
    "%s - failed resubmitting read urb, error %d\n",
__func__, result);
}
return result;
}
执行完以上代码后,系统就可在 bulk in 端点上接收数据了,当有数据时就调用回调函数,接下 来看看回调函数。
void usb_serial_generic_read_bulk_callback [14]  (struct urb *urb)
{
struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
unsigned long flags;
 ……
spin_lock_irqsave(&port->lock, flags);
port->throttled = port->throttle_req;
if (!port->throttled) {
spin_unlock_irqrestore(&port->lock, flags);
flush_and_resubmit_read_urb [15]  (port);  //将数据放入 tty 驱动的缓冲区,并继续接收
} else
spin_unlock_irqrestore(&port->lock, flags);
}
接下来分析 flush_and_resubmit_read_urb 函数。
/* Push data to tty layer and resubmit the bulk read URB */
static void flush_and_resubmit_read_urb [15]  (struct usb_serial_port *port)
{
struct urb *urb = port->read_urb;
struct tty_struct *tty = tty_port_tty_get(&port->port);
char *ch = (char *)urb->transfer_buffer;
int i;
if (!tty)
goto done;
/* The per character mucking around with sysrq path it too slow for
   stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases

   where the USB serial is not a console anyway */

if (!port->console || !port->sysrq)

   tty_insert_flip_string(tty, ch, urb->actual_length); //将数据放入 tty 驱动的缓冲区
else {
/* Push data to tty */
for (i = 0; i < urb->actual_length; i++, ch++) {
if (!usb_serial_handle_sysrq_char(tty, port, *ch))
tty_insert_flip_char(tty, *ch, TTY_NORMAL);
}
}
tty_flip_buffer_push(tty);
tty_kref_put(tty);
done:
usb_serial_generic_resubmit_read_urb [16]  (port, GFP_ATOMIC); //继续传输
}
继续往前看,usb_serial_generic_resubmit_read_urb 函数。
void usb_serial_generic_resubmit_read_urb [16]  (struct usb_serial_port *port,
gfp_t mem_flags)
{
struct urb *urb = port->read_urb;
struct usb_serial *serial = port->serial;
int result;
/* Continue reading from device */
//继续初始化 urb 并提交到 usb core
usb_fill_bulk_urb(urb, serial->dev,
   usb_rcvbulkpipe(serial->dev,
port->bulk_in_endpointAddress),
   urb->transfer_buffer,
   urb->transfer_buffer_length,
   ((serial->type->read_bulk_callback) ?
     serial->type->read_bulk_callback :
     usb_serial_generic_read_bulk_callback), port);
result = usb_submit_urb(urb, mem_flags);
if (result)
dev_err(&port->dev,
"%s - failed resubmitting read urb, error %d\n",
__func__, result);
}

很明显,回调函数就是把从设备端收到的数据 push 到相对上层的 tty 驱动中去,随后 tty 子系统会把这些数据返回给用户,并且重新提交一个个urb。至此,接收流程完毕。

接下来看看发送流程,还是从 serial_write 开始。
static int serial_write [17]  (struct tty_struct *tty, const unsigned char *buf,int count)
{
struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
 ……
/* pass on to the driver specific version of this function */
// usb_serial_generic_device.write =usb_serial_generic_write [18] ;
retval = port->serial->type->write(tty, port, buf, count);
exit:
return retval;
}
同理,serial_write 函数调用了 usb_serial_generic_write,看看先。
int usb_serial_generic_write [18]  (struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count)
{
struct usb_serial *serial = port->serial;
int result;
unsigned char *data;
……
if (serial->num_bulk_out) { //只有 bulk out 端点才能发送数据
unsigned long flags;
if (serial->type->max_in_flight_urbs)
return usb_serial_multi_urb_write(tty, port,
  buf, count);
spin_lock_irqsave(&port->lock, flags);
if (port->write_urb_busy) {
spin_unlock_irqrestore(&port->lock, flags);
dbg("%s - already writing", __func__);
return 0;
}
port->write_urb_busy = 1;
spin_unlock_irqrestore(&port->lock, flags);
count = (count > port->bulk_out_size) ?
port->bulk_out_size : count;
//将发送的数据及长度放入 urb 中
memcpy(port->write_urb->transfer_buffer, buf, count);
data = port->write_urb->transfer_buffer;
usb_serial_debug_data(debug, &port->dev, __func__, count, data);
/* set up our urb */
//初始化 urbusb_fill_bulk_urb(port->write_urb, serial->dev,
   usb_sndbulkpipe(serial->dev,
port->bulk_out_endpointAddress),
   port->write_urb->transfer_buffer, count,
   ((serial->type->write_bulk_callback) ?
     serial->type->write_bulk_callback :
     usb_serial_generic_write_bulk_callback [19] ),
   port);
/* send the data out the bulk port */
port->write_urb_busy = 1;
//提交 urb 到 usb core
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
dev_err(&port->dev,
"%s - failed submitting write urb, error %d\n",
__func__, result);
/* don't have to grab the lock here, as we will
   retry if != 0 */
port->write_urb_busy = 0;
} else
result = count;
return result;
}
/* no bulk out, so return 0 bytes written */
return 0;
}
接下来看看 usb_serial_generic_write_bulk_callback 回调函数。
void usb_serial_generic_write_bulk_callback [19]  (struct urb *urb)
{
unsigned long flags;
struct usb_serial_port *port = urb->context;
int status = urb->status;
dbg("%s - port %d", __func__, port->number);
……
usb_serial_port_softint(port)  [20] ; //请求更多传输
}
接下来看看 usb_serial_port_softint 函数。
void usb_serial_port_softint [20]  (struct usb_serial_port *port)
{
schedule_work(&port->work [21] );}
调度下一个工作,工作队列初始化 usb_serial_probe 函数中,其定义如下:
static void usb_serial_port_work [21]  (struct work_struct *work)
{
struct usb_serial_port *port =
container_of(work, struct usb_serial_port, work);
struct tty_struct *tty;
dbg("%s - port %d", __func__, port->number);
tty = tty_port_tty_get(&port->port);
if (!tty)
return;
tty_wakeup(tty); //请求更多的传输
tty_kref_put(tty);
}
  • 1
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值