Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1183341
  • 博文数量: 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 00:44:13

////
/* USB High Spped 2.0 Device (Gadget) */

#ifdef CONFIG_PLAT_S3C24XX
static struct resource s3c_hsudc_resource[] = {
    [0] = DEFINE_RES_MEM(S3C2416_PA_HSUDC, S3C2416_SZ_HSUDC),
    [1] = DEFINE_RES_IRQ(IRQ_USBD),
};

struct platform_device s3c_device_usb_hsudc = {
    .name        = "s3c-hsudc",
    .id        = -1,
    .num_resources    = ARRAY_SIZE(s3c_hsudc_resource),
    .resource    = s3c_hsudc_resource,
    .dev        = {
        .dma_mask        = &samsung_device_dma_mask,
        .coherent_dma_mask    = DMA_BIT_MASK(32),
    },
};

void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd)
{
    s3c_set_platdata(pd, sizeof(*pd), &s3c_device_usb_hsudc);
}
#endif /* CONFIG_PLAT_S3C24XX */

/////////
static void __init smdk2416_machine_init(void)---->
    s3c24xx_hsudc_set_platdata(&smdk2416_hsudc_platdata);
    platform_add_devices(smdk2416_devices, ARRAY_SIZE(smdk2416_devices));

static struct s3c24xx_hsudc_platdata smdk2416_hsudc_platdata = {
    .epnum = 9,
    .gpio_init = smdk2416_hsudc_gpio_init,
    .gpio_uninit = smdk2416_hsudc_gpio_uninit,
};
static void smdk2416_hsudc_gpio_init(void)
{
    s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_UP);
    s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_NONE);
    s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(1));
    s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 0);
}
static struct platform_device *smdk2416_devices[] __initdata = {
    &s3c_device_fb,
    &s3c_device_wdt,
    &s3c_device_ohci,
    &s3c_device_i2c0,
    &s3c_device_hsmmc0,
    &s3c_device_hsmmc1,
    &s3c_device_usb_hsudc,
    &s3c2443_device_dma,
};
/////////////////////////////////////////////////////////////////////////////////


MODULE_DESCRIPTION("Samsung S3C24XX USB high-speed controller driver");
static struct platform_driver s3c_hsudc_driver = {
    .driver        = {
        .name    = "s3c-hsudc",
    },
    .probe        = s3c_hsudc_probe,
};

module_platform_driver(s3c_hsudc_driver);
//////////////////////////

/**
 * struct s3c_hsudc - Driver's abstraction of the device controller.
 * @gadget: Instance of usb_gadget which is referenced by gadget driver.
 * @driver: Reference to currenty active gadget driver.
 * @dev: The device reference used by probe function.
 * @lock: Lock to synchronize the usage of Endpoints (EP's are indexed).
 * @regs: Remapped base address of controller's register space.
 * irq: IRQ number used by the controller.
 * uclk: Reference to the controller clock.
 * ep0state: Current state of EP0.
 * ep: List of endpoints supported by the controller.
 */
struct s3c_hsudc {
    struct usb_gadget gadget;
    struct usb_gadget_driver *driver;
    struct device *dev;
    struct s3c24xx_hsudc_platdata *pd;
    struct usb_phy *transceiver;
    struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)];
    spinlock_t lock;
    void __iomem *regs;
    int irq;
    struct clk *uclk;
    int ep0state;
    struct s3c_hsudc_ep ep[];      //端点
};
///////////////////////////////////////////////

