static int __init udc_init(void) { printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION); return platform_driver_register(&udc_driver);//驱动注冊进系统 }
发现设备后调用PROBE函数 static int __init fsl_udc_probe(struct platform_device *pdev) { struct resource *res; struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; int ret = -ENODEV; unsigned int i; u32 dccparams, portsc;
if (strcmp(pdev->name, driver_name)) { VDBG("Wrong device\n"); return -ENODEV; } /********************************************************/
static struct fsl_udc *udc_controller;
全局变量定义
/*******************************************************/ udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); if (udc_controller == NULL) { ERR("malloc udc failed\n"); return -ENOMEM; } udc_controller->pdata = pdata; //私有变量赋值
#ifdef CONFIG_USB_OTG /* Memory and interrupt resources will be passed from OTG */ udc_controller->transceiver = otg_get_transceiver();//在OTG功能中已经通过otg_set_transceiver 设置了transceiver结构,这里面就能够GET
if (!udc_controller->transceiver) { printk(KERN_ERR "Can't find OTG driver!\n"); ret = -ENODEV; goto err1a; }
res = otg_get_resources(); //获得资源 if (!res) { DBG("resource not registered!\n"); return -ENODEV; } #else if ((pdev->dev.parent) && (to_platform_device(pdev->dev.parent)->resource)) { pdev->resource = to_platform_device(pdev->dev.parent)->resource; pdev->num_resources = to_platform_device(pdev->dev.parent)->num_resources; }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -ENXIO; goto err1a; }
if (!request_mem_region(res->start, resource_size(res), driver_name)) { ERR("request mem region for %s failed \n", pdev->name); ret = -EBUSY; goto err1a; } #endif /*将物理地址映射为驱动能够訪问的虚拟地址*/ dr_regs = ioremap(res->start, resource_size(res)); if (!dr_regs) { ret = -ENOMEM; goto err1; } pdata->regs = (void *)dr_regs; //私有数据接收映射地址 /* * do platform specific init: check the clock, grab/config pins, etc. */
/*调用私有数据的初始化函数,关于初始化函数以下分析*/ if (pdata->platform_init && pdata->platform_init(pdev)) { ret = -ENODEV; goto err2a; }
if (pdata->have_sysif_regs) usb_sys_regs = (struct usb_sys_interface *) ((u32)dr_regs + USB_DR_SYS_OFFSET);
/* Read Device Controller Capability Parameters register */ dccparams = fsl_readl(&dr_regs->dccparams); if (!(dccparams & DCCPARAMS_DC)) { ERR("This SOC doesn't support device role\n"); ret = -ENODEV; goto err2; } /* Get max device endpoints */ /* DEN is bidirectional ep number, max_ep doubles the number */ udc_controller->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2;
#ifdef CONFIG_USB_OTG res++; udc_controller->irq = res->start; #else udc_controller->irq = platform_get_irq(pdev, 0); #endif if (!udc_controller->irq) { ret = -ENODEV; goto err2; } /*注冊中断。该中断和OTG的中断共享一个*/ ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED, driver_name, udc_controller); if (ret != 0) { ERR("cannot request irq %d err %d \n", udc_controller->irq, ret); goto err2; }
/* Initialize the udc structure including QH member and other member */ /*对一些资源进行空间开辟等初始化操作*/ if (struct_udc_setup(udc_controller, pdev)) { ERR("Can't initialize udc data structure\n"); ret = -ENOMEM; goto err3; }
if (!udc_controller->transceiver) { /* initialize usb hw reg except for regs for EP, * leave usbintr reg untouched */ dr_controller_setup(udc_controller); }
/* Setup gadget structure */ udc_controller->gadget.ops = &fsl_gadget_ops; udc_controller->gadget.is_dualspeed = 1; udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; INIT_LIST_HEAD(&udc_controller->gadget.ep_list); udc_controller->gadget.speed = USB_SPEED_UNKNOWN; udc_controller->gadget.name = driver_name;
/* Setup gadget.dev and register with kernel */ dev_set_name(&udc_controller->gadget.dev, "gadget"); udc_controller->gadget.dev.release = fsl_udc_release; udc_controller->gadget.dev.parent = &pdev->dev; ret = device_register(&udc_controller->gadget.dev); if (ret < 0) goto err3;
if (udc_controller->transceiver) { udc_controller->gadget.is_otg = 1; /* now didn't support lpm in OTG mode*/ device_set_wakeup_capable(&pdev->dev, 0); }
/* setup QH and epctrl for ep0 */ ep0_setup(udc_controller);
/* setup udc->eps[] for ep0 */ struct_ep_setup(udc_controller, 0, "ep0", 0); /* for ep0: the desc defined here; * for other eps, gadget layer called ep_enable with defined desc */ udc_controller->eps[0].desc = &fsl_ep0_desc; udc_controller->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD;
/* setup the udc->eps[] for non-control endpoints and link * to gadget.ep_list */ for (i = 1; i < (int)(udc_controller->max_ep / 2); i++) { char name[14];
sprintf(name, "ep%dout", i); struct_ep_setup(udc_controller, i * 2, name, 1); sprintf(name, "ep%din", i); struct_ep_setup(udc_controller, i * 2 + 1, name, 1); }
/* use dma_pool for TD management */ udc_controller->td_pool = dma_pool_create("udc_td", &pdev->dev, sizeof(struct ep_td_struct), DTD_ALIGNMENT, UDC_DMA_BOUNDARY); if (udc_controller->td_pool == NULL) { ret = -ENOMEM; goto err4; } if (g_iram_size) { for (i = 0; i < IRAM_PPH_NTD; i++) { udc_controller->iram_buffer[i] = USB_IRAM_BASE_ADDR + i * g_iram_size; udc_controller->iram_buffer_v[i] = IO_ADDRESS(udc_controller->iram_buffer[i]); } } #ifdef POSTPONE_FREE_LAST_DTD last_free_td = NULL; #endif
/* disable all INTR */ fsl_writel(0, &dr_regs->usbintr);
dr_wake_up_enable(udc_controller, false); udc_controller->stopped = 1;
portsc = fsl_readl(&dr_regs->portsc1); portsc |= PORTSCX_PHY_LOW_POWER_SPD; fsl_writel(portsc, &dr_regs->portsc1);
if (udc_controller->pdata->usb_clock_for_pm) udc_controller->pdata->usb_clock_for_pm(false);
create_proc_file(); return 0;
err4: device_unregister(&udc_controller->gadget.dev); err3: free_irq(udc_controller->irq, udc_controller); err2: if (pdata->platform_uninit) pdata->platform_uninit(pdata); err2a: iounmap((u8 __iomem *)dr_regs); err1: if (!udc_controller->transceiver) release_mem_region(res->start, resource_size(res)); err1a: kfree(udc_controller); udc_controller = NULL; return ret; }
|