//见static struct platform_device isp116x_device
static const char hcd_name[] = "isp116x-hcd";
module_platform_driver(isp116x_driver);
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:isp116x-hcd");
static struct platform_driver isp116x_driver = {
.probe = isp116x_probe,
.remove = isp116x_remove,
.suspend = isp116x_suspend,
.resume = isp116x_resume,
.driver = {
//static const char hcd_name[] = "isp116x-hcd";
.name = hcd_name,
},
};
/////////////////////////////////////////////////////////////////////////////////////
//匹配到"isp116x-hcd"设备后就probe
static int isp116x_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct isp116x *isp116x;
struct resource *addr, *data, *ires;
void __iomem *addr_reg;
void __iomem *data_reg;
int irq;
int ret = 0;
unsigned long irqflags;
data = platform_get_resource(pdev, IORESOURCE_MEM, 0);
addr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
irq = ires->start;
irqflags = ires->flags & IRQF_TRIGGER_MASK;
//使用I/O内存首先要申请,然后才能映射
// /O端口的函数是request_region, 申请I/O内存的函数是request_mem_region
if (!request_mem_region(addr->start, 2, hcd_name)) {
ret = -EBUSY;
goto err1;
}
//将一个IO地址空间映射到内核的虚拟地址空间上去,便于访问
addr_reg = ioremap(addr->start, resource_size(addr));
if (!request_mem_region(data->start, 2, hcd_name)) {
ret = -EBUSY;
goto err3;
}
//将一个IO地址空间映射到内核的虚拟地址空间上去,便于访问
data_reg = ioremap(data->start, resource_size(data));
//用usb_hcd结构体描述USB主机控制器驱动,
//它包含USB主机控制器的“家务”信息、硬件资源、状态描述和用于操作主机控制器的hc_driver
/* allocate and initialize hcd */
hcd = usb_create_hcd(&isp116x_hc_driver, &pdev->dev, dev_name(&pdev->dev));
/* this rsrc_start is bogus */
hcd->rsrc_start = addr->start;
isp116x = hcd_to_isp116x(hcd);
isp116x->data_reg = data_reg;
isp116x->addr_reg = addr_reg;
spin_lock_init(&isp116x->lock);
INIT_LIST_HEAD(&isp116x->async);
//
//static struct isp116x_platform_data isp116x_platform_data 被赋值给了isp116x->board
isp116x->board = dev_get_platdata(&pdev->dev);
if (isp116x_check_platform_delay(isp116x)) {
ret = -ENODEV;
goto err6;
}
//调用函数usb_add_hcd填充usb_hcd 将这个hcd添加到系统.hcd就是host control driver的意思
//usb_add_hcd 会调用register_root_hub(hcd)来register a root hub
ret = usb_add_hcd(hcd, irq, irqflags);
//device_init_wakeup(struct device *dev, bool val);
// 初始化设备能不能唤醒系统,并且使用这个功能
//Enable given device to be a wakeup source
//Create a wakeup source object, register it and attach it to @dev.
device_wakeup_enable(hcd->self.controller);
ret = create_debug_file(isp116x);
return 0;
return ret;
}
///////////////////////////////////////////////////////////////////////
//见上文 isp116x_probe函数
//hcd = usb_create_hcd(&isp116x_hc_driver, &pdev->dev, dev_name(&pdev->dev));
//Hc就是host control的意思.即为主机控制器驱动
static struct hc_driver isp116x_hc_driver = {
//static const char hcd_name[] = "isp116x-hcd";
.description = hcd_name,
.product_desc = "ISP116x Host Controller",
.hcd_priv_size = sizeof(struct isp116x),
.irq = isp116x_irq,
.flags = HCD_USB11,
.reset = isp116x_reset,
.start = isp116x_start,
.stop = isp116x_stop,
.urb_enqueue = isp116x_urb_enqueue,
.urb_dequeue = isp116x_urb_dequeue,
.endpoint_disable = isp116x_endpoint_disable,
.get_frame_number = isp116x_get_frame,
.hub_status_data = isp116x_hub_status_data,
.hub_control = isp116x_hub_control,
.bus_suspend = isp116x_bus_suspend,
.bus_resume = isp116x_bus_resume,
};
//////////////////////////////////////////////////////////////////////////////
static irqreturn_t isp116x_irq(struct usb_hcd *hcd)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
u16 irqstat;
irqreturn_t ret = IRQ_NONE;
spin_lock(&isp116x->lock);
isp116x_write_reg16(isp116x, HCuPINTENB, 0);
irqstat = isp116x_read_reg16(isp116x, HCuPINT);
isp116x_write_reg16(isp116x, HCuPINT, irqstat);
if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) {
ret = IRQ_HANDLED;
finish_atl_transfers(isp116x);
}
if (irqstat & HCuPINT_OPR) {
u32 intstat = isp116x_read_reg32(isp116x, HCINTSTAT);
isp116x_write_reg32(isp116x, HCINTSTAT, intstat);
if (intstat & HCINT_UE) {
ERR("Unrecoverable error, HC is dead!\n");
/* IRQ's are off, we do no DMA,
perfectly ready to die ... */
hcd->state = HC_STATE_HALT;
usb_hc_died(hcd);
ret = IRQ_HANDLED;
goto done;
}
if (intstat & HCINT_RHSC)
/* When root hub or any of its ports is going
to come out of suspend, it may take more
than 10ms for status bits to stabilize. */
mod_timer(&hcd->rh_timer, jiffies
+ msecs_to_jiffies(20) + 1);
if (intstat & HCINT_RD) {
DBG("---- remote wakeup\n");
usb_hcd_resume_root_hub(hcd);
}
irqstat &= ~HCuPINT_OPR;
ret = IRQ_HANDLED;
}
if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) {
start_atl_transfers(isp116x);
}
isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb);
done:
spin_unlock(&isp116x->lock);
return ret;
}