//很重要
static int s3c_hsudc_probe(struct platform_device *pdev)
{
    struct device *dev = &pdev->dev;
    struct resource *res;
    struct s3c_hsudc *hsudc;
    struct s3c24xx_hsudc_platdata *pd = dev_get_platdata(&pdev->dev);
    int ret, i;

    hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) +
            sizeof(struct s3c_hsudc_ep) * pd->epnum,
            GFP_KERNEL);
    if (!hsudc)
        return -ENOMEM;

    platform_set_drvdata(pdev, dev);
    hsudc->dev = dev;
    hsudc->pd = dev_get_platdata(&pdev->dev);

    hsudc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);

    for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
        hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];

    ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies),
                 hsudc->supplies);
    if (ret != 0) {
        dev_err(dev, "failed to request supplies: %d\n", ret);
        goto err_supplies;
    }

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

    hsudc->regs = devm_ioremap_resource(&pdev->dev, res);
    if (IS_ERR(hsudc->regs)) {
        ret = PTR_ERR(hsudc->regs);
        goto err_res;
    }

    spin_lock_init(&hsudc->lock);

    hsudc->gadget.max_speed = USB_SPEED_HIGH;
//OPS操作集合
    hsudc->gadget.ops = &s3c_hsudc_gadget_ops;
    hsudc->gadget.name = dev_name(dev);
    hsudc->gadget.ep0 = &hsudc->ep[0].ep;
    hsudc->gadget.is_otg = 0;
    hsudc->gadget.is_a_peripheral = 0;
    hsudc->gadget.speed = USB_SPEED_UNKNOWN;

    s3c_hsudc_setup_ep(hsudc);

    ret = platform_get_irq(pdev, 0);
    if (ret < 0) {
        dev_err(dev, "unable to obtain IRQ number\n");
        goto err_res;
    }
    hsudc->irq = ret;
//很重要
//这个申请的中断函数是用来接收数据的。
//这里申请的中断处理函数是 s3c_hsudc_irq,这是这个驱动的核心,该USB device驱动的正常工作都围绕它展开。
    ret = devm_request_irq(&pdev->dev, hsudc->irq, s3c_hsudc_irq, 0,
                driver_name, hsudc);

    if (ret < 0) {
        dev_err(dev, "irq request failed\n");
        goto err_res;
    }

    hsudc->uclk = devm_clk_get(&pdev->dev, "usb-device");
    if (IS_ERR(hsudc->uclk)) {
        dev_err(dev, "failed to find usb-device clock source\n");
        ret = PTR_ERR(hsudc->uclk);
        goto err_res;
    }
    clk_enable(hsudc->uclk);

    local_irq_disable();

    disable_irq(hsudc->irq);
    local_irq_enable();

//usb_add_gadget_udc - adds a new gadget to the udc class driver list
//hsudc->gadget可以认为是USB设备控制器
    ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
    if (ret)
        goto err_add_udc;

    pm_runtime_enable(dev);

    return 0;
err_add_udc:
    clk_disable(hsudc->uclk);
err_res:
    if (!IS_ERR_OR_NULL(hsudc->transceiver))
        usb_put_phy(hsudc->transceiver);

err_supplies:
    return ret;
}
///////////////////////////////////////////////////////

物理层的核心
/**
 * s3c_hsudc_irq - Interrupt handler for device controller.
 * @irq: Not used.
 * @_dev: Reference to the device controller.
 *
 * Interrupt handler for the device controller. This handler handles controller
 * interrupts and endpoint interrupts.
 */
