- /*
- * OHCI HCD (Host Controller Driver) for USB
- 该程序主要完成s3c2410 USB 主机控制器的初始化工作,包括电源,时钟等
- */
- //需要用到的头文件
- #include <ASM hardware.h>
- #include <ASM mach-types.h>
- #include <ASM hardware clock.h>
- #include <ASM arch usb-control.h>
- //定义主机控制器的有效端口数
- #define valid_port(idx) ((idx) == 1 || (idx) == 2)
- /* 主机控制器的时钟,在clock.h中有它的定义 */
- static struct clk *clk;
- /* 预定义,s3c2410_hcd_oc 主机端口的过流保护函数*/
- static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc);
- /* 该函数返回总线上的当前的平台信息
- 该函数的返回结构: (具体的定义在usb_control.h中)
- struct s3c2410_hcd_info{
- struct usb_hcd *hcd;
- struct s3c2410_hcd_port port[2];
- void (*power_control)(int port,int to);
- void (*enable_oc)(struct s3c2410_hcd_info *,int on);
- void (*report_oc)(struct s3c2410_hcd_info *,int ports);
- };
- */
- struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd)
- {
- return hcd->self.controller->platform_data;
- }
- /* s3c2410_start_hc 该函数启动主机控制器,主要是启动时钟,对打开对端口的过流保护
- */
- static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd)
- {
- struct s3c2410_hcd_info *info = dev->dev.platform_data;
- dev_dbg(&dev->dev, "s3c2410_start_hc:/n");
- clk_enable(clk);
- if (info != NULL) {
- info->hcd = hcd;
- info->report_oc = s3c2410_hcd_oc;
- if (info->enable_oc != NULL) {
- (info->enable_oc)(info, 1);
- }
- }
- }
- /* s3c2410_stop_hc 该函数停止主机控制器,关闭时钟
- */
- static void s3c2410_stop_hc(struct platform_device *dev)
- {
- struct s3c2410_hcd_info *info = dev->dev.platform_data;
- dev_dbg(&dev->dev, "s3c2410_stop_hc:/n");
- if (info != NULL) {
- info->report_oc = NULL;
- info->hcd = NULL;
- if (info->enable_oc != NULL) {
- (info->enable_oc)(info, 0);
- }
- }
- clk_disable(clk);
- }
- /* ohci_s3c2410_hub_status_data 该函数是集线器的状态函数,
- 扫描集线器的两个下行端口,检测是否连接USB设备,若有返回1,无,返回0
- */
- static int
- ohci_s3c2410_hub_status_data (struct usb_hcd *hcd, char *buf)
- {
- struct s3c2410_hcd_info *info = to_s3c2410_info(hcd);
- struct s3c2410_hcd_port *port;
- int orig;
- int portno;
- orig = ohci_hub_status_data (hcd, buf);
- if (info == NULL)
- return orig;
- port = &info->port[0];
- /*扫描两个端口*/
- for (portno = 0; portno < 2; port++, portno++) {
- if (port->oc_changed == 1 &&
- port->flags & S3C_HCDFLG_USED) {
- dev_dbg(hcd->self.controller,
- "oc change on port %d/n", portno);
- if (orig < 1)
- orig = 1;
- buf[0] |= 1<<(portno+1);
- }
- }
- return orig;
- }
- /* s3c2410_usb_set_power 该函数实现对端口的电源配置
- */
- static void s3c2410_usb_set_power(struct s3c2410_hcd_info *info,
- int port, int to)
- {
- if (info == NULL)
- return;
- if (info->power_control != NULL) {
- info->port[port-1].power = to;
- (info->power_control)(port, to);
- }
- }
- /* ohci_s3c2410_hub_control 该函数是集线器的控制函数
- 处理一些对 集线器的控制请求
- 具体参数:
- typeReq 控制请求类别
- wValue 请求值
- */
- static int ohci_s3c2410_hub_control (
- struct usb_hcd *hcd,
- u16 typeReq,
- u16 wValue,
- u16 wIndex,
- char *buf,
- u16 wLength)
- {
- struct s3c2410_hcd_info *info = to_s3c2410_info(hcd);
- struct usb_hub_descriptor *desc;
- int ret = -EINVAL;
- u32 *data = (u32 *)buf;
- dev_dbg(hcd->self.controller,
- "s3c2410_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)/n",
- hcd, typeReq, wValue, wIndex, buf, wLength);
- if (info == NULL) {
- ret = ohci_hub_control(hcd, typeReq, wValue,
- wIndex, buf, wLength);
- goto out;
- }
- /* 检测HUB的请求类别,并且处理相关请求
- */
- switch (typeReq) {
- /*集线器启用端口的请求 */
- case SetPortFeature:
- if (wValue == USB_PORT_FEAT_POWER) {
- dev_dbg(hcd->self.controller, "SetPortFeat: POWER/n");
- s3c2410_usb_set_power(info, wIndex, 1);
- goto out;
- }
- break;
- /* 消除端口的请求*/
- case ClearPortFeature:
- /*具体的请求值*/
- switch (wValue) {
- case USB_PORT_FEAT_C_OVER_CURRENT:
- dev_dbg(hcd->self.controller,
- "ClearPortFeature: C_OVER_CURRENT/n");
- if (valid_port(wIndex)) {
- info->port[wIndex-1].oc_changed = 0;
- info->port[wIndex-1].oc_status = 0;
- }
- goto out;
- case USB_PORT_FEAT_OVER_CURRENT:
- dev_dbg(hcd->self.controller,
- "ClearPortFeature: OVER_CURRENT/n");
- if (valid_port(wIndex)) {
- info->port[wIndex-1].oc_status = 0;
- }
- goto out;
- case USB_PORT_FEAT_POWER:
- dev_dbg(hcd->self.controller,
- "ClearPortFeature: POWER/n");
- if (valid_port(wIndex)) {
- s3c2410_usb_set_power(info, wIndex, 0);
- return 0;
- }
- }
- break;
- }
- ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
- if (ret)
- goto out;
- switch (typeReq) {
- /*获取集线器特定的描述符*/
- case GetHubDescriptor:
- /* 更新集线器的描述符*/
- desc = (struct usb_hub_descriptor *)buf;
- if (info->power_control == NULL)
- return ret;
- dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x/n",
- desc->wHubCharacteristics);
- /* 更新集线器的配置,包括HUB电源和过流保护的配置
- */
- desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM);
- desc->wHubCharacteristics |= cpu_to_le16(0x0001);
- if (info->enable_oc) {
- desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM);
- desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001);
- }
- dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x/n",
- desc->wHubCharacteristics);
- return ret;
- /* 获取端口的状态 */
- case GetPortStatus:
- dev_dbg(hcd->self.controller, "GetPortStatus(%d)/n", wIndex);
- if (valid_port(wIndex)) {
- if (info->port[wIndex-1].oc_changed) {
- *data |= cpu_to_le32(RH_PS_OCIC);
- }
- if (info->port[wIndex-1].oc_status) {
- *data |= cpu_to_le32(RH_PS_POCI);
- }
- }
- }
- out:
- return ret;
- }
- /* s3c2410_hcd_oc 该函数是主机控制器对端口的过流保护
- */
- static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
- {
- struct s3c2410_hcd_port *port;
- struct usb_hcd *hcd;
- unsigned long flags;
- int portno;
- if (info == NULL)
- return;
- port = &info->port[0];
- hcd = info->hcd;
- local_irq_save(flags);
- for (portno = 0; portno < 2; port++, portno++) {
- if (port_oc & (1<<PORTNO) && port->flags & S3C_HCDFLG_USED) {
- port->oc_status = 1;
- port->oc_changed = 1;
- /* 停止该端口的供电 */
- s3c2410_usb_set_power(info, portno+1, 0);
- }
- }
- local_irq_restore(flags);
- }
- /* usb_hcd_s3c2410_remove 主机控制器的卸载
- 停止主机控制器,释放内存资源
- *
- */
- void usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev)
- {
- usb_remove_hcd(hcd);
- s3c2410_stop_hc(dev);
- iounmap(hcd->regs); //解除与内存映射的关系函数
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- usb_put_hcd(hcd);
- }
- /** usb_hcd_s3c2410_probe USB 主机控制器的探测函数.
- 主要实现对主机控制器进行分配资源,并启动主机控制器等
- */
- int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
- struct platform_device *dev)
- {
- struct usb_hcd *hcd = NULL;
- int retval;
- /** 给端口进行供电*/
- s3c2410_usb_set_power(dev->dev.platform_data, 0, 1);
- s3c2410_usb_set_power(dev->dev.platform_data, 1, 1);
- /** usb_create_hcd() 函数初始化主机控制器*/
- hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
- if (hcd == NULL)
- return -ENOMEM; //系统错误,没有相应的内存空间
- /*主机控制器的资源节点*/
- hcd->rsrc_start = dev->resource[0].start;
- hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
- /*请求分配内存资源*/
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- dev_err(&dev->dev, "request_mem_region failed");
- retval = -EBUSY; //系统错误,表示要分配的内存资源已经被占用
- goto err0;
- }
- clk = clk_get(NULL, "usb-host");
- if (IS_ERR(clk)) {
- dev_err(&dev->dev, "cannot get usb-host clock/n");
- retval = -ENOENT;
- goto err1;
- }
- /*启动始终,并启动主机控制器*/
- clk_use(clk);
- s3c2410_start_hc(dev, hcd);
- /*ioremap()作用是将物理地址映射成相应的虚拟地址*/
- hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
- if (!hcd->regs) {
- dev_err(&dev->dev, "ioremap failed/n");
- retval = -ENOMEM;
- goto err2;
- }
- ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
- if (retval != 0)
- goto err2;
- return 0;
- err2:
- s3c2410_stop_hc(dev);
- iounmap(hcd->regs);
- clk_unuse(clk);
- clk_put(clk);
- err1:
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- err0:
- usb_put_hcd(hcd);
- return retval;
- }
- /* ohci_s3c2410_start 开放式主机控制器接口的启动函数
- 调用上层的 ohci_run()函数来实现该功能
- */
- static int
- ohci_s3c2410_start (struct usb_hcd *hcd)
- {
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- int ret;
- if ((ret = ohci_init(ohci)) < 0)
- return ret;
- if ((ret = ohci_run (ohci)) < 0) {
- err ("can't start %s", hcd->self.bus_name);
- ohci_stop (hcd);
- return ret;
- }
- return 0;
- }
- /*节点操作函数的实例
- 定义了2410 USB主机控制器的具体操作函数实例
- */
- static const struct hc_driver ohci_s3c2410_hc_driver = {
- .description = hcd_name,
- .product_desc = "S3C24XX OHCI",
- .hcd_priv_size = sizeof(struct ohci_hcd),
- .irq = ohci_irq,
- .flags = HCD_USB11 | HCD_MEMORY,
- .start = ohci_s3c2410_start,
- .stop = ohci_stop,
- /*
- * 管理I/O请求&相关的设备资源
- */
- .urb_enqueue = ohci_urb_enqueue, //提交URB的具体处理函数
- .urb_dequeue = ohci_urb_dequeue,
- .endpoint_disable = ohci_endpoint_disable,
- /*
- *调度支持,获取当前总线帧号
- */
- .get_frame_number = ohci_get_frame,
- /*
- * 根集线器的控制实例
- */
- .hub_status_data = ohci_s3c2410_hub_status_data,
- .hub_control = ohci_s3c2410_hub_control,
- #if defined(CONFIG_USB_SUSPEND) && 0
- .hub_suspend = ohci_hub_suspend,
- .hub_resume = ohci_hub_resume,
- #endif
- };
- /*ohci_hcd_s3c2410_drv_probe 主机控制器驱动的探测函数 */
- static int ohci_hcd_s3c2410_drv_probe(struct device *dev)
- {
- struct platform_device *pdev = to_platform_device(dev);
- return usb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev);
- }
- /*ohci_hcd_s3c2410_drv_remove 主机控制器驱动的卸载函数 */
- static int ohci_hcd_s3c2410_drv_remove(struct device *dev)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct usb_hcd *hcd = dev_get_drvdata(dev);
- usb_hcd_s3c2410_remove(hcd, pdev);
- return 0;
- }
- /*
- *s3c2410 主机控制驱动的结构实例
- ***/
- static struct device_driver ohci_hcd_s3c2410_driver = {
- .name = "s3c2410-ohci", //驱动名称
- .bus = &platform_bus_type, //总线类型
- .probe = ohci_hcd_s3c2410_drv_probe, //驱动的探测
- .remove = ohci_hcd_s3c2410_drv_remove, //驱动的卸载
- };
- /*s3c2410主机控制器的初始,系统调用,注册主机设备 */
- static int __init ohci_hcd_s3c2410_init (void)
- {
- return driver_register(&ohci_hcd_s3c2410_driver);
- }
- /* s3c2410主机控制器的注销,从Linux内核中注销驱动程序 */
- static void __exit ohci_hcd_s3c2410_cleanup (void)
- {
- driver_unregister(&ohci_hcd_s3c2410_driver);
- }
- /* 初始&卸载 s3c2410主机控制模块 */
- module_init (ohci_hcd_s3c2410_init);
- module_exit (ohci_hcd_s3c2410_cleanup);
ohci-s3c2410代码注释解析
最新推荐文章于 2020-11-09 20:43:51 发布