一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

詳細(xì)解析Host各模塊的架構(gòu)和原理

Linux閱碼場 ? 來源:Linux閱碼場 ? 作者:Linux閱碼場 ? 2022-06-09 09:57 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

1.簡介

整個 USB 系統(tǒng)的通訊模型如上圖所示,本文詳細(xì)解析其中 Host 各模塊的架構(gòu)和原理 (圖中彩色部分)。

8021c06a-e78a-11ec-ba43-dac502259ad0.png

2. Usb Core 驅(qū)動設(shè)備模型

80683874-e78a-11ec-ba43-dac502259ad0.png

由前幾節(jié)可知USB將Device進一步細(xì)分成了3個層級:Configuration 配置、Interface 接口、Endpoint 端點。

Usb Core 為其中兩個層次提供了 Device + Driver 的設(shè)備驅(qū)動模型,這兩個層次分別是 Usb Device Layer 和 Usb Interface Layer 層,一個Usb Device包含一個或多個Usb Interface。其中:

  • Usb Device Layer層。這一層的 Device 由 Hub 創(chuàng)建,Hub 本身也是一種 Usb Device;這一層的 Driver 完成的功能非常簡單,基本就是幫 Usb Device 創(chuàng)建其包含的所有子 Usb Interface 的 Device,大部分場景下都是使用 usb_generic_driver。

  • Usb Interface Layer層。這一層的 Device 由上一級 Usb Device 在驅(qū)動 probe() 時創(chuàng)建;而這一層的 Driver 就是普通的業(yè)務(wù) Usb 驅(qū)動,即 Usb 協(xié)議中所說的 Client Software。

2.1 Usb Device Layer

2.1.1 device (struct usb_device)

Usb Device Device 對應(yīng)的數(shù)據(jù)結(jié)構(gòu)為 struct usb_device,會在兩種情況下被創(chuàng)建:

1、roothub device。在 HCD 驅(qū)動注冊時創(chuàng)建:


/* (1) 首先創(chuàng)建和初始化 `usb_device` 結(jié)構(gòu):*/usb_add_hcd() → usb_alloc_dev():struct usb_device *usb_alloc_dev(struct usb_device *parent,         struct usb_bus *bus, unsigned port1){
  /* (1.1) dev 總線初始化為 usb_bus_type */  dev->dev.bus = &usb_bus_type;  /* (1.2) dev 類型初始化為 usb_device_type,標(biāo)明自己是一個 usb device */  dev->dev.type = &usb_device_type;  dev->dev.groups = usb_device_groups;
}
/* (2) 然后注冊  `usb_device` 結(jié)構(gòu):*/usb_add_hcd()→register_root_hub()→usb_new_device()→device_add()

2、普通 usb device。在 Hub 檢測到端口有設(shè)備 attach 時創(chuàng)建:


/* (1) 首先創(chuàng)建和初始化 `usb_device` 結(jié)構(gòu):*/hub_event() → port_event() → hub_port_connect_change() → hub_port_connect() → usb_alloc_dev()
/* (2) 然后注冊  `usb_device` 結(jié)構(gòu):*/hub_event()→port_event()→hub_port_connect_change()→hub_port_connect()→usb_new_device()→device_add()

2.1.2 driver (struct usb_device_driver)

Usb Device Driver 對應(yīng)的數(shù)據(jù)結(jié)構(gòu)為 struct usb_device_driver,使用 usb_register_device_driver() 函數(shù)進行注冊:


int usb_register_device_driver(struct usb_device_driver *new_udriver,    struct module *owner){
  /* (1) 設(shè)置for_devices標(biāo)志為1,表面這個驅(qū)動時給 usb device 使用的 */  new_udriver->drvwrap.for_devices = 1;  new_udriver->drvwrap.driver.name = new_udriver->name;  new_udriver->drvwrap.driver.bus = &usb_bus_type;  new_udriver->drvwrap.driver.probe = usb_probe_device;  new_udriver->drvwrap.driver.remove = usb_unbind_device;  new_udriver->drvwrap.driver.owner = owner;  new_udriver->drvwrap.driver.dev_groups = new_udriver->dev_groups;
  retval = driver_register(&new_udriver->drvwrap.driver);
}

注冊的 Usb Device Driver 驅(qū)動非常少,一般情況下所有的 Usb Device Device 都會適配到 usb_generic_driver。因為這一層次驅(qū)動的目的很單純,就是給 Usb Device 下所有的 Interface 創(chuàng)建對應(yīng)的 Usb Interface Device。


usb_init() → usb_register_device_driver() :
static int __init usb_init(void){
  retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
}
struct usb_device_driver usb_generic_driver = {  .name =  "usb",  .match = usb_generic_driver_match,  .probe = usb_generic_driver_probe,  .disconnect = usb_generic_driver_disconnect,#ifdef  CONFIG_PM  .suspend = usb_generic_driver_suspend,  .resume = usb_generic_driver_resume,#endif  .supports_autosuspend = 1,};

驅(qū)動 probe() 過程:


usb_probe_device() → usb_generic_driver_probe() → usb_set_configuration():
int usb_set_configuration(struct usb_device *dev, int configuration){
  /* (1) 創(chuàng)建和初始化 `struct usb_interface` */  for (i = 0; i < nintf; ++i) {    /* (1.1) dev 總線初始化為 usb_bus_type */    intf->dev.bus = &usb_bus_type;    /* (1.2) dev 類型初始化為 usb_if_device_type,標(biāo)明自己是一個 usb interface */    intf->dev.type = &usb_if_device_type;    intf->dev.groups = usb_interface_groups;  }
  /* (2) 注冊 `struct usb_interface` */  for (i = 0; i < nintf; ++i) {    ret = device_add(&intf->dev);  }
}

2.1.3 bus (usb_bus_type)

可以看到 struct usb_device 和 struct usb_interface 使用的總線都是 usb_bus_type。他們是通過字段 dev.type 來區(qū)分的:


/* (1) `struct usb_device` 的 `dev.type` 值為 `usb_device_type`:*/usb_add_hcd() → usb_alloc_dev():struct usb_device *usb_alloc_dev(struct usb_device *parent,         struct usb_bus *bus, unsigned port1){  dev->dev.type = &usb_device_type;}
/* (2) `struct usb_interface` 的 `dev.type` 值為 `usb_if_device_type` */usb_probe_device() → usb_generic_driver_probe() → usb_set_configuration():int usb_set_configuration(struct usb_device *dev, int configuration){  for (i = 0; i < nintf; ++i) {    intf->dev.type = &usb_if_device_type;  }}
static inline int is_usb_device(const struct device *dev){  /* (3) 判斷當(dāng)前 Device 是否為 Usb Device */  return dev->type == &usb_device_type;}
static inline int is_usb_interface(const struct device *dev){  /* (4) 判斷當(dāng)前 Device 是否為 Usb Interface */  return dev->type == &usb_if_device_type;}

另外 struct usb_device_driver 和 struct usb_driver 使用的總線都是 usb_bus_type。他們是通過字段 drvwrap.for_devices 來區(qū)分的:


/* (1) `struct usb_device_driver` 的 `drvwrap.for_devices` 值為 1:*/int usb_register_device_driver(struct usb_device_driver *new_udriver,    struct module *owner){  new_udriver->drvwrap.for_devices = 1;}
/* (2) `struct usb_driver` 的 `drvwrap.for_devices` 值為 0:*/int usb_register_driver(struct usb_driver *new_driver, struct module *owner,      const char *mod_name){  new_driver->drvwrap.for_devices = 0;}
/* (3) 判斷當(dāng)前 Driver 是適配 Usb Device 還是 Usb Interface */static inline int is_usb_device_driver(struct device_driver *drv){  return container_of(drv, struct usbdrv_wrap, driver)->      for_devices;}

在 usb_bus_type 的 match() 函數(shù)中利用 dev.type 進行判別分開處理:


struct bus_type usb_bus_type = {  .name =    "usb",  .match =  usb_device_match,  .uevent =  usb_uevent,  .need_parent_lock =  true,};
static int usb_device_match(struct device *dev, struct device_driver *drv){  /* devices and interfaces are handled separately */  /* (1) Device 是 `Usb Device` 的處理 */   if (is_usb_device(dev)) {     struct usb_device *udev;    struct usb_device_driver *udrv;
    /* interface drivers never match devices */    /* (1.1) 只查找 `Usb Device` 的 Driver */    if (!is_usb_device_driver(drv))      return 0;
    udev = to_usb_device(dev);    udrv = to_usb_device_driver(drv);
    /* If the device driver under consideration does not have a     * id_table or a match function, then let the driver's probe     * function decide.     */    if (!udrv->id_table && !udrv->match)      return 1;
    return usb_driver_applicable(udev, udrv);
  /* (2) Device 是 `Usb Interface` 的處理 */   } else if (is_usb_interface(dev)) {    struct usb_interface *intf;    struct usb_driver *usb_drv;    const struct usb_device_id *id;
    /* device drivers never match interfaces */    /* (2.1) 只查找 `Usb Interface` 的 Driver */    if (is_usb_device_driver(drv))      return 0;
    intf = to_usb_interface(dev);    usb_drv = to_usb_driver(drv);
    id = usb_match_id(intf, usb_drv->id_table);    if (id)      return 1;
    id = usb_match_dynamic_id(intf, usb_drv);    if (id)      return 1;  }
  return 0;}

2.2 Usb Interface Layer

2.2.1 device (struct usb_interface)

如上一節(jié)描述,Usb Interface Device 對應(yīng)的數(shù)據(jù)結(jié)構(gòu)為 struct usb_interface,會在 Usb Device Driver 驅(qū)動 probe() 時 被創(chuàng)建:


usb_probe_device() → usb_generic_driver_probe() → usb_set_configuration():
int usb_set_configuration(struct usb_device *dev, int configuration){
  /* (1) 創(chuàng)建和初始化 `struct usb_interface` */  for (i = 0; i < nintf; ++i) {    /* (1.1) dev 總線初始化為 usb_bus_type */    intf->dev.bus = &usb_bus_type;    /* (1.2) dev 類型初始化為 usb_if_device_type,標(biāo)明自己是一個 usb interface */    intf->dev.type = &usb_if_device_type;    intf->dev.groups = usb_interface_groups;  }
  /* (2) 注冊 `struct usb_interface` */  for (i = 0; i < nintf; ++i) {    ret = device_add(&intf->dev);  }
}

2.2.2 driver (struct usb_driver)

Usb Interface 這一層次的驅(qū)動就非常的多了,這一層主要是在 USB 傳輸層之上,針對 USB Device 的某個功能 Function 開發(fā)對應(yīng)的 USB 功能業(yè)務(wù)驅(qū)動,即常說的 USB Client Software。在 USB 定義中,一個 Interface 就是一個 Function。

Usb Interface Driver 對應(yīng)的數(shù)據(jù)結(jié)構(gòu)為 struct usb_driver,使用 usb_register_driver() 函數(shù)進行注冊:


int usb_register_driver(struct usb_driver *new_driver, struct module *owner,      const char *mod_name){
  /* (1) 設(shè)置for_devices標(biāo)志為0,表面這個驅(qū)動時給 usb interface 使用的 */  new_driver->drvwrap.for_devices = 0;  new_driver->drvwrap.driver.name = new_driver->name;  new_driver->drvwrap.driver.bus = &usb_bus_type;  new_driver->drvwrap.driver.probe = usb_probe_interface;  new_driver->drvwrap.driver.remove = usb_unbind_interface;  new_driver->drvwrap.driver.owner = owner;  new_driver->drvwrap.driver.mod_name = mod_name;  new_driver->drvwrap.driver.dev_groups = new_driver->dev_groups;  spin_lock_init(&new_driver->dynids.lock);  INIT_LIST_HEAD(&new_driver->dynids.list);
  retval = driver_register(&new_driver->drvwrap.driver);
}

一個最簡單的 Usb Interface Driver 是 usb_mouse_driver:


static const struct usb_device_id usb_mouse_id_table[] = {  { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,    USB_INTERFACE_PROTOCOL_MOUSE) },  { }  /* Terminating entry */};MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
static struct usb_driver usb_mouse_driver = {  .name    = "usbmouse",  .probe    = usb_mouse_probe,  .disconnect  = usb_mouse_disconnect,  .id_table  = usb_mouse_id_table,};
module_usb_driver(usb_mouse_driver);

在后面的章節(jié)中會進一步詳細(xì)分析這個驅(qū)動的實現(xiàn)。

2.2.3 bus (usb_bus_type)

Usb Interface 這一層次總線也是 usb_bus_type,上一節(jié)已經(jīng)分析,這里就不重復(fù)解析了。

3. USB Request Block

80a4dcfc-e78a-11ec-ba43-dac502259ad0.png

Usb Core 除了提供上一節(jié)描述的設(shè)備驅(qū)動模型以外,另一個重要的作用就是要給 Usb Interface Driver 提供讀寫 USB 數(shù)據(jù)的 API,這一任務(wù)是圍繞著 USB Request Block 來完成的。

Usb Interface Driver 適配成功以后,會從配置信息中獲取到當(dāng)前 Interface 包含了多少個 Endpoint,以及每個 Endpoint 的地址、傳輸類型、最大包長等其他信息。Endpoint 是 USB 總線傳輸中最小的尋址單位,Interface Driver 利用對幾個 Endpoint 的讀寫來驅(qū)動具體的設(shè)備功能。

3.1 urb

對某個 Endpoint 發(fā)起一次讀寫操作,具體工作使用 struct urb 數(shù)據(jù)結(jié)構(gòu)來承擔(dān)。

以下是一個對 Endpoint 0 使用 urb 發(fā)起讀寫的一個簡單實例:


static int usb_internal_control_msg(struct usb_device *usb_dev,            unsigned int pipe,            struct usb_ctrlrequest *cmd,            void *data, int len, int timeout){  struct urb *urb;  int retv;  int length;
  /* (1) 分配一個 urb 內(nèi)存空間 */  urb = usb_alloc_urb(0, GFP_NOIO);  if (!urb)    return -ENOMEM;
  /* (2) 填充 urb 內(nèi)容,最核心的有3方面:      1、總線地址:Device Num + Endpoint Num      2、數(shù)據(jù):data + len      3、回調(diào)函數(shù):usb_api_blocking_completion   */  usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,           len, usb_api_blocking_completion, NULL);
  /* (3) 發(fā)送 urb 請求,并且等待請求完成 */  retv = usb_start_wait_urb(urb, timeout, &length);  if (retv < 0)    return retv;  else    return length;}

static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length){  struct api_context ctx;  unsigned long expire;  int retval;
  init_completion(&ctx.done);  urb->context = &ctx;  urb->actual_length = 0;  /* (3.1) 把 urb 請求掛載到 hcd 的隊列當(dāng)中 */  retval = usb_submit_urb(urb, GFP_NOIO);  if (unlikely(retval))    goto out;
  expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;  /* (3.2) 當(dāng) urb 執(zhí)行完成后,首先會調(diào)用 urb 的回調(diào)函數(shù),然后會發(fā)送 completion 信號解除這里的阻塞 */  if (!wait_for_completion_timeout(&ctx.done, expire)) {    usb_kill_urb(urb);    retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
    dev_dbg(&urb->dev->dev,      "%s timed out on ep%d%s len=%u/%u
",      current->comm,      usb_endpoint_num(&urb->ep->desc),      usb_urb_dir_in(urb) ? "in" : "out",      urb->actual_length,      urb->transfer_buffer_length);  } else    retval = ctx.status;out:  if (actual_length)    *actual_length = urb->actual_length;
  usb_free_urb(urb);  return retval;}

3.2 normal device urb_enqueue

對普通的 Usb device 來說,urb 最后會提交到 Host Controller 的收發(fā)隊列上面,由 HC 完成實際的 USB 傳輸:


usb_submit_urb() → usb_hcd_submit_urb():
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags){
  /* (1) 如果是 roothub 走特殊的路徑 */  if (is_root_hub(urb->dev)) {    status = rh_urb_enqueue(hcd, urb);  /* (2) 如果是普通 device 調(diào)用對應(yīng)的 hcd 的 urb_enqueue() 函數(shù) */  } else {    status = map_urb_for_dma(hcd, urb, mem_flags);    if (likely(status == 0)) {      status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);      if (unlikely(status))        unmap_urb_for_dma(hcd, urb);    }  }
}

3.3 roothub device urb_enqueue

特別需要注意的是 roothub 它是一個虛擬的 usb device,實際上它并不在usb總線上而是在 host 內(nèi)部,所以相應(yīng)的 urb 需要特殊處理,而不能使用 hcd 把數(shù)據(jù)發(fā)送到 Usb 總線上去。


usb_submit_urb() → usb_hcd_submit_urb() → rh_urb_enqueue():
static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb){  /* (1) 對于 int 類型的數(shù)據(jù),被掛載到 hcd->status_urb 指針上面      通常 roothub 驅(qū)動用這個 urb 來查詢 roothub 的端口狀態(tài)   */  if (usb_endpoint_xfer_int(&urb->ep->desc))    return rh_queue_status (hcd, urb);
  /* (2) 對于 control 類型的數(shù)據(jù),是想讀取 roothub ep0 上的配置信息      使用軟件來模擬這類操作的響應(yīng)   */  if (usb_endpoint_xfer_control(&urb->ep->desc))    return rh_call_control (hcd, urb);  return -EINVAL;}
|→
static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb){
  /* (1.1) 將 urb 掛載到對應(yīng)的 ep 鏈表中 */  retval = usb_hcd_link_urb_to_ep(hcd, urb);  if (retval)    goto done;
  /* (1.2) 將 urb 賦值給 hcd->status_urb      在 hcd 驅(qū)動中,會通過這些接口來通知 roothub 的端口狀態(tài)變化   */  hcd->status_urb = urb;  urb->hcpriv = hcd;  /* indicate it's queued */  if (!hcd->uses_new_polling)    mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
}
|→
static int rh_call_control (struct usb_hcd *hcd, struct urb *urb){  /* (2.1) 軟件模擬對 roothub 配置讀寫的響應(yīng) */}

4. Usb Hub Driver

8107fcec-e78a-11ec-ba43-dac502259ad0.png

普通的 Usb Device 通過內(nèi)部的 Interface 提供各種業(yè)務(wù)功能。而 Hub 這類特殊的 Usb Device 功能就一種,那就是監(jiān)控端口的狀態(tài)變化:

  • 在端口上有設(shè)備 attach 時,創(chuàng)建新的 usb device,給其適配驅(qū)動。如果是 hub device,子 usb 驅(qū)動會進一步掃描端口。

  • 在端口上有設(shè)備 deattach 時,移除掉對應(yīng)的 usb device。如果是 hub device 進一步移除其所有的子 usb device。

Hub 也是標(biāo)準(zhǔn)的 Usb Device,它也是標(biāo)準(zhǔn)的流程被上一級設(shè)備發(fā)現(xiàn)后創(chuàng)建 Usb Device → 創(chuàng)建 Usb Interface,然后被 Usb Hub Interface Driver 給適配到。系統(tǒng)中只有一個 Hub 驅(qū)動:


static const struct usb_device_id hub_id_table[] = {    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR                   | USB_DEVICE_ID_MATCH_PRODUCT                   | USB_DEVICE_ID_MATCH_INT_CLASS,      .idVendor = USB_VENDOR_SMSC,      .idProduct = USB_PRODUCT_USB5534B,      .bInterfaceClass = USB_CLASS_HUB,      .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR      | USB_DEVICE_ID_MATCH_INT_CLASS,      .idVendor = USB_VENDOR_GENESYS_LOGIC,      .bInterfaceClass = USB_CLASS_HUB,      .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},    { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,      .bDeviceClass = USB_CLASS_HUB},    { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,      .bInterfaceClass = USB_CLASS_HUB},    { }            /* Terminating entry */};
MODULE_DEVICE_TABLE(usb, hub_id_table);
static struct usb_driver hub_driver = {  .name =    "hub",  .probe =  hub_probe,  .disconnect =  hub_disconnect,  .suspend =  hub_suspend,  .resume =  hub_resume,  .reset_resume =  hub_reset_resume,  .pre_reset =  hub_pre_reset,  .post_reset =  hub_post_reset,  .unlocked_ioctl = hub_ioctl,  .id_table =  hub_id_table,  .supports_autosuspend =  1,};

hub_driver 驅(qū)動啟動以后,只做一件事情發(fā)送一個查詢端口狀態(tài)的 urb :


hub_probe() → hub_configure():
static int hub_configure(struct usb_hub *hub,  struct usb_endpoint_descriptor *endpoint){
  /* (1) 分配 urb */  hub->urb = usb_alloc_urb(0, GFP_KERNEL);  if (!hub->urb) {    ret = -ENOMEM;    goto fail;  }
  /* (2) 初始化 urb,作用就是通過 ep0 查詢 hub 的端口狀態(tài)      urb 的回調(diào)函數(shù)是 hub_irq()   */  usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,    hub, endpoint->bInterval);
  /* (3) 發(fā)送 urb */  hub_activate(hub, HUB_INIT);
}

static void hub_activate(struct usb_hub *hub, enum hub_activation_type type){  /*  (3.1) 提交 urb */  status = usb_submit_urb(hub->urb, GFP_NOIO);}

4.1 normal hub port op

在普通的 hub 中,端口操作是通過標(biāo)準(zhǔn)的 urb 發(fā)起 usb ep0 讀寫。分為兩類:

  • 1、通過輪詢讀取 Hub Class-specific Requests 配置來查詢端口的狀態(tài):

812cf65a-e78a-11ec-ba43-dac502259ad0.png

  • 2、設(shè)置和使能端口也是通過 Hub Class-specific Requests 中相應(yīng)的命令實現(xiàn)的:

81a1b80a-e78a-11ec-ba43-dac502259ad0.png

4.2 rootHub port op

而對于 roothub 來說,對端口的操作的 urb 都需要特殊處理 (以 EHCI 的驅(qū)動為例):

  • 1、端口狀態(tài)的變化可以通過 HCD 觸發(fā)中斷再上報:


ehci_irq() → usb_hcd_poll_rh_status() :
void usb_hcd_poll_rh_status(struct usb_hcd *hcd){
  /* (1) 獲取端口狀態(tài)的變化 */  length = hcd->driver->hub_status_data(hcd, buffer);  if (length > 0) {
    /* try to complete the status urb */    spin_lock_irqsave(&hcd_root_hub_lock, flags);
    /* (2) 通過回復(fù) hcd->status_urb 來進行上報 */    urb = hcd->status_urb;    if (urb) {      clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);      hcd->status_urb = NULL;      urb->actual_length = length;      memcpy(urb->transfer_buffer, buffer, length);
      usb_hcd_unlink_urb_from_ep(hcd, urb);      usb_hcd_giveback_urb(hcd, urb, 0);    } else {      length = 0;      set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);    }    spin_unlock_irqrestore(&hcd_root_hub_lock, flags);  }
}

hcd->driver->hub_status_data() → ehci_hub_status_data():
static intehci_hub_status_data (struct usb_hcd *hcd, char *buf){  /* (1.1) 通過 HCD 驅(qū)動,獲取 roothub 端口的狀態(tài) */}

  • 2、設(shè)置和使能端口需要嫁接到 HCD 驅(qū)動相關(guān)函數(shù)上實現(xiàn):


usb_hcd_submit_urb() → rh_urb_enqueue() → rh_call_control() → hcd->driver->hub_control() → ehci_hub_control():
int ehci_hub_control(  struct usb_hcd  *hcd,  u16    typeReq,  u16    wValue,  u16    wIndex,  char    *buf,  u16    wLength) {  /* (1) 通過 HCD 驅(qū)動,設(shè)置 roothub 的端口 */}

4.3 device attach


hub_event() → port_event() → hub_port_connect_change() → hub_port_connect():
static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,    u16 portchange){
  for (i = 0; i < PORT_INIT_TRIES; i++) {
    /* (1) 給端口上新 Device 分配 `struct usb_device` 數(shù)據(jù)結(jié)構(gòu) */    udev = usb_alloc_dev(hdev, hdev->bus, port1);    if (!udev) {      dev_err(&port_dev->dev,          "couldn't allocate usb_device
");      goto done;    }
    /* (2) 給新的 Device 分配一個新的 Address */    choose_devnum(udev);    if (udev->devnum <= 0) {      status = -ENOTCONN;  /* Don't retry */      goto loop;    }
    /* reset (non-USB 3.0 devices) and get descriptor */    usb_lock_port(port_dev);    /* (3) 使能端口,并且調(diào)用 hub_set_address() 給 Device 配置上新分配的 Address */    status = hub_port_init(hub, udev, port1, i);    usb_unlock_port(port_dev);      /* (4) 注冊 `struct usb_device` */      status = usb_new_device(udev);
  }
}

4.4 device deattach


hub_event() → port_event() → hub_port_connect_change() → hub_port_connect():
static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,    u16 portchange){
  /* (1) 移除端口上的 `struct usb_device` */  if (udev) {    if (hcd->usb_phy && !hdev->parent)      usb_phy_notify_disconnect(hcd->usb_phy, udev->speed);    usb_disconnect(&port_dev->child);  }
}

5. Usb Host Controller Driver

Usb Host Controller 是主機側(cè)的硬件實現(xiàn),主要分為以下種類:

  • Usb1.0 有兩種控制器標(biāo)準(zhǔn):OHCI 康柏的開放主機控制器接口,UHCI Intel的通用主機控制器接口。它們的主要區(qū)別是UHCI更加依賴軟件驅(qū)動,因此對CPU要求更高,但是自身的硬件會更廉價。

  • Usb2.0 只有一種控制器標(biāo)準(zhǔn):EHCI。因為 EHCI 只支持高速傳輸,所以EHCI控制器包括四個虛擬的全速或者慢速控制器。EHCI主要用于usb 2.0,老的Usb1.1用OHCI和UHCI。EHCI為了兼容Usb1.1,將老的OHCI和UHCI合并到EHCI規(guī)范里。

  • Usb3.0 控制器標(biāo)準(zhǔn):XHCI。XHCI是Intel最新開發(fā)的主機控制器接口,廣泛用戶Intel六代Skylake處理器對應(yīng)的100系列主板上,支持USB3.0接口,往下也兼容USB2.0。XHCI英文全稱eXtensible Host Controller Interface,是一種可擴展的主機控制器接口,是Intel開發(fā)的USB主機控制器。Intel 系列芯片的USB協(xié)議采用的就是XHCI主控,主要面向USB 3.0標(biāo)準(zhǔn)的,同時也兼容2.0以下的設(shè)備。

我們以應(yīng)用最廣泛的 EHCI 為例,分析其軟硬件實現(xiàn)的架構(gòu)。

5.1 ehci hardware

5.1.1 compatible usb1.0

對 EHCI 來說,它向下兼容的方案是非常有特點的。因為 EHCI 只支持 Usb2.0 高速傳輸,為了向下兼容 Usb1.1,它直接在內(nèi)部集成最多4個全速或者慢速控制器 OHCI。在 EHCI 協(xié)議內(nèi)稱這種伴生的 OHCI 控制器為 companion host controllers。

81dcb81a-e78a-11ec-ba43-dac502259ad0.png

由 EHCI 驅(qū)動根據(jù)端口速率情況來決定由誰來處理:

  • 每個端口有一個 Owner 屬性,用來決定是 EHCI 管理還是 OHCI 管理。就是一個 Switch 開關(guān),決定 USB 數(shù)據(jù)切到哪邊處理。

  • 初始狀態(tài)時端口默認(rèn)屬于 OHCI 管理。所以對于硬件上從 OHCI 升級到 EHCI,而軟件上只有 OHCI 驅(qū)動而沒有 EHCI 驅(qū)動的系統(tǒng)來說是透明的,它繼續(xù)把 EHCI 當(dāng)成 OHCI 硬件來使用就行了,保持完美的向前兼容。

  • 如果系統(tǒng)軟件上啟用了 EHCI 驅(qū)動,它首先會把所有端口的Owner配置成 EHCI 管理。如果 EHCI 驅(qū)動發(fā)現(xiàn)端口連接且速率是全速或者慢速,則把端口的Owner配置成 OHCI 管理。

對于 EHCI 這種包含兩種控制器的兼容方式,軟件上需要同時啟動 EHCI Driver 和 OHCI Driver,才能完整的兼容 Usb1.0 和 Usb2.0:

821dcaf8-e78a-11ec-ba43-dac502259ad0.png

5.1.2 Periodic Schedule

82557ac0-e78a-11ec-ba43-dac502259ad0.png

EHCI 把數(shù)據(jù)傳輸分成了兩類來進行調(diào)度:

  • Periodic Schedule。用來傳輸對時間延遲要求高的 Endpoint 數(shù)據(jù),包括 Isochronous Transfer 和 Interrupt Transfer。

  • Asynchronous Schedule。用來傳輸對時間延遲要求不高的 Endpoint 數(shù)據(jù),包括 Control Transfer 和 Bulk Transfer。

828cfafe-e78a-11ec-ba43-dac502259ad0.png

Periodic Schedule 內(nèi)部實現(xiàn)如上圖所示,核心是兩級鏈表:

  • 1、第一級鏈表如上圖綠色所示。是各種傳輸結(jié)構(gòu)的實際描述符,主要包含以下幾種類型的描述符:

82ee8e22-e78a-11ec-ba43-dac502259ad0.png

  • 2、第二級鏈表如上圖橙色所示。是一個指針數(shù)組,數(shù)組中保存的是指向第一級鏈表的指針。這里每個數(shù)組成員代表一個時間分片 Frame/Micro-Frame 的起始位置,每個時間片會根據(jù)指針傳輸?shù)谝患夋湵碇械臄?shù)據(jù),直到第一級鏈表的結(jié)尾。指針的格式如下:

