小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

usb-serial分析

 WUCANADA 2013-10-10

usb-serial分析

分類: usb 驅(qū)動 658人閱讀 評論(0) 收藏 舉報
重要文件由usb-serial.c ; generic.c ; usb.c ; option.c
從module_init(usb_serial_init)開始
//按照tty驅(qū)動結(jié)構(gòu),先創(chuàng)建"tty_driver"對象
alloc_tty_driver(SERIAL_TTY_MINIOR)
注冊總線usb-serial,之后很多驅(qū)動及設備都會注冊到該總線上
bus_register(&usb_serial_bus_type)
關于
struct bus_type usb_serial_bus_type = {
 .name =  "usb-serial",
 .match = usb_serial_device_match,
 .probe = usb_serial_device_probe,
 .remove = usb_serial_device_remove,
 .drv_attrs =  drv_attrs,
};

為什么沒有注冊這個總線設備,device_register(usb_serial_bus)??
初始化tty_driver對象
usb_serial_tty_driver->name=..
.
.
.

設置tty_driver的操作函數(shù)fops
tty_set_operation(usb_serial_tty_driver,&serial_ops)
向tty核心注冊tty驅(qū)動
tty_register_driver(usb_serial_tty_driver)
將usb_serial_driver驅(qū)動注冊到usb總線上
usb_register(usb_serial_driver)
關于usb_serial_driver
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,
};
最后注冊generic驅(qū)動
usb_serial_generic_register(debug)

分析usb_serial_generic_register(debug)
保存idVendor generic_device_ids[0].idVendor=vendor
保存idProduct generic_device_ids[0].idProduct=idProduct
匹配類型generic_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
將usb_serial_generic_device結(jié)構(gòu)體(未知是驅(qū)動結(jié)構(gòu)體還是設備結(jié)構(gòu)體)注冊到usb-serial總線上
usb_serial_register(&usb_serial_generic_device)
關于usb_serial_generic_device
struct usb_serial_driver usb_serial_generic_device = {
 .driver = {
  .owner = THIS_MODULE,
  .name =  "generic",
 },
 .id_table =  generic_device_ids,
 .usb_driver =   &generic_driver,
 .num_interrupt_in = NUM_DONT_CARE,
 .num_bulk_in =  NUM_DONT_CARE,
 .num_bulk_out =  NUM_DONT_CARE,
 .num_ports =  1,
 .shutdown =  usb_serial_generic_shutdown,
 .throttle =  usb_serial_generic_throttle,
 .unthrottle =  usb_serial_generic_unthrottle,
 .resume =  usb_serial_generic_resume,
};
其中,usb_serial_driver是新定義的驅(qū)動結(jié)構(gòu)體

將"generic_driver"注冊到usb總線上,目的是當設備插入系統(tǒng)后,通過generic_driver的generic_probe
來匹配設備。因此。已經(jīng)注冊了兩個驅(qū)動進了usb總線
usb_register(&generic_driver)
關于generic_driver結(jié)構(gòu)體
static struct usb_driver generic_driver = {
 .name =  "usbserial_generic", //驅(qū)動名稱
 .probe = generic_probe, //重要的匹配函數(shù)
 .disconnect = usb_serial_disconnect,
 .id_table = generic_serial_ids, //無用
 .no_dynamic_id = 1, //不支持動態(tài)匹配
};
 

函數(shù) usb_serial_generic_register(int _debug)已經(jīng)整體分析完,下面分析該函數(shù)里面的usb_serial_register函數(shù)
 
為usb_serial_driver添加新的操作功能(open,write,close,....)
fixup_generic(struct usb_serial_driver* device)

將usb_serial_driver添加到usb-serial總線上的驅(qū)動列表usb_serial_driver_list上
list_add(&driver->driver_list, &usb_serial_driver_list);
注冊驅(qū)動到usb-serial總線上
usb_serial_bus_register(driver)
 
 
在usb總線上注冊了兩個驅(qū)動"usbserial"和"usbserial_generic",那么當插入設備的時候
究竟是匹配哪一個驅(qū)動呢???????????????????????

現(xiàn)在似乎usb-serial總線和usb總線沒有什么聯(lián)系,好,那么就看generic_probe函數(shù)
id_pattern = usb_match_id(interface, generic_device_ids)
初步匹配
if (id_pattern != NULL)
 return usb_serial_probe(interface, id);
繼續(xù)匹配,尋找和其匹配的驅(qū)動
 
usb中的probe函數(shù)的工作
1.初始化用于控制usb設備的局部結(jié)構(gòu)體
2.探測端點類型
3.保存相關局部結(jié)構(gòu)體的信息
4.把設備注冊到USB核心,以便與用戶程序監(jiān)護信息
 
另外一個匹配函數(shù)usn_serial_probe出場了
int usb_serial_probe(struct usb_interface *interface,const struct usb_device_id *id)
type = search_serial_device(interface);
獲取該設備匹配的驅(qū)動,"struct usb_serial_driver* type"

獲取到設備之后,為該設備創(chuàng)建一個"usb_serial"對象
serial = create_serial (dev, interface, type)
(一般的驅(qū)動程序都會為自己匹配設備創(chuàng)建一個用于描述設備的對象,在以后的所有操作中,
如讀寫等都會直接從這個對象獲取相應的信息)
iface_desc = interface->cur_altsetting  //獲取設備接口的當前設置
endpoint = &iface_desc->endpoint[i].desc
檢查當前接口的端點類型,并保存,對于usb_serial_generic設備,常見的端點類型為bulkin和bulkout
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL)
用struct usb_serial_port來描述一個tty端口,因為每個端口都有自己的工作模式
關于 struct usb_serial_port
struct usb_serial_port {
 struct usb_serial *serial;
 struct tty_struct *tty;
 spinlock_t  lock;
 struct mutex            mutex;
 unsigned char  number;
 unsigned char  *interrupt_in_buffer;
 struct urb  *interrupt_in_urb;
 __u8   interrupt_in_endpointAddress;
 unsigned char  *interrupt_out_buffer;
 int   interrupt_out_size;
 struct urb  *interrupt_out_urb;
 __u8   interrupt_out_endpointAddress;
 unsigned char  *bulk_in_buffer;
 int   bulk_in_size;
 struct urb  *read_urb;
 __u8   bulk_in_endpointAddress;
 unsigned char  *bulk_out_buffer;
 int   bulk_out_size;
 struct urb  *write_urb;
 int   write_urb_busy;
 __u8   bulk_out_endpointAddress;
 wait_queue_head_t write_wait;
 struct work_struct work;
 int   open_count;
 char   throttled;
 char   throttle_req;
 char   console;
 struct device  dev;
};
port->serial = serial
將usb_serial對象保存到usb_serial_port中,便于通過port來訪問serial

初始化bulk_in端點,保存到"usb_serial_port"(port對象中)
 for (i = 0; i < num_bulk_in; ++i) {
  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);//創(chuàng)建DMA緩沖區(qū)
  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);//在提交urb之前將其正確的初始化
}
同樣的方法初始化bulk_out端點
-----------------------------------------------------------------------------------------
初始化輸入中斷interrupt_in端點
 if (serial->type->read_int_callback) {//對于generic驅(qū)動,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");
 }
同樣的方法初始化interrupt_out端點和attach
————————————————————————————————————————————-

usbserial模塊總共支持254個設備,他為每個設備分配了一個serial_table項,
用于保存"usb_serial"對象,方便以后直接通過minor號獲取"usbserial"對象
serial->minor = minor

注冊所有獨立的ports到驅(qū)動核心
 /* 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;//驅(qū)動的總線
  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);
  retval = device_register(&port->dev);  //重要,吧設備注冊到usb核心,以便與用戶程序交互信息
  if (retval)
   dev_err(&port->dev, "Error registering port device, "
    "continuing\n");
 }
 usb_serial_console_init (debug, minor); //初始化中斷控制臺
 usb_set_intfdata (interface, serial);//把serial結(jié)構(gòu)體保存到interface接口設備中,可以調(diào)用usb_get_intfdata來獲取數(shù)據(jù)。
 
 至此,probe函數(shù)完成了4個主要工作,probe函數(shù)也走到了盡頭
--------------------------------------------------------------------------------------------

到現(xiàn)在usb_serial_bus都沒怎么用到,也沒有看到這個設備和初始化時的tty_driver
綁定,這些東西都在了probe函數(shù)最后調(diào)用的device_register中。

device_register(&port->dev);
一下分析device_driver:
int device_register(struct device *dev)
{
 device_initialize(dev);
 return device_add(dev);
}
1.device_add():把設備device注冊到相應的總線上。并創(chuàng)建device_file,最后
調(diào)用bus_attach_device()函數(shù)
->bus_attach_device調(diào)用device_attach(dev)
->bus_for_each_drv()遍歷bus上的每個driver,當找到一個就用__device_attach()
來判斷匹配
->driver_probe_device(dev,drv)首先如果所有的driver所在總線由nach函數(shù)則
先調(diào)用match來匹配,如果匹配,直接調(diào)用really_probe(dev,drv)
->really_probe。判斷總線,如果由probe函數(shù)則調(diào)用和匹配它
->drv->probe:它是一類設備的probe,在他里面會調(diào)用具體某個drv的probe函數(shù),
這個函數(shù)是在我們的驅(qū)動程序里面注冊的
 
在該device_register里,
struct bus_type usb_serial_bus_type = {
 .name =  "usb-serial",
 .match = usb_serial_device_match,
 .probe = usb_serial_device_probe,
 .remove = usb_serial_device_remove,
 .drv_attrs =  drv_attrs,
};
所以會先調(diào)用usb_serial_device_match,進行匹配

static int usb_serial_device_match (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);
 if (!port)
  return 0;
 driver = to_usb_serial_driver(drv);
 if (driver == port->serial->type)//將設備和驅(qū)動進行匹配
  return 1;
 return 0;
}

接下來調(diào)用probe函數(shù),也就是usb_serial_device_probe
static int usb_serial_device_probe (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;
 }
 driver = port->serial->type;
 if (driver->port_probe) {
  if (!try_module_get(driver->driver.owner)) {
   dev_err(dev, "module get failed, exiting\n");
   retval = -EIO;
   goto exit;
  }
  retval = driver->port_probe (port);
  module_put(driver->driver.owner);
  if (retval)
   goto exit;
 }
 retval = device_create_file(dev, &dev_attr_port_number);
 if (retval)
  goto exit;
 minor = port->number;
 tty_register_device (usb_serial_tty_driver, minor, dev);
 dev_info(&port->serial->dev->dev,
   "%s converter now attached to ttyUSB%d\n",
   driver->description, minor);
exit:
 return retval;
}

其中,調(diào)用了tty_register_device將tty_driver和device綁定,注冊該驅(qū)動控制的設備
到了這一步完成了tty和usb的注冊,同時也在/dev目錄下創(chuàng)建了相應的設備文件,也就是說應用層可以使用這個設備了。
 
 
分析玩整個注冊過程,接下來當然時分析它的讀寫過程了,讀寫過程相對來說
會感覺容易一點,因為他們沒有太多錯綜復雜的關系,各功能函數(shù)相對獨立
 
要使用設備當然要先打開這個設備了,應用層調(diào)用open系統(tǒng)調(diào)用來打開這個設備,他最終
調(diào)用到tty_driver的open函數(shù)
static const struct tty_operations serial_ops = {
 .open =   serial_open,
 .close =  serial_close,
 .write =  serial_write,
 .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函數(shù):
serial = usb_serial_get_by_index(tty->index) //將tty指針(終端)中獲取相應的usb_serial結(jié)構(gòu)體上
port = serial->port[portNumber]; //獲取設備對應的port對象
++port->port.count;記錄打開次數(shù)
tty->driver_data=port; //保存相應的port信息到該終端(tty)的私有指針里
serial->type->open(tty,port,flip);//usb_serial_generic_device.open=usb_serial_generic_open
所以,將會調(diào)用usb_serial_generic_open函數(shù)
一下分析int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp)
int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp)
{
   ..
   ..
   ..
   ..
 /* if we have a bulk endpoint, start reading from it */
 //如果有bulk_in端點,就提交這個端點的urb,即讓系統(tǒng)開始在這個端點上接收
 來自設備端發(fā)過來的數(shù)據(jù),當數(shù)據(jù)收到后會調(diào)用serial->type->read_bulk_callback函數(shù)

 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),
       port);
  result = usb_submit_urb(port->read_urb, GFP_KERNEL);//使用函數(shù)usb_submit_urb   //將urb提交到usb_core,成功后若接受到數(shù)據(jù)將會執(zhí)行      //usb_serial_generic_read_bulk_callback
  if (result)
   dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
 }
 return result;
}

