| usb-serial分析重要文件由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); //請求更多的傳輸 } | 
|  |