//接收到数据处理的函数
//次函数即为 linux板子作为usb从设备时的irq中断接收usb数据的开始函数
static irqreturn_t s3c_hsudc_irq(int irq, void *_dev)
{
    struct s3c_hsudc *hsudc = _dev;
    struct s3c_hsudc_ep *hsep;
    u32 ep_intr;
    u32 sys_status;
    u32 ep_idx;

    spin_lock(&hsudc->lock);
//读System Status寄存器
    sys_status = readl(hsudc->regs + S3C_SSR);
//读EP Intr Status寄存器
    ep_intr = readl(hsudc->regs + S3C_EIR) & 0x3FF;

    if (!ep_intr && !(sys_status & S3C_SSR_DTZIEN_EN)) {
        spin_unlock(&hsudc->lock);
        return IRQ_HANDLED;
    }

    if (sys_status) {
        if (sys_status & S3C_SSR_VBUSON)
            writel(S3C_SSR_VBUSON, hsudc->regs + S3C_SSR);

        if (sys_status & S3C_SSR_ERR)
            writel(S3C_SSR_ERR, hsudc->regs + S3C_SSR);

        if (sys_status & S3C_SSR_SDE) {
            writel(S3C_SSR_SDE, hsudc->regs + S3C_SSR);
            hsudc->gadget.speed = (sys_status & S3C_SSR_HSP) ?
                USB_SPEED_HIGH : USB_SPEED_FULL;
        }

        if (sys_status & S3C_SSR_SUSPEND) {
            writel(S3C_SSR_SUSPEND, hsudc->regs + S3C_SSR);
            if (hsudc->gadget.speed != USB_SPEED_UNKNOWN
                && hsudc->driver && hsudc->driver->suspend)
                hsudc->driver->suspend(&hsudc->gadget);
        }

        if (sys_status & S3C_SSR_RESUME) {
            writel(S3C_SSR_RESUME, hsudc->regs + S3C_SSR);
            if (hsudc->gadget.speed != USB_SPEED_UNKNOWN
                && hsudc->driver && hsudc->driver->resume)
                hsudc->driver->resume(&hsudc->gadget);
        }

        if (sys_status & S3C_SSR_RESET) {
            writel(S3C_SSR_RESET, hsudc->regs + S3C_SSR);
            for (ep_idx = 0; ep_idx < hsudc->pd->epnum; ep_idx++) {
                hsep = &hsudc->ep[ep_idx];
                hsep->stopped = 1;
                s3c_hsudc_nuke_ep(hsep, -ECONNRESET);
            }
            s3c_hsudc_reconfig(hsudc);
            hsudc->ep0state = WAIT_FOR_SETUP;
        }
    }

    if (ep_intr & S3C_EIR_EP0) {
        writel(S3C_EIR_EP0, hsudc->regs + S3C_EIR);
        set_index(hsudc, 0);
          //此处应该是端点0有数据 Handle endpoint 0 interrupt
         //EP0 interrupt could occur when a stall handshake is sent to host
         //or data is sent/received on endpoint 0
        s3c_hsudc_handle_ep0_intr(hsudc);
    }

    ep_intr >>= 1;
    ep_idx = 1;
    while (ep_intr) {
        if (ep_intr & 1)  {
            hsep = &hsudc->ep[ep_idx];
            set_index(hsudc, ep_idx);
            writel(1 << ep_idx, hsudc->regs + S3C_EIR);
            if (ep_is_in(hsep))
                s3c_hsudc_epin_intr(hsudc, ep_idx);
            else
                s3c_hsudc_epout_intr(hsudc, ep_idx);
        }
        ep_intr >>= 1;
        ep_idx++;
    }

    spin_unlock(&hsudc->lock);
    return IRQ_HANDLED;
}
//////////////////////////////////


 
/** s3c_hsudc_handle_ep0_intr - Handle endpoint 0 interrupt.
 * @hsudc: Device controller on which endpoint 0 interrupt has occured.
 *
 * Handle endpoint 0 interrupt when it occurs. EP0 interrupt could occur
 * when a stall handshake is sent to host or data is sent/received on
 * endpoint 0.
 */
static void s3c_hsudc_handle_ep0_intr(struct s3c_hsudc *hsudc)
{

    struct s3c_hsudc_ep *hsep = &hsudc->ep[0];
    struct s3c_hsudc_req *hsreq;

//读EP0 Status寄存器
 
    u32 csr = readl(hsudc->regs + S3C_EP0SR);
    u32 ecr;

    if (csr & S3C_EP0SR_STALL) {
        ecr = readl(hsudc->regs + S3C_EP0CR);
        ecr &= ~(S3C_ECR_STALL | S3C_ECR_FLUSH);
        writel(ecr, hsudc->regs + S3C_EP0CR);

        writel(S3C_EP0SR_STALL, hsudc->regs + S3C_EP0SR);
        hsep->stopped = 0;

        s3c_hsudc_nuke_ep(hsep, -ECONNABORTED);
        hsudc->ep0state = WAIT_FOR_SETUP;
        hsep->bEndpointAddress &= ~USB_DIR_IN;
        return;
    }

    if (csr & S3C_EP0SR_TX_SUCCESS) {
        writel(S3C_EP0SR_TX_SUCCESS, hsudc->regs + S3C_EP0SR);
        if (ep_is_in(hsep)) {
            if (list_empty(&hsep->queue))
                return;

            hsreq = list_entry(hsep->queue.next,
                    struct s3c_hsudc_req, queue);
            s3c_hsudc_write_fifo(hsep, hsreq);
        }
    }
//端点0接收到数据
    if (csr & S3C_EP0SR_RX_SUCCESS) {
        //属于SETUP建立令牌包,SETUP令牌包只用在控制传输中,USB设备的枚举过程都使用控制传输模式,保证数据正确性。
        if (hsudc->ep0state == WAIT_FOR_SETUP)
            s3c_hsudc_process_setup(hsudc);
        else {
            if (!ep_is_in(hsep)) {
                if (list_empty(&hsep->queue))
                    return;
                hsreq = list_entry(hsep->queue.next,
                    struct s3c_hsudc_req, queue);
                s3c_hsudc_read_fifo(hsep, hsreq);
            }
        }
    }
}

////////////////////////////////////////
/**
 * s3c_hsudc_process_setup - Process control request received on endpoint 0.
 * @hsudc: Device controller on which control request has been received.
 *
 * Read the control request received on endpoint 0, decode it and handle
 * the request.
 */
//USB建立令牌包,枚举过程,可以细看,按照USB协议来看是如何握手
static void s3c_hsudc_process_setup(struct s3c_hsudc *hsudc)
{
    struct s3c_hsudc_ep *hsep = &hsudc->ep[0];
    struct usb_ctrlrequest ctrl = {0};
    int ret;

    s3c_hsudc_nuke_ep(hsep, -EPROTO);
    s3c_hsudc_read_setup_pkt(hsudc, (u16 *)&ctrl);

    if (ctrl.bRequestType & USB_DIR_IN) {
        hsep->bEndpointAddress |= USB_DIR_IN;
        hsudc->ep0state = DATA_STATE_XMIT;
    } else {
        hsep->bEndpointAddress &= ~USB_DIR_IN;
        hsudc->ep0state = DATA_STATE_RECV;
    }

    switch (ctrl.bRequest) {
    case USB_REQ_SET_ADDRESS:
        if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
            break;
        hsudc->ep0state = WAIT_FOR_SETUP;
        return;

    case USB_REQ_GET_STATUS:
        if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
            break;
        s3c_hsudc_process_req_status(hsudc, &ctrl);
        return;

    case USB_REQ_SET_FEATURE:
    case USB_REQ_CLEAR_FEATURE:
        if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
            break;
        s3c_hsudc_handle_reqfeat(hsudc, &ctrl);
        hsudc->ep0state = WAIT_FOR_SETUP;
        return;
    }

    if (hsudc->driver) {
        spin_unlock(&hsudc->lock);
        ret = hsudc->driver->setup(&hsudc->gadget, &ctrl);
        spin_lock(&hsudc->lock);

        if (ctrl.bRequest == USB_REQ_SET_CONFIGURATION) {
            hsep->bEndpointAddress &= ~USB_DIR_IN;
            hsudc->ep0state = WAIT_FOR_SETUP;
        }

        if (ret < 0) {
            dev_err(hsudc->dev, "setup failed, returned %d\n",
                        ret);
            s3c_hsudc_set_halt(&hsep->ep, 1);
            hsudc->ep0state = WAIT_FOR_SETUP;
            hsep->bEndpointAddress &= ~USB_DIR_IN;
        }
    }
}


///////////////////////////////////////////////////////////////////

//usb操作
static const struct usb_gadget_ops s3c_hsudc_gadget_ops = {
    .get_frame    = s3c_hsudc_gadget_getframe,
    .udc_start    = s3c_hsudc_start,
    .udc_stop    = s3c_hsudc_stop,
    .vbus_draw    = s3c_hsudc_vbus_draw,
};

///////////////////////////////////////////////////////////////////







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