⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb_ohci.c

📁 基于s3c2440的U盘读写程序
💻 C
📖 第 1 页 / 共 4 页
字号:
            return -1;
        }
    }
    if (ed->state == ED_NEW || (ed->state & ED_DEL)) 
    {
        urb_free_priv (purb_priv);
        err("sohci_submit_job: EINVAL");
        return -1;
    }
    /* link the ed into a chain if is not already */
    if (ed->state != ED_OPER)
    ep_link (ohci, ed);
    /* fill the TDs and link it to the ed */
    td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval);
    return 0;
}


/*-------------------------------------------------------------------------*/
#ifdef DEBUG
/* tell us the current USB frame number */
static int sohci_get_current_frame_number (struct usb_device *usb_dev)
{
    ohci_t *ohci = &gohci;
    return m16_swap (ohci->hcca->frame_no);
}


#endif
/*-------------------------------------------------------------------------*
 * ED handling functions
 *-------------------------------------------------------------------------*/
/* link an ed into one of the HC chains */
static int ep_link (ohci_t *ohci, ed_t *edi)
{
    volatile ed_t *ed = edi;
    ed->state = ED_OPER;
    switch (ed->type) 
    {
    case PIPE_CONTROL:
        ed->hwNextED = 0;
        if (ohci->ed_controltail == NULL) 
        {
            writel (ed, &ohci->regs->ed_controlhead);
        } 
        else 
        {
            ohci->ed_controltail->hwNextED = m32_swap (ed);
        }
        ed->ed_prev = ohci->ed_controltail;
        if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
        !ohci->ed_rm_list[1] && !ohci->sleeping) 
        {
            ohci->hc_control |= OHCI_CTRL_CLE;
            //s_UartPrint("hc_contro|= OHCI_CTRL_CLE\n");
            writel (ohci->hc_control, &ohci->regs->control);
        }
        ohci->ed_controltail = edi;
        break;
    case PIPE_BULK:
        ed->hwNextED = 0;
        if (ohci->ed_bulktail == NULL) 
        {
            writel (ed, &ohci->regs->ed_bulkhead);
        } 
        else 
        {
            ohci->ed_bulktail->hwNextED = m32_swap (ed);
        }
        ed->ed_prev = ohci->ed_bulktail;
        if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
        !ohci->ed_rm_list[1] && !ohci->sleeping) 
        {
            ohci->hc_control |= OHCI_CTRL_BLE;
            //s_UartPrint("hc_contro|= OHCI_CTRL_BLE\n");
            writel (ohci->hc_control, &ohci->regs->control);
        }
        ohci->ed_bulktail = edi;
        break;
    }
    return 0;
}


/*-------------------------------------------------------------------------*/
/* unlink an ed from one of the HC chains.
 * just the link to the ed is unlinked.
 * the link from the ed still points to another operational ed or 0
 * so the HC can eventually finish the processing of the unlinked ed */
