📄 usb-ohci.c
字号:
}
urb_priv->td_cnt = 0;
if (data_len)
{
data = pci_map_single (ohci->ohci_dev,
urb->transfer_buffer, data_len,
usb_pipeout (urb->pipe)
? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE
);
}
else
data = 0;
switch (usb_pipetype (urb->pipe))
{
case PIPE_BULK:
/*
if (usb_pipeout (urb->pipe))
{
printk(KERN_CRIT " ===> BULK OUT URB 0x%x\n", urb);
submit_urb_out_debug();
}
else
printk(KERN_CRIT " ===> BULK IN URB 0x%x\n", urb);
*/
info = usb_pipeout (urb->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, urb, cnt);
data += 4096; data_len -= 4096; cnt++;
}
info = usb_pipeout (urb->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, urb, cnt);
cnt++;
/* If the transfer size is multiple of the pipe mtu,
* we may need an extra TD to create a empty frame
* Note : another way to check this condition is
* to test if(urb_priv->length > cnt) - Jean II */
if ((urb->transfer_flags & USB_ZERO_PACKET) &&
usb_pipeout (urb->pipe) &&
(urb->transfer_buffer_length != 0) &&
((urb->transfer_buffer_length % maxps) == 0))
{
td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), 0, 0, urb, cnt);
cnt++;
}
if (!ohci->sleeping)
{
wmb();
Ohci_WriteReg (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
}
break;
case PIPE_INTERRUPT:
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;
td_fill (ohci, info, data, data_len, urb, cnt++);
break;
case PIPE_CONTROL:
info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
td_fill (ohci, info,
pci_map_single (ohci->ohci_dev,
urb->setup_packet, 8,
PCI_DMA_TODEVICE),
8, urb, cnt++);
if (data_len > 0) {
info = usb_pipeout (urb->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, urb, cnt++);
}
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
td_fill (ohci, info, data, 0, urb, cnt++);
if (!ohci->sleeping) {
wmb();
Ohci_WriteReg (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
}
break;
case PIPE_ISOCHRONOUS:
// printk(KERN_CRIT "+ td_submit_urb: %x \n", urb);
for (cnt = 0; cnt < urb->number_of_packets; cnt++)
{
td_fill (ohci, TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff),
data + urb->iso_frame_desc[cnt].offset,
urb->iso_frame_desc[cnt].length, urb, cnt);
}
break;
}
if (urb_priv->length != cnt)
dbg("TD LENGTH %d != CNT %d", urb_priv->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;
__u16 tdPSW;
urb_t * urb = td->urb;
urb_priv_t * urb_priv = urb->hcpriv;
int dlen = 0;
int cc = 0;
tdINFO = le32_to_cpup (&td->hwINFO);
tdBE = le32_to_cpup (&td->hwBE);
tdCBP = le32_to_cpup (&td->hwCBP);
if (tdINFO & TD_ISO) {
tdPSW = le16_to_cpu (td->hwPSW[0]);
cc = (tdPSW >> 12) & 0xF;
if (cc < 0xE) {
if (usb_pipeout(urb->pipe)) {
dlen = urb->iso_frame_desc[td->index].length;
} else {
dlen = tdPSW & 0x3ff;
}
urb->actual_length += dlen;
urb->iso_frame_desc[td->index].actual_length = dlen;
if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
cc = TD_CC_NOERROR;
urb->iso_frame_desc[td->index].status = cc_to_error[cc];
}
} else { /* BULK, INT, CONTROL DATA */
if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL &&
((td->index == 0) || (td->index == urb_priv->length - 1)))) {
if (tdBE != 0) {
if (td->hwCBP == 0)
urb->actual_length += tdBE - td->data_dma + 1;
else
urb->actual_length += tdCBP - td->data_dma;
}
}
}
}
/* handle an urb that is being unlinked */
static void dl_del_urb (urb_t * urb)
{
wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;
urb_rm_priv_locked (urb);
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
urb->status = -ECONNRESET;
if (urb->complete)
urb->complete (urb);
} else {
urb->status = -ENOENT;
/* unblock sohci_unlink_urb */
if (wait_head)
wake_up (wait_head);
}
}
/*-------------------------------------------------------------------------*/
/* 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 * urb_priv = NULL;
unsigned long flags;
spin_lock_irqsave (&usb_ed_lock, flags);
td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
ohci->hcca->done_head = 0;
while (td_list_hc) {
td_list = dma_to_td (ohci, td_list_hc);
if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
dbg(" USB-error/status: %x : %p",
TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list);
if (td_list->ed->hwHeadP & cpu_to_le32 (0x1)) {
if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {
td_list->ed->hwHeadP =
(urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |
(td_list->ed->hwHeadP & cpu_to_le32 (0x2));
urb_priv->td_cnt += urb_priv->length - td_list->index - 1;
} else
td_list->ed->hwHeadP &= cpu_to_le32 (0xfffffff2);
}
}
td_list->next_dl_td = td_rev;
td_rev = td_list;
td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;
}
spin_unlock_irqrestore (&usb_ed_lock, flags);
return td_list;
}
/*-------------------------------------------------------------------------*/
/* there are some pending requests to remove
* - some of the eds (if ed->state & ED_DEL (set by sohci_free_dev)
* - some URBs/TDs if urb_priv->state == URB_DEL */
static void dl_del_list (ohci_t * ohci, unsigned int frame)
{
unsigned long flags;
ed_t * ed;
__u32 edINFO;
__u32 tdINFO;
td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
__u32 * td_p;
int ctrl = 0, bulk = 0;
spin_lock_irqsave (&usb_ed_lock, flags);
for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
edINFO = le32_to_cpup (&ed->hwINFO);
td_p = &ed->hwHeadP;
for (td = tdHeadP; td != tdTailP; td = td_next) {
urb_t * urb = td->urb;
urb_priv_t * urb_priv = td->urb->hcpriv;
td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
tdINFO = le32_to_cpup (&td->hwINFO);
if (TD_CC_GET (tdINFO) < 0xE)
dl_transfer_length (td);
*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
/* URB is done; clean up */
if (++(urb_priv->td_cnt) == urb_priv->length)
dl_del_urb (urb);
} else {
td_p = &td->hwNextTD;
}
}
if (ed->state & ED_DEL) { /* set by sohci_free_dev */
struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);
td_free (ohci, tdTailP); /* free dummy td */
ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);
ed->state = ED_NEW;
hash_free_ed(ohci, ed);
/* if all eds are removed wake up sohci_free_dev */
if (!--dev->ed_cnt) {
wait_queue_head_t *wait_head = dev->wait;
dev->wait = 0;
if (wait_head)
wake_up (wait_head);
}
} else {
ed->state &= ~ED_URB_DEL;
tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
if (tdHeadP == tdTailP) {
if (ed->state == ED_OPER)
ep_unlink(ohci, ed);
td_free (ohci, tdTailP);
ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);
ed->state = ED_NEW;
hash_free_ed(ohci, ed);
--(usb_to_ohci (ohci->dev[edINFO & 0x7F]))->ed_cnt;
} else
ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
}
switch (ed->type) {
case PIPE_CONTROL:
ctrl = 1;
break;
case PIPE_BULK:
bulk = 1;
break;
}
}
/* maybe reenable control and bulk lists */
if (!ohci->disabled) {
if (ctrl) /* reset control list */
Ohci_WriteReg (0, &ohci->regs->ed_controlcurrent);
if (bulk) /* reset bulk list */
Ohci_WriteReg (0, &ohci->regs->ed_bulkcurrent);
if (!ohci->ed_rm_list[!frame] && !ohci->sleeping) {
if (ohci->ed_controltail)
ohci->hc_control |= OHCI_CTRL_CLE;
if (ohci->ed_bulktail)
ohci->hc_control |= OHCI_CTRL_BLE;
Ohci_WriteReg (ohci->hc_control, &ohci->regs->control);
}
}
ohci->ed_rm_list[frame] = NULL;
spin_unlock_irqrestore (&usb_ed_lock, flags);
}
/*-------------------------------------------------------------------------*/
void urb_return_debug()
{
}
/* td done list */
static void dl_done_list (ohci_t * ohci, td_t * td_list)
{
td_t * td_list_next = NULL;
ed_t * ed;
int cc = 0;
urb_t * urb;
urb_priv_t * urb_priv;
__u32 tdINFO, edHeadP, edTailP;
unsigned long flags;
//ying
int i;
unsigned int pipe;
while (td_list)
{
td_list_next = td_list->next_dl_td;
urb = td_list->urb;
urb_priv = urb->hcpriv;
tdINFO = le32_to_cpup (&td_list->hwINFO);
ed = td_list->ed;
dl_transfer_length(td_list);
/* error code of transfer */
cc = TD_CC_GET (tdINFO);
if (cc == TD_CC_STALL)
usb_endpoint_halt(urb->dev,
usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe));
if (!(urb->transfer_flags & USB_DISABLE_SPD)
&& (cc == TD_DATAUNDERRUN))
cc = TD_CC_NOERROR;
if (++(urb_priv->td_cnt) == urb_priv->length)
{
if ((ed->state & (ED_OPER | ED_UNLINK))
&& (urb_priv->state != URB_DEL))
{
urb->status = cc_to_error[cc];
/*
printk(KERN_CRIT " <=== URB 0x%x, status %d, trans_len %d, actual_len %d, ed:desc 0x%x \n",
urb,
urb->status,
urb->transfer_buffer_length,
urb->actual_length,
ed->hwINFO);
//ying
pipe = urb->pipe;
if (( usb_pipetype (pipe) == PIPE_CONTROL) && (urb->actual_length == 0x12))
{
urb_return_debug();
for ( i=0; i< urb->actual_length; i++)
{
printk(KERN_CRIT "Offset[%d]:%x \n", i, *((unsigned char*)urb->transfer_buffer + i));
}
printk(KERN_CRIT "\n");
}
//end of testing
*/
sohci_return_urb (ohci, urb);
}
else
{
spin_lock_irqsave (&usb_ed_lock, flags);
dl_del_urb (urb);
spin_unlock_irqrestore (&usb_ed_lock, flags);
}
}
spin_lock_irqsave (&usb_ed_lock, flags);
if (ed->state != ED_NEW)
{
edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
edTailP = le32_to_cpup (&ed->hwTailP);
/* unlink eds if they are not busy */
if ((edHeadP == edTailP) && (ed->state == ED_OPER))
ep_unlink (ohci, ed);
}
spin_unlock_irqrestore (&usb_ed_lock, flags);
td_list = td_list_next;
}
}
/*-------------------------------------------------------------------------*
* 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; */
0x02, /* __u8 iProduct; */
0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -