Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1366241
  • 博文数量: 860
  • 博客积分: 425
  • 博客等级: 下士
  • 技术积分: 1464
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-20 19:57
个人简介

对技术执着

文章分类

全部博文(860)

文章存档

2019年(16)

2018年(12)

2015年(732)

2013年(85)

2012年(15)

我的朋友

分类: LINUX

2015-03-14 15:33:40

三大控制器已经分析一个啦,下面接着第一篇分析,这篇分析下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子系统的功能。
阅读(645) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~