static int ep_unlink (ohci_t *ohci, ed_t *ed)
{
    ed->hwINFO |= m32_swap (OHCI_ED_SKIP);
    switch (ed->type) 
    {
    case PIPE_CONTROL:
        if (ed->ed_prev == NULL) 
        {
            if (!ed->hwNextED) 
            {
                ohci->hc_control &= ~OHCI_CTRL_CLE;
                writel (ohci->hc_control, &ohci->regs->control);
            }
            writel (m32_swap (*((U32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
        } 
        else 
        {
            ed->ed_prev->hwNextED = ed->hwNextED;
        }
        if (ohci->ed_controltail == ed) 
        {
            ohci->ed_controltail = ed->ed_prev;
        } 
        else 
        {
            ((ed_t *)m32_swap (*((U32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
        }
        break;
    case PIPE_BULK:
        if (ed->ed_prev == NULL) 
        {
            if (!ed->hwNextED) 
            {
                ohci->hc_control &= ~OHCI_CTRL_BLE;
                writel (ohci->hc_control, &ohci->regs->control);
            }
            writel (m32_swap (*((U32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
        } 
        else 
        {
            ed->ed_prev->hwNextED = ed->hwNextED;
        }
        if (ohci->ed_bulktail == ed) 
        {
            ohci->ed_bulktail = ed->ed_prev;
        } 
        else 
        {
            ((ed_t *)m32_swap (*((U32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
        }
        break;
    }
    ed->state = ED_UNLINK;
    return 0;
}


/*-------------------------------------------------------------------------*/
/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
 * but the USB stack is a little bit stateless  so we do it at every transaction
 * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
 * in all other cases the state is left unchanged
 * the ed info fields are setted anyway even though most of them should not change */
static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe)
{
    td_t *td;
    ed_t *ed_ret;
    volatile ed_t *ed;
    ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
    (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
    if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) 
    {
        err("ep_add_ed: pending delete");
        /* pending delete request */
        return NULL;
    }
    if (ed->state == ED_NEW) 
    {
        ed->hwINFO = m32_swap (OHCI_ED_SKIP); /* skip ed */
        /* dummy td; end of td list for ed */
        td = td_alloc (usb_dev);
        ed->hwTailP = m32_swap (td);
        ed->hwHeadP = ed->hwTailP;
        ed->state = ED_UNLINK;
        ed->type = usb_pipetype (pipe);
        ohci_dev.ed_cnt++;
    }
    ed->hwINFO = m32_swap (usb_pipedevice (pipe)
    | usb_pipeendpoint (pipe) << 7
    | (usb_pipeisoc (pipe)? 0x8000: 0)
    | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
    | usb_pipeslow (pipe) << 13
    | usb_maxpacket (usb_dev, pipe) << 16);
    return ed_ret;
}


/*-------------------------------------------------------------------------*
 * TD handling functions
 *-------------------------------------------------------------------------*/
/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
static void td_fill (ohci_t *ohci, unsigned int info,
void *data, int len,
struct usb_device *dev, int index, urb_priv_t *urb_priv)
{
    volatile td_t  *td, *td_pt;
    //#define OHCI_FILL_TRACE
    #ifdef OHCI_FILL_TRACE
    //int i;
    #endif
    if (index > urb_priv->length) 
    {
        err("index > length");
        return;
    }
    /* use this td as the next dummy */
    td_pt = urb_priv->td [index];
    td_pt->hwNextTD = 0;
    /* fill the old dummy TD */
    td = urb_priv->td [index] = (td_t *)(m32_swap (urb_priv->ed->hwTailP) & ~0xf);
    td->ed = urb_priv->ed;
    td->next_dl_td = NULL;
    td->index = index;
    td->data = (U32)data;
    #ifdef OHCI_FILL_TRACE
    //if ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe)) {
    //	for (i = 0; i < len; i++)
    //	s_UartPrint("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]);
    //	s_UartPrint("\n");
    //}
    //if ((usb_pipetype(urb_priv->pipe) == PIPE_CONTROL) && usb_pipeout(urb_priv->pipe)) {
    //	for (i = 0; i < len; i++)
    //	s_UartPrint("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]);
    //	s_UartPrint("\n");
    //}
    #endif
    if (!len)
    data = 0;
    td->hwINFO = m32_swap (info);
    td->hwCBP = m32_swap (data);
    if (data)
    td->hwBE = m32_swap (((int)data + len - 1));
    else
    td->hwBE = 0;
    td->hwNextTD = m32_swap (td_pt);
    /* append to queue */
    td->ed->hwTailP = td->hwNextTD;
}


/*-------------------------------------------------------------------------*/
/* prepare all TDs of a transfer */
static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
{
    ohci_t *ohci = &gohci;
    int data_len = transfer_len;
    void *data;
    int cnt = 0;
    U32 info = 0;
    unsigned int toggle = 0,temp;
    /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
    if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) 
    {
        toggle = TD_T_TOGGLE;
        //dbg("TD_T_TOGGLE  data_len=%d\n",data_len);
    } 
    else 
    {
        toggle = TD_T_DATA0;
        usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1);
        //dbg("TD_T_DATA0  data_len=%d\n",data_len);
    }
    urb->td_cnt = 0;
    if (data_len)
    data = buffer;
    else
    data = 0;
    switch (usb_pipetype (pipe)) 
    {
    case PIPE_BULK:
        info = usb_pipeout (pipe)?
        TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
        while(data_len > 4096) 
        {
            td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb);
            (int)data += 4096; data_len -= 4096; cnt++;
        }
        info = usb_pipeout (pipe)?
        TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
        td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb);
        cnt++;
        if (!ohci->sleeping)
        {
            writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
        }
        break;
    case PIPE_CONTROL:
        info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
        td_fill (ohci, info, setup, 8, dev, cnt++, urb);
        if (data_len > 0) 
        {
            info = usb_pipeout (pipe)?
            TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
            /* NOTE:  mishandles transfers >8K, some >4K */
            td_fill (ohci, info, data, data_len, dev, cnt++, urb);
        }
        info = usb_pipeout (pipe)?
        TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
        td_fill (ohci, info, data, 0, dev, cnt++, urb);
        if (!ohci->sleeping)
        {
            //dbg("\nstep2:");
            writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
            //writel (OHCI_CLF, &ohci->regs->cmdstatus);
            temp=rHcCommonStatus;
        }
        dbg("\nstep3: cmd=%04x %04x",rHcCommonStatus,temp);
        break;
    }
    if (urb->length != cnt)
    dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
}


/*-------------------------------------------------------------------------*
 * Done List handling functions
 *-------------------------------------------------------------------------*/
/* calculate the transfer length and update the urb */
static void dl_transfer_length(td_t * td)
{
    U32 tdINFO, tdBE, tdCBP;
    urb_priv_t *lurb_priv = &urb_priv;
    tdINFO = m32_swap (td->hwINFO);
    tdBE   = m32_swap (td->hwBE);
    tdCBP  = m32_swap (td->hwCBP);
    if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL &&
    ((td->index == 0) || (td->index == lurb_priv->length - 1)))) 
    {
        if (tdBE != 0) 
        {
            if (td->hwCBP == 0)
            lurb_priv->actual_length += tdBE - td->data + 1;
            else
            lurb_priv->actual_length += tdCBP - td->data;
        }
    }
}


/*-------------------------------------------------------------------------*/
/* replies to the request have to be on a FIFO basis so
 * we reverse the reversed done-list */
static td_t * dl_reverse_done_list (ohci_t *ohci)
{
    U32 td_list_hc;
    td_t *td_rev = NULL;
    td_t *td_list = NULL;
    urb_priv_t *lurb_priv = NULL;
    td_list_hc = m32_swap (ohci->hcca->done_head) & 0xfffffff0;
    ohci->hcca->done_head = 0;
    while (td_list_hc) 
    {
        td_list = (td_t *)td_list_hc;
        if (TD_CC_GET (m32_swap (td_list->hwINFO))) 
        {
            lurb_priv = &urb_priv;
            dbg(" USB-error/status: %x : %p",
            TD_CC_GET (m32_swap (td_list->hwINFO)), td_list);
            if (td_list->ed->hwHeadP & m32_swap (0x1)) 
            {
                if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) 
                {
                    td_list->ed->hwHeadP =
                    (lurb_priv->td[lurb_priv->length - 1]->hwNextTD & m32_swap (0xfffffff0)) |
                    (td_list->ed->hwHeadP & m32_swap (0x2));
                    lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
                } 
                else
                td_list->ed->hwHeadP &= m32_swap (0xfffffff2);
            }
        }
        td_list->next_dl_td = td_rev;
        td_rev = td_list;
        td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0;
    }
    return td_list;
}


/*-------------------------------------------------------------------------*/
/* td done list */
static int dl_done_list (ohci_t *ohci, td_t *td_list)
{
    td_t *td_list_next = NULL;
    ed_t *ed;
    int cc = 0;
    int stat = 0;
    /* urb_t *urb; */
    urb_priv_t *lurb_priv;
    U32 tdINFO, edHeadP, edTailP;
    while (td_list) 
    {
        td_list_next = td_list->next_dl_td;
        lurb_priv = &urb_priv;
        tdINFO = m32_swap (td_list->hwINFO);
        ed = td_list->ed;
        dl_transfer_length(td_list);
        /* error code of transfer */
        cc = TD_CC_GET (tdINFO);
        if (cc != 0) 
        {
            dbg("ConditionCode %#x", cc);
            stat = cc_to_error[cc];
        }
        /* see if this done list makes for all TD's of current URB,
        		 * and mark the URB finished if so */
        if (++(lurb_priv->td_cnt) == lurb_priv->length) 
        {
            if ((ed->state & (ED_OPER | ED_UNLINK)))
            urb_finished = 1;
            else
            dbg("dl_done_list: strange.., ED state %x, ed->state\n");
        } 
        else
        dbg("dl_done_list: processing TD %x, len %x\n", lurb_priv->td_cnt,
        lurb_priv->length);
        if (ed->state != ED_NEW) 
        {
            edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0;
            edTailP = m32_swap (ed->hwTailP);
            /* unlink eds if they are not busy */
            if ((edHeadP == edTailP) && (ed->state == ED_OPER))
            ep_unlink (ohci, ed);
        }
        td_list = td_list_next;
    }
    return stat;
}


/*-------------------------------------------------------------------------*
 * Virtual Root Hub
 *-------------------------------------------------------------------------*/
/* Device descriptor */
static U8 root_hub_dev_des[] =
{
    0x12,       /*  __u8  bLength; */
    0x01,       /*  __u8  bDescriptorType; Device */
    0x10,	 /*  __u16 bcdUSB; v1.1 */
    0x01,
    0x09,	 /*  __u8  bDeviceClass; HUB_CLASSCODE */
    0x00,	 /*  __u8  bDeviceSubClass; */
    0x00,       /*  __u8  bDeviceProtocol; */
    0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
    0x00,       /*  __u16 idVendor; */
    0x00,
    0x00,       /*  __u16 idProduct; */
    0x00,
    0x00,       /*  __u16 bcdDevice; */
    0x00,
    0x00,       /*  __u8  iManufacturer; */
    0x01,       /*  __u8  iProduct; */
    0x00,       /*  __u8  iSerialNumber; */
    0x01        /*  __u8  bNumConfigurations; */
};


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -