usb_serial部分分析4

转自http://blog.csdn.net/aaronychen/article/details/3555885

接着看usb_serial_probe()

usb-serial.c:

....

       /* found all that we need */

       dev_info(&interface->dev, "%s converter detected/n", type->description);

 

#ifdef CONFIG_USB_SERIAL_GENERIC   //这个宏定义了, 因为我们使用的是通用USB驱动.

       if (type == &usb_serial_generic_device) {   //这个if为TRUE(上面分析过了)

              num_ports = num_bulk_out;  

              if (num_ports == 0) {    //bulk out端点必须要有

                     dev_err(&interface->dev, "Generic device with no bulk out, not allowed./n");

                     kfree (serial);

                     return -EIO;

              }

       }

#endif

       if (!num_ports) {   //由于走到了上面那个if段,因此这里的num_ports肯定不为0

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

              if (type->calc_num_ports) {

                     if (!try_module_get(type->driver.owner)) {

                            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_table项

       if (get_free_serial (serial, num_ports, &minor) == NULL) {

              dev_err(&interface->dev, "No more free serial devices/n");

              kfree (serial);

              return -ENOMEM;

       }

usbserial模块总共支持SERIAL_TTY_MINORS个设备, 它为每个设备都分配了一个serial_table项, 用于保存usb_serial对象, 方便以后直接通过minor号获取usb_serial对象.

usb-serial.c:

static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_ports, unsigned int *minor)

{

       unsigned int i, j;

       int good_spot;

 

       dbg("%s %d", __FUNCTION__, num_ports);

 

       *minor = 0;

       for (i = 0; i < SERIAL_TTY_MINORS; ++i) {

              if (serial_table[i])    //查找一个空闲的serial_table项, serial_table是个usb_serial的指针数组.

                     continue;

 

              good_spot = 1;

        //从上面代码可知, 对于generic的驱动, num_ports就等于num_bulk_out, 而一般的设备仅有//一个bulk out 的端点, 因此这个for循环不会执行.

              for (j = 1; j <= num_ports-1; ++j)

                     if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) {

                            good_spot = 0;

                            i += j;

                            break;

                     }

              if (good_spot == 0)

                     continue;

 

              *minor = i;  //获取minor号

              dbg("%s - minor base = %d", __FUNCTION__, *minor);

              for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)

serial_table[i] = serial;   //获取空闲的serial_table项, 并把我们的usb_serial对象地址保

//存在其中.

              return serial;

       }

       return NULL;

}

通过这个函数我们找到了一个空闲的serial_table项, 并把描述我们设备的usb_serial对象保存在其中, 在以后对设备的使用中, 我们可以轻易的通过minor号来找到这个usb_serial.

接着看usb_serial_probe()

usb-serial.c:

....

    //保存设备信息到usb_serial对象中,

       serial->minor = minor;

       serial->num_ports = num_ports;   //这里的port数量不是endpoint的数量,

       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;

 

      /* create our ports, we need as many as the max endpoints */

       /* we  don't use num_ports here cauz some devices have more endpoint pairs than ports */

    //对于generic的驱动来说一般都只有一个bulk in,一个bulk out,一个interrupt in,一个interrupt out

       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);

    //到这一步,对于generic来说大多数情况下max_endpoints还是为1

       serial->num_port_pointers = max_endpoints;

       dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);

       for (i = 0; i < max_endpoints; ++i) {

              port = kmalloc(sizeof(struct usb_serial_port), GFP_KERNEL);  //分配一个port对象

              if (!port)

                     goto probe_error;

       //初始化port对象

              memset(port, 0x00, sizeof(struct usb_serial_port));

              port->number = i + serial->minor;

              port->serial = serial;   //保存usb_serial对象, 便于以后通过port对象访问到usb_serial对象

              spin_lock_init(&port->lock);

              sema_init(&port->sem, 1);

              INIT_WORK(&port->work, usb_serial_port_softint, port);

              serial->port[i] = port;

       }

    //由上面的对port的初始化可知,每个port都有一套自己的工作机制, port间互不干扰

       /* set up the endpoint information */

       for (i = 0; i < num_bulk_in; ++i) {

        //初始化bulk in 端点, 并把它保存到相应的port里

              endpoint = bulk_in_endpoint[i];

              port = serial->port[i];

              port->read_urb = usb_alloc_urb (0, GFP_KERNEL);  //分配urb

              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);  //分配传输缓存

              if (!port->bulk_in_buffer) {

                     dev_err(&interface->dev, "Couldn't allocate bulk_in_buffer/n");

                     goto probe_error;

              }

        //设置好该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) {

        //初始化bulk out 端点, 并把它保存到相应的port里

              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);

       }

.....

上面这段代码主要是保存设备信息到usb_serial中去, 并为每个口分配一个port, 同时设置好port中的项.  对于这里的port, 我的理解是有的设备可能有多个口, 而每个口都有自己的一套endpoint用于该口的功能实现. 因此我们要为每个口分别分配port对象,并保存该口下的endpoint信息.

接着看usb_serial_probe()

usb-serial.c:

....

       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) {  //如果有interrupt in 而没有read_int_callback则是错误的

              dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");

       }

     //从上面这个if可以看出generic驱动的设备不应该有interrupt in 端点, 有也可以但是这个端点将

//不起作用.

//下面这个if和上面的这个if功能一模一样.

       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");

       }

      

       /* 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 */

                     goto exit;

              }

       }

 

       /* 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_bus上去

              port->dev.release = &port_release;

 

              snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number);

              dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id);

              device_register (&port->dev);    //把该设备注册到系统中去

       }

 

       usb_serial_console_init (debug, minor);

......

上面这段代码主要就是初始化interrupt的端点, 并且把port设备挂到usb_serial_bus上注册进系统,

接着看usb_serial_probe()

usb-serial.c:

......

exit:

       /* success */

       usb_set_intfdata (interface, serial);    //在interface对象里保存usb_serial对象地址,以方便以后使用

       return 0;

 

//错误处理

probe_error:

       for (i = 0; i < num_bulk_in; ++i) {

              port = serial->port[i];

              if (!port)

                     continue;

              if (port->read_urb)

                     usb_free_urb (port->read_urb);

              kfree(port->bulk_in_buffer);

       }

       for (i = 0; i < num_bulk_out; ++i) {

              port = serial->port[i];

              if (!port)

                     continue;

              if (port->write_urb)

                     usb_free_urb (port->write_urb);

              kfree(port->bulk_out_buffer);

       }

       for (i = 0; i < num_interrupt_in; ++i) {

              port = serial->port[i];

              if (!port)

                     continue;

              if (port->interrupt_in_urb)

                     usb_free_urb (port->interrupt_in_urb);

              kfree(port->interrupt_in_buffer);

       }

       for (i = 0; i < num_interrupt_out; ++i) {

              port = serial->port[i];

              if (!port)

                     continue;

              if (port->interrupt_out_urb)

                     usb_free_urb (port->interrupt_out_urb);

              kfree(port->interrupt_out_buffer);

       }

 

       /* return the minor range that this device had */

       return_serial (serial);

 

       /* 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都没什么用, 而且好像没看见这个设备和init时的那个tty_driver绑定啊,  不错, 这个probe函数本身还没有作这些工作, 我们接着分析

usb_serial_probe()函数在最后调用了device_register (&port->dev);把设备注册进了系统, 在这个注册过程中, 系统会在次为这个注册的设备进行probe过程.

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值