Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1183299
  • 博文数量: 221
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2139
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(221)

文章存档

2024年(6)

2023年(8)

2022年(2)

2021年(2)

2020年(29)

2019年(11)

2018年(23)

2017年(41)

2016年(76)

2015年(23)

我的朋友
最近访客

分类: LINUX

2020-09-04 01:35:38

系统内核:linux 4.10


//见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;
}






阅读(1049) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~