OTG与gadget学习(一)

OTG即可工作在host模式又可以工作在device模式,模式之间通过HNP协议来进行转换。“USB接口上有4个管脚,OTG功能有5个。原来4个分别是电 D+ D- 地。 现在增加了一个ID。这个ID线就决定了自己做主设备还是从设备。如果ID线是高则自己是从设备,反之是主设备。”

s5pv210使用的是s3c_udc_otg.c驱动。

arch/arm/plat-s5p/dev-hsdevice.c

定义platform_device结构

struct platform_device s3c_device_usbgadget = {

.name = "s3c-usbgadget",

.id = -1,

.num_resources = ARRAY_SIZE(s3c_usbgadget_resource),

.resource = s3c_usbgadget_resource,

};


定义platform_device下的struct resource设备资源结构

static struct resource s3c_usbgadget_resource[] = {

[0] = {

  //描述设备实体在cpu总线上的线性起始物理地址

.start = S3C_PA_OTG,

//描述设备实体在cpu总线上的线性结尾物理地址

.end = S3C_PA_OTG + S3C_SZ_OTG - 1,

.flags = IORESOURCE_MEM,

},

[1] = {

.start = IRQ_OTG,//中断号

.end = IRQ_OTG,

.flags = IORESOURCE_IRQ,

}

};

void __init s5p_otg_set_platdata(struct s5p_otg_platdata *pd)

{

struct s5p_otg_platdata *npd;

 

npd = s3c_set_platdata(pd, sizeof(struct s5p_otg_platdata),

&s3c_device_usbgadget);

 

if (!npd->phy_init)

npd->phy_init = s5p_usb_phy_init;

if (!npd->phy_exit)

npd->phy_exit = s5p_usb_phy_exit;

}

 

 

arch/arm/mach-s5pv210/mach-mini210.c

/* USB DEVICE */

static struct s5p_otg_platdata mini210_otg_pdata;

static void __init mini210_otg_init(void)

{

struct s5p_otg_platdata *pdata = &mini210_otg_pdata;

s5p_otg_set_platdata(pdata);

}

 

 

drivers/usb/gadget/s3c_udc_otg.c

static struct platform_driver s3c_udc_driver = {

.probe = s3c_udc_probe,

.remove = s3c_udc_remove,

.suspend = s3c_udc_suspend,

.resume = s3c_udc_resume,

.driver = {

.owner = THIS_MODULE,

.name = "s3c-usbgadget", //通过该名字匹配开始注册进系统的设备

},

};

//定义处理函数,在设备名字匹配到后调用,发现该驱动对应的设备在系统中注册过。

static int s3c_udc_probe(struct platform_device *pdev)

{

struct s3c_udc *dev = &memory;

int retval;

printk("<<<<< %s >>>>>\n", __func__);

DEBUG("%s: %p\n", __func__, pdev);

pdata = pdev->dev.platform_data;

   if (!pdata) {

      dev_err(&pdev->dev, "No platform data defined\n");

      return -EINVAL;

   }

 

spin_lock_init(&dev->lock);

dev->dev = pdev;

 

device_initialize(&dev->gadget.dev);

dev->gadget.dev.parent = &pdev->dev;

 

dev->gadget.is_dualspeed = 1; /* Hack only*/

dev->gadget.is_otg = 0;

dev->gadget.is_a_peripheral = 0;

dev->gadget.b_hnp_enable = 0;

dev->gadget.a_hnp_support = 0;

dev->gadget.a_alt_hnp_support = 0;

 

the_controller = dev;

platform_set_drvdata(pdev, dev);

 

dev_set_name(&dev->gadget.dev, "gadget");

otg_clock = clk_get(&pdev->dev, "otg");

if (otg_clock == NULL) {

printk("failed to find otg clock source\n");

return -ENOENT;

}

 

udc_reinit(dev);

 

 

retval = request_irq(IRQ_EINT8, s5p_eint8_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "s5pv210-ein8", dev);

if (retval != 0)

printk("s5pv210-ein8: can't get irq %i, err %d\n", IRQ_EINT8, retval);

/* irq setup after old hardware state is cleaned up */

retval =

    request_irq(IRQ_OTG, s3c_udc_irq, 0, driver_name, dev);

 

if (retval != 0) {

printk("%s: can't get irq %i, err %d\n", driver_name,

      IRQ_OTG, retval);

return -EBUSY;

}

wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");

disable_irq(IRQ_OTG);

create_proc_files();

return retval;

}

 

 

//将platform_driver结构注册进系统

//系统通过注册名字匹配该设备是否已经在系统中

//如果在调用注册的probe = s3c_udc_probe函数

static int __init udc_init(void)

{

int ret;

 

printk("<<<<< %s >>>>>\n", __func__);

 

ret = platform_driver_register(&s3c_udc_driver);

if (!ret)

printk(KERN_INFO "%s : %s\n"

"%s : version %s %s\n",

driver_name, DRIVER_DESC,

driver_name, DRIVER_VERSION, OTG_DMA_MODE ?

"(DMA Mode)" : "(Slave Mode)");

 

return ret;

}

 

基于s3c6410 otg controllergadget driverusb枚举分析 

http://blog.csdn.net/fanqipin/article/details/8450694

 

说的比较好,但对于USB新手来说,真的是看得云里雾里的。otg controller? gadget device controller? Device controller? gadget driver? 

不知道有没从上电枚举开始,硬件驱动都讲的?

他讲的还是有点模糊。

host端枚举过程如下:

a. 当hub检测到hub状态寄存器发生变化时,去唤醒hub的守护进程,去查看具体是那 一个port引起的;

b.  如果发现有设备插入,等待100ms使设备稳定后,root hub会向插入设备的port发送reset请求,reset成功后usb设备处于default状态;

c. 向新插入的设备发送设置地址请求,用来设置设备地址;

d. 获取usb设备的设备描述符; 

e.根据usb设备的配置个数,获取对应usb设备配置描述符;

f. 选择e获取的配置描述符,选择合适 的usb配置,对usb设备进行配置;

“usb设备侧对host的请求都是通过中断进行触发的”?这个usb设备侧?这个host?

他下面就分析s3c-hsotg.c了,但我这边210开发板用到的是s3c_udc_otg.c。对于函数及数据结构,没有给出文件目录就直接代码分析了,东一块西一块的,对于我们新手真的只能看着他给的代码看,而无法自己跟着他的思路找代码。

反正我看完,就只知道他分析了,也分析了代码,但一点暂时记忆都没有,不知道他到底分析的是什么流程,数据是怎样的走向。重复看了几遍之后还是一脸的茫然。

 

自己再看看吧。

    210开发板运行Linux系统接上OTG线,没有任何反应。dmesg下也没有任何新加的打印信息。

    怎么找到s3c_udc_otg.c,先不说了。

    加打印,dmesg | grep “s3c_udc_probe”搜索到了,说明s3c_udc_probe运行了。查看drivers/usb/gadget/s3c_udc_otg.c,s3c_udc_probe设置在s3c_udc_driver里。s3c_udc_driver是名为“s3c-usbgadget”的平台驱动,那就还有“s3c-usbgadget”平台设备。

linux源码下搜索,找到arch/arm/plat-s5p/dev-hsdevice.c中s3c_device_usbgadget平台设备。但这个文件很简单,没有注册平台设备。但看到s5p_otg_set_platdata()调用。搜索此函数的调用。找到arch/arm/mach-s5pv210/mach-mini210.c。在mini210_otg_init()中调用设置了。mini210_otg_init()调用自mini210_machine_init()。

 

mini210_machine_init()调用的地方。

MACHINE_START(MINI210, "MINI210")

/* Maintainer: Kukjin Kim <[email protected]> */

.boot_params = S5P_PA_SDRAM + 0x100,

.fixup = mini210_fixup,

.init_irq = s5pv210_init_irq,

.map_io = mini210_map_io,

.init_machine = mini210_machine_init,

#ifdef CONFIG_S5P_HIGH_RES_TIMERS

.timer = &s5p_systimer,

#else

.timer = &s5p_timer,

#endif

MACHINE_END

init_machine,那肯定是会运行了,s3c_device_usbgadget平台设备是注册上去了。为验证,s5p_otg_set_platdata()中加打印,dmesg | grep "s5p_otg_set_platdata",确实。

在s3c_udc_probe中:

static int s3c_udc_probe(struct platform_device *pdev)

{

struct s3c_udc *dev = &memory;

int retval;

DEBUG("%s: %p\n", __func__, pdev);

pdata = pdev->dev.platform_data;

        if (!pdata) {

                dev_err(&pdev->dev, "No platform data defined\n");

                return -EINVAL;

        }

 

spin_lock_init(&dev->lock);

dev->dev = pdev;

 

device_initialize(&dev->gadget.dev);

dev->gadget.dev.parent = &pdev->dev;

 

dev->gadget.is_dualspeed = 1; /* Hack only*/

dev->gadget.is_otg = 0;

dev->gadget.is_a_peripheral = 0;

dev->gadget.b_hnp_enable = 0;

dev->gadget.a_hnp_support = 0;

dev->gadget.a_alt_hnp_support = 0;

 

the_controller = dev;

platform_set_drvdata(pdev, dev);

 

dev_set_name(&dev->gadget.dev, "gadget");

otg_clock = clk_get(&pdev->dev, "otg");

if (otg_clock == NULL) {

pr_err("failed to find otg clock source\n");

return -ENOENT;

}

 

udc_reinit(dev);

 

/* irq setup after old hardware state is cleaned up */

retval =

    request_irq(IRQ_OTG, s3c_udc_irq, 0, driver_name, dev);

 

if (retval != 0) {

pr_err("%s: can't get irq %i, err %d\n", driver_name,

      IRQ_OTG, retval);

return -EBUSY;

}

wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");

disable_irq(IRQ_OTG);

create_proc_files();

return retval;

request_irq申请了IRQ_OTG,但却disable了。搜索enable的地方。就两个地方:

1)usb_gadget_probe_driver()

2)s3c_udc_resume()

s3c_udc_resume是电源管理部分(休眠)的,那就是usb_gadget_probe_driver()。

 

struct usb_gadget_driver {

char *function;

enum usb_device_speed speed;

void (*unbind)(struct usb_gadget *);

int (*setup)(struct usb_gadget *,

const struct usb_ctrlrequest *);

void (*disconnect)(struct usb_gadget *);

void (*suspend)(struct usb_gadget *);

void (*resume)(struct usb_gadget *);

 

/* FIXME support safe rmmod */

struct device_driver driver;

}

 

struct usb_composite_driver {

const char *name;

const char *iProduct;

const char *iManufacturer;

const struct usb_device_descriptor *dev;

struct usb_gadget_strings **strings;

unsigned needs_serial:1;

 

int (*unbind)(struct usb_composite_dev *);

 

void (*disconnect)(struct usb_composite_dev *);

 

/* global suspend hooks */

void (*suspend)(struct usb_composite_dev *);

void (*resume)(struct usb_composite_dev *);

};


     继续找,http://blog.csdn.net/yaozhenguo2006?viewmode=contents,《Linux USB Gadget--软件结构》、《Linux USB Gadget--各环节的整合》、《Linux USB Gadget--设备枚举》三篇文章还不错。

OTG与gadget学习(一)_第1张图片

Webcam使用的却是usb_composite_driver?


你可能感兴趣的:(OTG与gadget学习(一))