三大控制器已经分析一个啦,下面接着第一篇分析,这篇分析下usb主机控制器设备与驱动的注册:
//代码路径Devices-msm8x60.c (arch\arm\mach-msm)
//主机控制器平台设备的注册
#define IORESOURCE_MEM 0x00000200
#define IORESOURCE_IRQ 0x00000400
static u64 dma_mask = 0xffffffffULL;
#ifdef CONFIG_USB_EHCI_MSM_72K
static struct resource resources_hsusb_host[] = {
{
.start = 0x12500000,
.end = 0x12500000 + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
{
.start = USB1_HS_IRQ,//132
.end = USB1_HS_IRQ,
.flags = IORESOURCE_IRQ,
},
};
/*主机控制器平台设备*/
struct platform_device msm_device_hsusb_host = {
.name = "msm_hsusb_host",
.id = 0,
.num_resources= ARRAY_SIZE(resources_hsusb_host),
.resource = resources_hsusb_host,
.dev = {
.dma_mask = &dma_mask,
.coherent_dma_mask = 0xffffffffULL,
},
};
/*要增加的主机控制器的平台设备数组*/
static struct platform_device *msm_host_devices[] = {
&msm_device_hsusb_host,
};
/*向系统中注册主机控制器*/
int msm_add_host(unsigned int host, struct msm_usb_host_platform_data *plat)
{
struct platform_device *pdev;
pdev = msm_host_devices[host];
if (!pdev)
return -ENODEV;
pdev->dev.platform_data = plat;
return platform_device_register(pdev);//向设备驱动模型中注册平台设备
}
#endif
//代码路径Board-msm8x60.c (arch\arm\mach-msm)
//主机控制器的平台数据
static struct msm_usb_host_platform_data msm_usb_host_pdata = {
.phy_info = (USB_PHY_INTEGRATED | USB_PHY_MODEL_45NM),//集成的PHY,用的45纳米工艺
.power_budget = 390,//主机最大提供390mA的电流
};
static void __init msm8x60_init(struct msm_board_data *board_data)
{
msm_add_host(0, &msm_usb_host_pdata);//增加第一个主机控制器
}
//代码路径Ehci-msm72k.c (drivers\usb\host)
//主机控制器平台驱动的注册
static struct platform_driver ehci_msm_driver = {
.probe = ehci_msm_probe,//平台驱动的探测函数
.remove = __exit_p(ehci_msm_remove),
.driver = {
.name = "msm_hsusb_host",
.pm = &ehci_msm_dev_pm_ops, },
};
//代码路径Ehci-hcd.c (drivers\usb\host)
/*平台驱动数组*/
static struct platform_driver *plat_drivers[] = {
...........
#if defined(CONFIG_USB_EHCI_MSM_72K) || defined(CONFIG_USB_EHCI_MSM)
&ehci_msm_driver,
#endif
............
};
/* Keep track of which host controller drivers are loaded */
#define USB_UHCI_LOADED 0
#define USB_OHCI_LOADED 1
#define USB_EHCI_LOADED 2
unsigned long usb_hcds_loaded;
EXPORT_SYMBOL_GPL(usb_hcds_loaded);
static int __init ehci_hcd_init(void)
{
int i, retval = 0;
if (usb_disabled())//查看系统是否支持usb?
return -ENODEV;
printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name);//打印log
set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);//设置跟踪EHCI主机控制器的bit位
/*测试是否有UHCI和OHCI控制器驱动已经加载,如果有则给出警告*/
if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) || test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
printk(KERN_WARNING "Warning! ehci_hcd should always be loaded"
" before uhci_hcd and ohci_hcd, not after\n");
for (i = 0; i < ARRAY_SIZE(plat_drivers); i++) {
retval = platform_driver_register(plat_drivers[i]);//向系统中注册平台驱动
...................
}
}
module_init(ehci_hcd_init);
//平台驱动注册过程,如果匹配到设备,会调用驱动的probe函数
static int __devinit ehci_msm_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct resource *res;
struct msm_usb_host_platform_data *pdata;
struct msmusb_hcd *mhcd;
hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev));//创建一个主机控制器
hcd->irq = platform_get_irq(pdev, 0);//获取平台设备的中断资源132
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->rsrc_start = res->start;//获得io内存的起始地址
hcd->rsrc_len = resource_size(res);//获得io内存的长度
//获得msm的ehci主机控制器的结构体
mhcd = hcd_to_mhcd(hcd);//(struct msmusb_hcd *) (hcd->hcd_priv);
/*初始化struct msmusb_hcd结构体的各个成员*/
spin_lock_init(&mhcd->lock);
mhcd->in_lpm = 0;//是否处于低功耗模式?
mhcd->running = 0;//是否正在运行?
device_init_wakeup(&pdev->dev, 1);
pdata = pdev->dev.platform_data;//取出平台设备数据
hcd->power_budget = pdata->power_budget;//取出主机控制器能提供的最大电流390
mhcd->pdata = pdata;//保存平台数据到该设备中
INIT_WORK(&mhcd->lpm_exit_work, usb_lpm_exit_w);//初始化退出低功耗的work
wake_lock_init(&mhcd->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));//初始化该控制器的wake lock
/*初始化ehci的时钟,并初始化*/
pdata->ebi1_clk = clk_get(&pdev->dev, "core_clk");
clk_set_rate(pdata->ebi1_clk, INT_MAX);
retval = msm_xusb_init_host(pdev, mhcd);//初始化host控制器
pm_runtime_enable(&pdev->dev);
return retval;
}
1、创建通用主机控制器结构
/*********************************************************************************************************************/
//在分析前看下这些结构体的关系
struct usb_hcd {
struct usb_bus self; /* hcd is-a bus */
struct kref kref; /* reference counter */
const char *product_desc; /* product/vendor string */
int speed; /* Speed for this roothub. May be different from hcd->driver->flags & HCD_MASK */
char irq_descr[24]; /* driver + bus # */
struct timer_list rh_timer; /* drives root-hub polling */
struct urb *status_urb; /* the current status urb */
#ifdef CONFIG_USB_SUSPEND
struct work_struct wakeup_work; /* for remote wakeup */
#endif
/* hardware info/state */
const struct hc_driver *driver; /* hw-specific hooks */
unsigned long flags;
#define HCD_FLAG_HW_ACCESSIBLE 0 /* at full power */
#define HCD_FLAG_SAW_IRQ 1
#define HCD_FLAG_POLL_RH 2 /* poll for rh status? */
#define HCD_FLAG_POLL_PENDING 3 /* status has changed? */
#define HCD_FLAG_WAKEUP_PENDING 4 /* root hub is resuming? */
#define HCD_FLAG_RH_RUNNING 5 /* root hub is running? */
#define HCD_FLAG_DEAD 6 /* controller has died? */
/* The flags can be tested using these macros; they are likely to be slightly faster than test_bit(). */
#define HCD_HW_ACCESSIBLE(hcd) ((hcd)->flags & (1U << HCD_FLAG_HW_ACCESSIBLE))
#define HCD_SAW_IRQ(hcd) ((hcd)->flags & (1U << HCD_FLAG_SAW_IRQ))
#define HCD_POLL_RH(hcd) ((hcd)->flags & (1U << HCD_FLAG_POLL_RH))
#define HCD_POLL_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_POLL_PENDING))
#define HCD_WAKEUP_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_WAKEUP_PENDING))
#define HCD_RH_RUNNING(hcd) ((hcd)->flags & (1U << HCD_FLAG_RH_RUNNING))
#define HCD_DEAD(hcd) ((hcd)->flags & (1U << HCD_FLAG_DEAD))
/* Flags that get set only during HCD registration or removal. */
unsigned rh_registered:1;/* is root hub registered? */
unsigned rh_pollable:1; /* may we poll the root hub? */
unsigned msix_enabled:1; /* driver has MSI-X enabled? */
/* The next flag is a stopgap, to be removed when all the HCDs
* support the new root-hub polling mechanism. */
unsigned uses_new_polling:1;
unsigned wireless:1; /* Wireless USB HCD */
unsigned authorized_default:1;
unsigned has_tt:1; /* Integrated TT in root hub */
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
u64 rsrc_start; /* memory/io resource start */
u64 rsrc_len; /* memory/io resource length */
unsigned power_budget;/* in mA, 0 = no limit */
struct mutex *bandwidth_mutex;
struct usb_hcd *shared_hcd;
struct usb_hcd *primary_hcd;
#define HCD_BUFFER_POOLS 4
struct dma_pool *pool[HCD_BUFFER_POOLS];
int state;
# define __ACTIVE 0x01
# define __SUSPEND 0x04
# define __TRANSIENT 0x80
# define HC_STATE_HALT 0
# define HC_STATE_RUNNING (__ACTIVE)
# define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
# define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT)
# define HC_STATE_SUSPENDED (__SUSPEND)
#define HC_IS_RUNNING(state) ((state) & __ACTIVE)
#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
unsigned long hcd_priv[0]//预留空间存放下面的结构体(1)
__attribute__ ((aligned(sizeof(unsigned long))));
};
struct msmusb_hcd {//(1)
struct ehci_hcd ehci;//指向下面的结构体(2)
struct clk *alt_core_clk;
struct clk *iface_clk;
unsigned in_lpm;
struct work_struct lpm_exit_work;
spinlock_t lock;
struct wake_lock wlock;
unsigned int clk_enabled;
struct msm_usb_host_platform_data *pdata;
unsigned running;
struct otg_transceiver *xceiv;
struct work_struct otg_work;
unsigned flags;
struct msm_otg_ops otg_ops;
};
/* one per controller */
struct ehci_hcd {//(2)
/* glue to PCI and HCD framework */
struct ehci_caps __iomem *caps;//对应ehci spec上的寄存器
struct ehci_regs __iomem *regs;
struct ehci_dbg_port __iomem *debug;
__u32 hcs_params; /* cached register copy */
spinlock_t lock;
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *dummy; /* For AMD quirk use */
struct ehci_qh *reclaim;
struct ehci_qh *qh_scan_next;
unsigned scanning : 1;
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
unsigned periodic_size;
__hc32 *periodic; /* hw periodic table */
dma_addr_t periodic_dma;
unsigned i_thresh; /* uframes HC might cache */
union ehci_shadow *pshadow; /* mirror hw periodic table */
int next_uframe; /* scan periodic, start here */
unsigned periodic_sched; /* periodic activity count */
/* list of itds & sitds completed while clock_frame was still active */
struct list_head cached_itd_list;
struct list_head cached_sitd_list;
unsigned clock_frame;
/* per root hub port */
unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
/* bit vectors (one bit per port) */
unsigned long bus_suspended; /* which ports were already suspended at the start of a bus suspend */
unsigned long companion_ports; /* which ports are dedicated to the companion controller */
unsigned long owned_ports; /* which ports are owned by the companion during a bus suspend */
unsigned long port_c_suspend; /* which ports have the change-suspend feature turned on */
unsigned long suspended_ports; /* which ports are suspended */
/* per-HC memory pools (could be per-bus, but ...) */
struct dma_pool *qh_pool; /* qh per active urb */
struct dma_pool *qtd_pool; /* one or more per qh */
struct dma_pool *itd_pool; /* itd per iso urb */
struct dma_pool *sitd_pool; /* sitd per split iso urb */
struct timer_list iaa_watchdog;
struct timer_list watchdog;
unsigned long actions;
unsigned periodic_stamp;
unsigned random_frame;
unsigned long next_statechange;
ktime_t last_periodic_enable;
u32 command;
void (*start_hnp)(struct ehci_hcd *ehci);
/* SILICON QUIRKS */
unsigned no_selective_suspend:1;
unsigned has_fsl_port_bug:1; /* FreeScale */
unsigned big_endian_mmio:1;
unsigned big_endian_desc:1;
unsigned big_endian_capbase:1;
unsigned has_amcc_usb23:1;
unsigned need_io_watchdog:1;
unsigned broken_periodic:1;
unsigned amd_pll_fix:1;
unsigned fs_i_thresh:1; /* Intel iso scheduling */
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
#define OHCI_USB_OPER (2 << 6)
#define OHCI_USB_SUSPEND (3 << 6)
#define OHCI_HCCTRL_OFFSET 0x4
#define OHCI_HCCTRL_LEN 0x4
__hc32 *ohci_hcctrl_reg;
unsigned has_hostpc:1;
unsigned has_lpm:1; /* support link power management */
unsigned has_ppcd:1; /* support per-port change bits */
u8 sbrn; /* packed release number */
...............
/* OTG controllers and transceivers need software interaction*/
struct otg_transceiver *transceiver;//连接OTG核心控制器的桥梁
};
/*************************************************************************************************************/
//hc driver驱动结构体
struct hc_driver {
const char *description; /* "ehci-hcd" etc */
const char *product_desc; /* product/vendor string */
size_t hcd_priv_size; /* size of private data */
/* irq handler */
irqreturn_t (*irq) (struct usb_hcd *hcd);
int flags;
#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */
#define HCD_SHARED 0x0004 /* Two (or more) usb_hcds share HW */
#define HCD_USB11 0x0010 /* USB 1.1 */
#define HCD_USB2 0x0020 /* USB 2.0 */
#define HCD_USB3 0x0040 /* USB 3.0 */
#define HCD_MASK 0x0070
/* called to init HCD and root hub */
int (*reset) (struct usb_hcd *hcd);
int (*start) (struct usb_hcd *hcd);
/* NOTE: these suspend/resume calls relate to the HC as a whole, not just the root hub; they're for PCI bus glue.*/
/* called after suspending the hub, before entering D3 etc */
int (*pci_suspend)(struct usb_hcd *hcd, bool do_wakeup);
/* called after entering D0 (etc), before resuming the hub */
int (*pci_resume)(struct usb_hcd *hcd, bool hibernated);
/* cleanly make HCD stop writing memory and doing I/O */
void (*stop) (struct usb_hcd *hcd);
void (*shutdown) (struct usb_hcd *hcd); /* shutdown HCD */
/* return current frame number */
int (*get_frame_number) (struct usb_hcd *hcd);
/* manage i/o requests, device state */
int (*urb_enqueue)(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
int (*urb_dequeue)(struct usb_hcd *hcd, struct urb *urb, int status);
/* hw synch, freeing endpoint resources that urb_dequeue can't */
void(*endpoint_disable)(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
/* (optional) these hooks allow an HCD to override the default DMA mapping and unmapping routines. In general, they shouldn't be
* necessary unless the host controller has special DMA requirements, such as alignment contraints. If these are not specified, the
* general usb_hcd_(un)?map_urb_for_dma functions will be used instead (and it may be a good idea to call these functions in your HCD implementation) */
int (*map_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
void (*unmap_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb);
/* (optional) reset any endpoint state such as sequence number and current window */
void (*endpoint_reset)(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
/* root hub support */
int (*hub_status_data) (struct usb_hcd *hcd, char *buf);
int (*hub_control) (struct usb_hcd *hcd,u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength);
int (*bus_suspend)(struct usb_hcd *);
int (*bus_resume)(struct usb_hcd *);
int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
/* force handover of high-speed port to full-speed companion */
void(*relinquish_port)(struct usb_hcd *, int);
/* has a port been handed over to a companion? */
int (*port_handed_over)(struct usb_hcd *, int);
/* CLEAR_TT_BUFFER completion callback */
void(*clear_tt_buffer_complete)(struct usb_hcd *, struct usb_host_endpoint *);
/* xHCI specific functions Called by usb_alloc_dev to alloc HC device structures */
int (*alloc_dev)(struct usb_hcd *, struct usb_device *);
/* Called by usb_disconnect to free HC device structures */
void (*free_dev)(struct usb_hcd *, struct usb_device *);
/* Change a group of bulk endpoints to support multiple stream IDs */
int (*alloc_streams)(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint **eps, unsigned int num_eps, unsigned int num_streams, gfp_t mem_flags);
/* Reverts a group of bulk endpoints back to not using stream IDs. Can fail if we run out of memory.*/
int (*free_streams)(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint **eps, unsigned int num_eps, gfp_t mem_flags);
/* Bandwidth computation functions */
/* Note that add_endpoint() can only be called once per endpoint before check_bandwidth() or reset_bandwidth() must be called.
* drop_endpoint() can only be called once per endpoint also. A call to xhci_drop_endpoint() followed by a call to
* xhci_add_endpoint() will add the endpoint to the schedule with possibly new parameters denoted by a different endpoint descriptor
* in usb_host_endpoint. A call to xhci_add_endpoint() followed by a call to xhci_drop_endpoint() is not allowed. */
/* Allocate endpoint resources and add them to a new schedule */
int (*add_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);
/* Drop an endpoint from a new schedule */
int (*drop_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);
/* Check that a new hardware configuration, set using endpoint_enable and endpoint_disable, does not exceed bus
* bandwidth. This must be called before any set configuration or set interface requests are sent to the device.*/
int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
/* Reset the device schedule to the last known good schedule, which was set from a previous successful call to
* check_bandwidth(). This reverts any add_endpoint() and drop_endpoint() calls since that last successful call.
* Used for when a check_bandwidth() call fails due to resource or bandwidth constraints. */
void(*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
/* Returns the hardware-chosen device address */
int (*address_device)(struct usb_hcd *, struct usb_device *udev);
/* Notifies the HCD after a hub descriptor is fetched. Will block. */
int (*update_hub_device)(struct usb_hcd *, struct usb_device *hdev, struct usb_tt *tt, gfp_t mem_flags);
int (*reset_device)(struct usb_hcd *, struct usb_device *);
/* Notifies the HCD after a device is connected and its address is set */
int (*update_device)(struct usb_hcd *, struct usb_device *);
};
//下面重点看下控制器的分配函数usb_create_hcd()
static struct hc_driver msm_hc_driver = {
.description = hcd_name,//static const char hcd_name [] = "ehci_hcd";
.product_desc = "Qualcomm On-Chip EHCI Host Controller",
.hcd_priv_size = sizeof(struct msmusb_hcd),//实际的控制器结构体分配的大小
/*generic hardware linkage */
.irq = ehci_msm_irq,
.flags = HCD_USB2, //#define HCD_USB2 0x0020
.reset = ehci_msm_reset,
.start = ehci_msm_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,
/* 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_msm_bus_suspend,
.bus_resume = ehci_msm_bus_resume,
.relinquish_port = ehci_relinquish_port,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
//下面开始分析该函数
hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev));
struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name)
{
return usb_create_shared_hcd(driver, dev, bus_name, NULL);
}
//下面是该函数的具体实现
struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name, struct usb_hcd *primary_hcd)
{
struct usb_hcd *hcd;
hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);//分配内存,该内存有两部分,hcd+hcd_priv_size
if (primary_hcd == NULL) {
hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),GFP_KERNEL);//为互斥体分配内存
mutex_init(hcd->bandwidth_mutex);//初始化hcd的互斥体
dev_set_drvdata(dev, hcd);//把该hcd设置为dev的私有数据
}
...........
kref_init(&hcd->kref);//初始化引用
/*初始化usb总线*/
usb_bus_init(&hcd->self);
hcd->self.controller = dev;
hcd->self.bus_name = bus_name;
hcd->self.uses_dma = (dev->dma_mask != NULL);
/*初始化hcd用的timer*/
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;//root hub轮询时用的hub
hcd->rh_timer.data = (unsigned long) hcd;//该timer的function参数
#ifdef CONFIG_USB_SUSPEND
INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
#endif
hcd->driver = driver;//把driver挂到hcd上
hcd->speed = driver->flags & HCD_MASK;//usb2.0
hcd->product_desc = (driver->product_desc) ? driver->product_desc :"USB Host Controller";//为产品描述符赋值
return hcd;
}
2、初始化EHCI主机控制器
static int msm_xusb_init_host(struct platform_device *pdev, struct msmusb_hcd *mhcd)
{
int ret = 0;
struct msm_otg *otg;
struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct msm_usb_host_platform_data *pdata = mhcd->pdata;
switch (PHY_TYPE(pdata->phy_info)) {
case USB_PHY_INTEGRATED:
...................
INIT_WORK(&mhcd->otg_work, msm_hsusb_otg_work);
mhcd->xceiv = otg_get_transceiver();//从otg控制器中获得收发器,这时可以使用otg核心资源
otg = container_of(mhcd->xceiv, struct msm_otg, otg);
hcd->regs = otg->regs;//从otg中取出io寄存器的操作地址
otg->start_host = msm_hsusb_start_host;//挂载启动主机控制器回调函数
ehci->start_hnp = ehci_msm_start_hnp;
ret = otg_set_host(mhcd->xceiv, &hcd->self);//设置otg收发器的host成员
break;
default:
pr_err("phy type is bad\n");
}
return ret;
}
//----------------------------------------------------------------------------
2.1 设置收发器的host成员
otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
otg->set_host(otg, host);
msm_otg_set_host;
static int msm_otg_set_host(struct otg_transceiver *xceiv, struct usb_bus *host)
{
struct msm_otg *dev = container_of(xceiv, struct msm_otg, otg);
dev->usbdev_nb.notifier_call = usbdev_notify;//挂载通知链函数
usb_register_notify(&dev->usbdev_nb);//注册通知链
dev->otg.host = host;//把主控制器总线挂到otg设备控制器上
pr_info("host driver registered w/ tranceiver\n");
............
return 0;
}
//下面看下上面用到的通知链处理函数,主要目的是驱动otg控制器的状态机
static int usbdev_notify(struct notifier_block *self, unsigned long action, void *device)
{
enum usb_otg_state state;
struct msm_otg *dev = container_of(self, struct msm_otg, usbdev_nb);
struct usb_device *udev = device;
int work = 1;
unsigned long flags;
....................
spin_lock_irqsave(&dev->lock, flags);
state = dev->otg.state;
spin_unlock_irqrestore(&dev->lock, flags);
switch (state) {
case OTG_STATE_A_WAIT_BCON:
if (action == USB_DEVICE_ADD) {
pr_debug("B_CONN set\n");
set_bit(B_CONN, &dev->inputs);//设置位域
.............
}
break;
case OTG_STATE_A_HOST:
if (action == USB_DEVICE_REMOVE) {
pr_debug("B_CONN clear\n");
clear_bit(B_CONN, &dev->inputs);//清除位域
set_aca_bmaxpower(dev, 0);
}
break;
default:
work = 0;
break;
}
do_work:
if (work) {
wake_lock(&dev->wlock);
queue_work(dev->wq, &dev->sm_work);//调度msm_otg_sm_work,驱动状态机
}
out:
return NOTIFY_OK;
}
上面就是主机控制器设备与驱动的注册.下一篇接着分析设备控制器及其驱动的注册。当分析完三大控制器后,看下该控制器三大控制器是如何配合完成android usb子系统的功能。