一、总线和驱动的注册,和别的驱动一样从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>