8326e3bc-e78a-11ec-ba43-dac502259ad0.png

這里的調(diào)度思想就是:第一級鏈表是一個傳輸數(shù)據(jù)全集,第二級鏈表決定了某個時間片里要傳輸?shù)臄?shù)據(jù)。這樣合理的安排二級鏈表的指針,比如間隔8次指向同一位置這部分?jǐn)?shù)據(jù)的interval就是8,間隔4次指向同一位置這部分?jǐn)?shù)據(jù)的interval就是4。 第一級鏈表也是要根據(jù)interval排序的。

Periodic Schedule 中幾個核心的描述符如下:

1、Isochronous (High-Speed) Transfer Descriptor (iTD)

8396da32-e78a-11ec-ba43-dac502259ad0.png

2、Queue Head

83da8c32-e78a-11ec-ba43-dac502259ad0.png

2.1、Queue Element Transfer Descriptor (qTD)

8421ea8c-e78a-11ec-ba43-dac502259ad0.png

5.1.3 Asynchronous Schedule

8457648c-e78a-11ec-ba43-dac502259ad0.png

Asynchronous Schedule 內(nèi)部實現(xiàn)非常的簡單就只有一級鏈表,鏈表中只有Queue Head類型的描述符。每個時間片內(nèi)傳輸完 Period 數(shù)據(jù)以后,再盡可能的傳輸 Asynchronous 數(shù)據(jù)即可。

5.2 ehci driver

ehci driver 負(fù)責(zé)把 echi 功能封裝成標(biāo)準(zhǔn)的 hcd 驅(qū)動。它主要完成兩項工作:

  • 1、注冊標(biāo)準(zhǔn)的 hcd 驅(qū)動。把 Client Software 傳說下來的 urb 映射到 EHCI 的鏈表中進行傳輸。

  • 2、創(chuàng)建一個虛擬的根 hub 設(shè)備,即 roothub。

5.2.1 urb transfer

ehci 注冊 hcd 驅(qū)動:


static int ehci_platform_probe(struct platform_device *dev){
  /* (1) 分配 hcd,并且把 hcd->driver 初始化成 ehci_hc_driver */  ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides);  hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,           dev_name(&dev->dev));
  /* (2) 注冊標(biāo)準(zhǔn)的 hcd 驅(qū)動 */  err = usb_add_hcd(hcd, irq, IRQF_SHARED);}

hcd 驅(qū)動向上提供了標(biāo)準(zhǔn)接口,最終的實現(xiàn)會調(diào)用到 ehci_hc_driver 當(dāng)中。


static const struct hc_driver ehci_hc_driver = {  .description =    hcd_name,  .product_desc =    "EHCI Host Controller",  .hcd_priv_size =  sizeof(struct ehci_hcd),
  /*   * generic hardware linkage   */  .irq =      ehci_irq,  .flags =    HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
  /*   * basic lifecycle operations   */  .reset =    ehci_setup,  .start =    ehci_run,  .stop =      ehci_stop,  .shutdown =    ehci_shutdown,
  /*   * managing i/o requests and associated device resources   */  .urb_enqueue =    ehci_urb_enqueue,  .urb_dequeue =    ehci_urb_dequeue,  .endpoint_disable =  ehci_endpoint_disable,  .endpoint_reset =  ehci_endpoint_reset,  .clear_tt_buffer_complete =  ehci_clear_tt_buffer_complete,
  /*   * scheduling support   */  .get_frame_number =  ehci_get_frame,
  /*   * root hub support   */  .hub_status_data =  ehci_hub_status_data,  .hub_control =    ehci_hub_control,  .bus_suspend =    ehci_bus_suspend,  .bus_resume =    ehci_bus_resume,  .relinquish_port =  ehci_relinquish_port,  .port_handed_over =  ehci_port_handed_over,  .get_resuming_ports =  ehci_get_resuming_ports,
  /*   * device support   */  .free_dev =    ehci_remove_device,};

在 urb transfer 過程中,最核心的是調(diào)用上述的 ehci_urb_enqueue() 和 ehci_urb_dequeue() 函數(shù)。

5.2.2 roothub

首先創(chuàng)建虛擬的 roothub:


/* (1) 首先創(chuàng)建和初始化 `usb_device` 結(jié)構(gòu): */ehci_platform_probe() → usb_add_hcd() → usb_alloc_dev():struct usb_device *usb_alloc_dev(struct usb_device *parent,         struct usb_bus *bus, unsigned port1){
  /* (1.1) dev 總線初始化為 usb_bus_type */  dev->dev.bus = &usb_bus_type;  /* (1.2) dev 類型初始化為 usb_device_type,標(biāo)明自己是一個 usb device */  dev->dev.type = &usb_device_type;  dev->dev.groups = usb_device_groups;
}
/* (2) 然后注冊  `usb_device` 結(jié)構(gòu): */usb_add_hcd()→register_root_hub()→usb_new_device()→device_add()

然后因為 roothub 并不是在 Usb 物理總線上,所以對它的查詢和配置需要特殊處理。詳見Usb Hub Driver這一節(jié)。

6. Usb Client Software

這里再詳細(xì)分析一下典型的 Usb Client Software 即 usb mouse 驅(qū)動,看看它是怎么利用 urb 讀取 usb 設(shè)備數(shù)據(jù)的。


static const struct usb_device_id usb_mouse_id_table[] = {  /* (1) 驅(qū)動可以適配的 interface 列表 */  { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,    USB_INTERFACE_PROTOCOL_MOUSE) },  { }  /* Terminating entry */};
MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
static struct usb_driver usb_mouse_driver = {  .name    = "usbmouse",  .probe    = usb_mouse_probe,  .disconnect  = usb_mouse_disconnect,  .id_table  = usb_mouse_id_table,};
module_usb_driver(usb_mouse_driver);

