一、总线和驱动的注册,和别的驱动一样从module_init(ftdi_init);函数开始, ftdi_init------->
1. 先添加指定的VID/PID到
id_table_combined
中
if (vendor > 0 && product > 0) { <span style="color:#ff0000;">/* Add user specified VID/PID to reserved element of table. */ int i; for (i = 0; id_table_combined[i].idVendor; i++) ; id_table_combined[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE; id_table_combined[i].idVendor = vendor; id_table_combined[i].idProduct = product;</span> }
2. usb_serial_register(&ftdi_sio_device) 在USB转串口总线上注册驱动,它只是想USB总线注册,并不想kernel注册
-------------------------------------------------------------ftdi_sio_device-----------------------------------------------------------------------------
static struct usb_serial_driver ftdi_sio_device = {
.driver = {
.owner = THIS_MODULE,
.name = "ftdi_sio",
},
.description = "FTDI USB Serial Device",
.usb_driver = &ftdi_driver,
.id_table = id_table_combined,
.num_ports = 1,
.bulk_in_size = 512,
.bulk_out_size = 256,
.probe = ftdi_sio_probe,
.port_probe = ftdi_sio_port_probe,
.port_remove = ftdi_sio_port_remove,
.open = ftdi_open,
.close = ftdi_close,
.dtr_rts = ftdi_dtr_rts,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
.process_read_urb = ftdi_process_read_urb,
.prepare_write_buffer = ftdi_prepare_write_buffer,
.tiocmget = ftdi_tiocmget,
.tiocmset = ftdi_tiocmset,
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
};
-------------------------------------------------------------------------------------------------------------------------------------------
3.
usb_register(&ftdi_driver)
注册一条USB总线
----------------------------------------------------------------------ftdi_driver--------------------------------------------------------------------
static struct usb_driver ftdi_driver = {
.name = "ftdi_sio",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
.no_dynamic_id = 1,
};
-----------------------------------------------------------------------------------------------------------------------------------------------------
这时总线和驱动都已经准备就绪,只需要设备接入了。
二、当设备接入时,kernel将去调用
usb_serial_probe
函数。
1. 调用search_serial_device来收索设备,并获得
ftdi_sio_device
这个结构体
, 如果失败将返回错误信息。
2. 有设备与之匹配后,调用creat_serial函数去创建usb_serial结构体,同时对该结构体赋值,serial->type = driver;(即
ftdi_sio_device
), serial->interface = interface;------》此函数使用了kzalloc为设备分配usb_serial空间。
3. 如果创建成功,系统将调用usb serial 的探测函数probe了,即ftdi_sio_probe, 这个上面结构体中已经编写好了。
<span style="color:#333333;">static int ftdi_sio_probe(struct usb_serial *serial, const struct usb_device_id *id) { struct ftdi_sio_quirk *quirk = (struct ftdi_sio_quirk *)id->driver_info; if (quirk && quirk->probe) { int ret = quirk->probe(serial); if (ret != 0) return ret; } usb_set_serial_data(serial, (void *)id->driver_info); //将serial->private = </span><span style="font-family: Arial;"><span style="color:#333333;">id->driver_info, </span><span style="color:#3333ff;">此处的</span></span><span style="font-family: Arial;"><span style="color:#3333ff;">id->driver_info这个东西还没有看懂怎么来的,主要是interface还没有看是怎么出来的,兴许随着分析的深入就能找到答案。</span></span><span style="color: rgb(51, 51, 51); font-family: Arial;"> </span><span style="color:#333333;"> return 0; }</span>4. 接下来循环检测端点类型
iface_desc = interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; 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; } }5. 接着讲检测处理的结果赋值给serial,之后算出最大端点 max_endpoints
6. 对每一个端点进行设置和相关的初始化工作
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);//<span style="color:#3333ff;">初始化tty端口(z主要是这两个port->close_delay, port->closing_wait)</span> port->port.ops = &<span style="color:#ff0000;">serial_port_ops</span>; //⑴<span style="background-color: rgb(255, 255, 255);"><span style="color:#3333ff;">这个之后用着的时候进行详细分析</span></span> port->serial = serial; spin_lock_init(&port->lock); /* Keep this for private driver use for the moment but should probably go away */ INIT_WORK(&port->work, <span style="color:#ff0000;">usb_serial_port_work</span>);//⑵<span style="color:#3333ff;">创建以个工作队列,仍然是在使用到时在进行分析</span> serial->port[i] = port; port->dev.parent = &interface->dev; port->dev.driver = NULL; port->dev.bus = &<span style="color:#ff0000;">usb_serial_bus_type</span>;//⑶ port->dev.release = &<span style="color:#ff0000;">port_release</span>;//⑷ device_initialize(&port->dev); }7. 建立端点信息
for (i = 0; i < num_bulk_in; ++i) { endpoint = bulk_in_endpoint[i]; port = serial->port[i]; <span style="color:#ff0000;">port->read_urb = usb_alloc_urb(0, GFP_KERNEL)</span>;//分配<span style="color:#3366ff;">URB</span> if (!port->read_urb) { dev_err(&interface->dev, "No free urbs available\n"); goto probe_error; } buffer_size = serial->type->bulk_in_size; if (!buffer_size) 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); if (!port->bulk_in_buffer) { dev_err(&interface->dev, "Couldn't allocate bulk_in_buffer\n"); goto probe_error; } 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); }
<span style="font-size: 14px; line-height: 26px;">for (i = 0; i < num_bulk_out; ++i) { int j; 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; } if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL)) goto probe_error; buffer_size = serial->type->bulk_out_size; if (!buffer_size) 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); for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) { set_bit(j, &port->write_urbs_free); port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); if (!port->write_urbs[j]) { dev_err(&interface->dev, "No free urbs available\n"); goto probe_error; } port->bulk_out_buffers[j] = kmalloc(buffer_size, GFP_KERNEL); if (!port->bulk_out_buffers[j]) { dev_err(&interface->dev, "Couldn't allocate bulk_out_buffer\n"); goto probe_error; } usb_fill_bulk_urb(port->write_urbs[j], dev, usb_sndbulkpipe(dev, endpoint->bEndpointAddress), port->bulk_out_buffers[j], buffer_size, serial->type->write_bulk_callback, port); } } if (serial->type->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) { 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"); }</span>