分析usb_serial_generic_read_bulk_callback(struct urb *urb)

void usb_serial_generic_read_bulk_callback (struct urb *urb)
{
 struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 unsigned char *data = urb->transfer_buffer;
 int status = urb->status;
 unsigned long flags;
  ..
  ..
 usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
 /* Throttle the device if requested by tty */
 spin_lock_irqsave(&port->lock, flags);
 if (!(port->throttled = port->throttle_req)) {
  spin_unlock_irqrestore(&port->lock, flags);
  flush_and_resubmit_read_urb(port);
 } else {
  spin_unlock_irqrestore(&port->lock, flags);
 }
}
其中,調(diào)用函數(shù)flush_and_resubmit_read_urb(port)  //將數(shù)據(jù)放入tty驅(qū)動的緩沖區(qū)中
/* Push data to tty layer and resubmit the bulk read URB */
static void flush_and_resubmit_read_urb (struct usb_serial_port *port)
{
 struct urb *urb = port->read_urb;
 struct tty_struct *tty = port->tty;
 int room;
 /* Push data to tty */
 if (tty && urb->actual_length) {
  room = tty_buffer_request_room(tty, urb->actual_length);
  if (room) {
   tty_insert_flip_string(tty, urb->transfer_buffer, room);
   tty_flip_buffer_push(tty);
  }
 }
 resubmit_read_urb(port, GFP_ATOMIC);//繼續(xù)傳輸
}
最后調(diào)用的函數(shù)resubmit_read_urb(port, GFP_ATOMIC);
static void resubmit_read_urb(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 */
 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", __FUNCTION__, result);
}
在函數(shù)里又調(diào)用了usb_submit_urb函數(shù),起到遞歸的作用。
 至此,打開設備和讀設備的流程已經(jīng)寫完
 
 
最后看serial_write函數(shù),該函數(shù)對應了usb_serial_generic_write
int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *buf, int count)
{
 struct usb_serial *serial = port->serial;
   ..
   ..
   ..
 /* only do something if we have a bulk out endpoint */
 if (serial->num_bulk_out) {
  unsigned long flags;
  spin_lock_irqsave(&port->lock, flags);
  if (port->write_urb_busy) {
   spin_unlock_irqrestore(&port->lock, flags);
   dbg("%s - already writing", __FUNCTION__);
   return 0;
  }
  port->write_urb_busy = 1;
  spin_unlock_irqrestore(&port->lock, flags);
  count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
  //將數(shù)據(jù)存放進urb中
  memcpy (port->write_urb->transfer_buffer, buf, count);
  data = port->write_urb->transfer_buffer;
  usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, data);
  /* set up our urb */
  //初始化urb
  usb_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), 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);
   ..
   ..
}
當serial_write函數(shù)的urb成功提交到usb_core后,若urb被成功的傳遞到USB設備后,將會調(diào)用回調(diào)函數(shù)
usb_serial_generic_write_bulk_callback
void usb_serial_generic_write_bulk_callback (struct urb *urb)
{
 struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 int status = urb->status;
 dbg("%s - port %d", __FUNCTION__, port->number);
 port->write_urb_busy = 0;
 if (status) {
  dbg("%s - nonzero write bulk status received: %d",
      __FUNCTION__, status);
  return;
 }
 usb_serial_port_softint(port); //請求更多的傳輸
}

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多