1、首先根據(jù)得到的 endpoint 準(zhǔn)備好 urb,創(chuàng)建好 input 設(shè)備:


static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id){  struct usb_device *dev = interface_to_usbdev(intf);  struct usb_host_interface *interface;  struct usb_endpoint_descriptor *endpoint;  struct usb_mouse *mouse;  struct input_dev *input_dev;  int pipe, maxp;  int error = -ENOMEM;
  interface = intf->cur_altsetting;
  if (interface->desc.bNumEndpoints != 1)    return -ENODEV;
  /* (1) 得到當(dāng)前 interface 中的第一個 endpoint,mouse設(shè)備只需一個 endpoint */  endpoint = &interface->endpoint[0].desc;  if (!usb_endpoint_is_int_in(endpoint))    return -ENODEV;
  pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);  maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
  mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);  /* (2.1) 分配 input device */  input_dev = input_allocate_device();  if (!mouse || !input_dev)    goto fail1;
  mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);  if (!mouse->data)    goto fail1;
  /* (3.1) 分配 urb */  mouse->irq = usb_alloc_urb(0, GFP_KERNEL);  if (!mouse->irq)    goto fail2;
  mouse->usbdev = dev;  mouse->dev = input_dev;
  if (dev->manufacturer)    strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));
  if (dev->product) {    if (dev->manufacturer)      strlcat(mouse->name, " ", sizeof(mouse->name));    strlcat(mouse->name, dev->product, sizeof(mouse->name));  }
  if (!strlen(mouse->name))    snprintf(mouse->name, sizeof(mouse->name),       "USB HIDBP Mouse %04x:%04x",       le16_to_cpu(dev->descriptor.idVendor),       le16_to_cpu(dev->descriptor.idProduct));
  usb_make_path(dev, mouse->phys, sizeof(mouse->phys));  strlcat(mouse->phys, "/input0", sizeof(mouse->phys));
  /* (2.2) 初始化 input device */  input_dev->name = mouse->name;  input_dev->phys = mouse->phys;  usb_to_input_id(dev, &input_dev->id);  input_dev->dev.parent = &intf->dev;
  input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);  input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |    BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);  input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);  input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |    BIT_MASK(BTN_EXTRA);  input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);
  input_set_drvdata(input_dev, mouse);
  input_dev->open = usb_mouse_open;  input_dev->close = usb_mouse_close;
  /* (3.2) 初始化 urb */  usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,       (maxp > 8 ? 8 : maxp),       usb_mouse_irq, mouse, endpoint->bInterval);  mouse->irq->transfer_dma = mouse->data_dma;  mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
  /* (2.3) 注冊 input device */  error = input_register_device(mouse->dev);  if (error)    goto fail3;
  usb_set_intfdata(intf, mouse);  return 0;
fail3:    usb_free_urb(mouse->irq);fail2:    usb_free_coherent(dev, 8, mouse->data, mouse->data_dma);fail1:    input_free_device(input_dev);  kfree(mouse);  return error;}

2、在 input device 被 open 時提交 urb 啟動傳輸:


static int usb_mouse_open(struct input_dev *dev){  struct usb_mouse *mouse = input_get_drvdata(dev);
  mouse->irq->dev = mouse->usbdev;  /* (1) 提交初始化好的 usb,開始查詢數(shù)據(jù) */  if (usb_submit_urb(mouse->irq, GFP_KERNEL))    return -EIO;
  return 0;}

3、在傳輸完 urb 的回調(diào)函數(shù)中,根據(jù)讀回的數(shù)據(jù)上報 input 事件,并且重新提交 urb 繼續(xù)查詢:


static void usb_mouse_irq(struct urb *urb){  struct usb_mouse *mouse = urb->context;  signed char *data = mouse->data;  struct input_dev *dev = mouse->dev;  int status;
  switch (urb->status) {  case 0:      /* success */    break;  case -ECONNRESET:  /* unlink */  case -ENOENT:  case -ESHUTDOWN:    return;  /* -EPIPE:  should clear the halt */  default:    /* error */    goto resubmit;  }
  /* (1) 根據(jù) urb 讀回的數(shù)據(jù),上報 input event */  input_report_key(dev, BTN_LEFT,   data[0] & 0x01);  input_report_key(dev, BTN_RIGHT,  data[0] & 0x02);  input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);  input_report_key(dev, BTN_SIDE,   data[0] & 0x08);  input_report_key(dev, BTN_EXTRA,  data[0] & 0x10);
  input_report_rel(dev, REL_X,     data[1]);  input_report_rel(dev, REL_Y,     data[2]);  input_report_rel(dev, REL_WHEEL, data[3]);
  input_sync(dev);resubmit:  /* (2) 重新提交 urb 繼續(xù)查詢 */  status = usb_submit_urb (urb, GFP_ATOMIC);  if (status)    dev_err(&mouse->usbdev->dev,      "can't resubmit intr, %s-%s/input0, status %d
",      mouse->usbdev->bus->bus_name,      mouse->usbdev->devpath, status);}

參考資料

1.Enhanced Host Controller Interface Specification

2.USB 2.0 Specification

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • usb
    usb
    +關(guān)注

    關(guān)注

    60

    文章

    8190

    瀏覽量

    272916
  • Host
    +關(guān)注

    關(guān)注

    0

    文章

    32

    瀏覽量

    35111

原文標(biāo)題:Linux usb Host 詳解

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    涂鴉WiFi模塊原理圖加PCB封裝

    涂鴉WiFi模塊原理圖加PCB封裝
    發(fā)表于 06-04 16:36 ?89次下載

    GPU架構(gòu)深度解析

    GPU架構(gòu)深度解析從圖形處理到通用計算的進化之路圖形處理單元(GPU),作為現(xiàn)代計算機中不可或缺的一部分,已經(jīng)從最初的圖形渲染專用處理器,發(fā)展成為強大的并行計算引擎,廣泛應(yīng)用于人工智能、科學(xué)計算
    的頭像 發(fā)表于 05-30 10:36 ?384次閱讀
    GPU<b class='flag-5'>架構(gòu)</b>深度<b class='flag-5'>解析</b>

    NVMe控制器之完成信息解析模塊

    完成信息解析模塊用于解析NVMe命令執(zhí)行完成后返回的信息。該模塊首先提取完成信息中的Status Field字段和ID號。通過檢查Status Field字段,判斷NVMe命令是否成功
    的頭像 發(fā)表于 05-03 15:58 ?197次閱讀

    解鎖未來汽車電子技術(shù):軟件定義車輛與區(qū)域架構(gòu)深度解析

    ?? 顛覆傳統(tǒng)架構(gòu),定義行業(yè)未來 深度解析軟件定義車輛(SDV)如何通過集中式軟件管理,實現(xiàn)硬件與軟件解耦,徹底解決傳統(tǒng)域架構(gòu)的碎片化難題。 揭秘區(qū)域控制架構(gòu)如何降低30%開發(fā)成本,支
    的頭像 發(fā)表于 04-27 11:58 ?582次閱讀

    NVIDIA Blackwell數(shù)據(jù)手冊與NVIDIA Blackwell架構(gòu)技術(shù)解析

    NVIDIA Blackwell數(shù)據(jù)手冊與NVIDIA Blackwell 架構(gòu)技術(shù)解析
    的頭像 發(fā)表于 03-20 17:19 ?736次閱讀

    博世GTM IP模塊架構(gòu)介紹

    上篇文章我們介紹了博世GTM IP模塊的核心功能及基礎(chǔ)結(jié)構(gòu)模塊。本篇文章將繼續(xù)解析GTM模塊架構(gòu),重點介紹I/O
    的頭像 發(fā)表于 03-07 17:50 ?1015次閱讀
    博世GTM IP<b class='flag-5'>模塊</b><b class='flag-5'>架構(gòu)</b>介紹

    博世GTM IP模塊的核心功能及架構(gòu)解析

    能夠大幅提升系統(tǒng)性能和響應(yīng)速度,是智能控制系統(tǒng)中的關(guān)鍵組件。本文將為您介紹博世GTM模塊的核心功能及架構(gòu)。
    的頭像 發(fā)表于 02-27 14:15 ?1062次閱讀
    博世GTM IP<b class='flag-5'>模塊</b>的核心功能及<b class='flag-5'>架構(gòu)</b><b class='flag-5'>解析</b>

    電鴻系統(tǒng)技術(shù)架構(gòu)解析,觸覺智能推出多款電鴻適配硬件方案

    電鴻系統(tǒng)技術(shù)架構(gòu)解析,觸覺智能推出多款電鴻適配硬件方案
    的頭像 發(fā)表于 02-26 16:21 ?875次閱讀
    電鴻系統(tǒng)技術(shù)<b class='flag-5'>架構(gòu)</b><b class='flag-5'>解析</b>,觸覺智能推出多款電鴻適配硬件方案

    奶泡棒專用芯片詳細(xì)解析

    奶泡棒專用芯片詳細(xì)解析
    的頭像 發(fā)表于 02-24 11:23 ?349次閱讀

    國外物理服務(wù)器詳細(xì)解析

    國外物理服務(wù)器是指位于國外數(shù)據(jù)中心的物理設(shè)備,用于提供互聯(lián)網(wǎng)服務(wù)。以下是對國外物理服務(wù)器的詳細(xì)解析,主機推薦小編為您整理發(fā)布國外物理服務(wù)器詳細(xì)解析。
    的頭像 發(fā)表于 02-07 09:36 ?406次閱讀

    硅谷云平臺詳細(xì)解析

     硅谷云平臺作為硅谷地區(qū)領(lǐng)先的云計算服務(wù)提供商,在數(shù)字化時代發(fā)揮著舉足輕重的作用。主機推薦小編為您整理發(fā)布硅谷云平臺的詳細(xì)解析。
    的頭像 發(fā)表于 01-24 09:24 ?391次閱讀

    SiC模塊封裝技術(shù)解析

    昨天比較詳細(xì)的描寫了半導(dǎo)體材料中襯板和基板的選擇,里面提到了功率器件在新能源汽車中的應(yīng)用,那么功率器件的襯板和基板的選擇也是在半導(dǎo)體的工藝中比較重要的部分,而對于模塊來說,梵易之前對IGBT模塊有比
    的頭像 發(fā)表于 01-02 10:20 ?1039次閱讀
    SiC<b class='flag-5'>模塊</b>封裝技術(shù)<b class='flag-5'>解析</b>

    AUTOSAR通信協(xié)議解析 如何實現(xiàn)AUTOSAR通信

    AUTOSAR(Automotive Open System Architecture)即汽車開放系統(tǒng)架構(gòu),該架構(gòu)支持汽車電子控制單元(ECU)之間的通信,實現(xiàn)了高度模塊化和可重用性。AUTOSAR
    的頭像 發(fā)表于 12-17 14:54 ?2834次閱讀

    GPU云服務(wù)器架構(gòu)解析及應(yīng)用優(yōu)勢

    GPU云服務(wù)器作為一種高性能計算資源,近年來在人工智能、大數(shù)據(jù)分析、圖形渲染等領(lǐng)域得到了廣泛應(yīng)用。它結(jié)合了云計算的靈活性與GPU的強大計算能力,為企業(yè)和個人用戶提供了一種高效、便捷的計算解決方案。下面我們將從架構(gòu)解析和技術(shù)優(yōu)勢兩個方面來
    的頭像 發(fā)表于 08-14 09:43 ?884次閱讀

    SSD架構(gòu)與功能模塊詳解

    在之前的系列文章中,我們介紹了固態(tài)硬盤的系列知識,包括閃存的介質(zhì)、原理,以及作為SSD大腦的控制器設(shè)計,本文將詳細(xì)介紹SSD架構(gòu)以及功能模塊。
    的頭像 發(fā)表于 07-27 10:30 ?2254次閱讀
    SSD<b class='flag-5'>架構(gòu)</b>與功能<b class='flag-5'>模塊</b>詳解