r8a66597-hcd.c
来自「linux 内核源代码」· C语言 代码 · 共 2,241 行 · 第 1/4 页
C
2,241 行
if (info->pipenum == 0) return; r8a66597_bset(r8a66597, ACLRM, get_pipectr_addr(info->pipenum)); r8a66597_bclr(r8a66597, ACLRM, get_pipectr_addr(info->pipenum)); r8a66597_write(r8a66597, info->pipenum, PIPESEL); if (!info->dir_in) val |= R8A66597_DIR; if (info->type == R8A66597_BULK && info->dir_in) val |= R8A66597_DBLB | R8A66597_SHTNAK; val |= info->type | info->epnum; r8a66597_write(r8a66597, val, PIPECFG); r8a66597_write(r8a66597, (info->buf_bsize << 10) | (info->bufnum), PIPEBUF); r8a66597_write(r8a66597, make_devsel(info->address) | info->maxpacket, PIPEMAXP); if (info->interval) info->interval--; r8a66597_write(r8a66597, info->interval, PIPEPERI);}/* this function must be called with interrupt disabled */static void pipe_setting(struct r8a66597 *r8a66597, struct r8a66597_td *td){ struct r8a66597_pipe_info *info; struct urb *urb = td->urb; if (td->pipenum > 0) { info = &td->pipe->info; cfifo_change(r8a66597, 0); pipe_buffer_setting(r8a66597, info); if (!usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) && !usb_pipecontrol(urb->pipe)) { r8a66597_pipe_toggle(r8a66597, td->pipe, 0); pipe_toggle_set(r8a66597, td->pipe, urb, 0); clear_all_buffer(r8a66597, td->pipe); usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 1); } pipe_toggle_restore(r8a66597, td->pipe, urb); }}/* this function must be called with interrupt disabled */static u16 get_empty_pipenum(struct r8a66597 *r8a66597, struct usb_endpoint_descriptor *ep){ u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min; memset(array, 0, sizeof(array)); switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_BULK: if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) array[i++] = 4; else { array[i++] = 3; array[i++] = 5; } break; case USB_ENDPOINT_XFER_INT: if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { array[i++] = 6; array[i++] = 7; array[i++] = 8; } else array[i++] = 9; break; case USB_ENDPOINT_XFER_ISOC: if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) array[i++] = 2; else array[i++] = 1; break; default: err("Illegal type"); return 0; } i = 1; min = array[0]; while (array[i] != 0) { if (r8a66597->pipe_cnt[min] > r8a66597->pipe_cnt[array[i]]) min = array[i]; i++; } return min;}static u16 get_r8a66597_type(__u8 type){ u16 r8a66597_type; switch (type) { case USB_ENDPOINT_XFER_BULK: r8a66597_type = R8A66597_BULK; break; case USB_ENDPOINT_XFER_INT: r8a66597_type = R8A66597_INT; break; case USB_ENDPOINT_XFER_ISOC: r8a66597_type = R8A66597_ISO; break; default: err("Illegal type"); r8a66597_type = 0x0000; break; } return r8a66597_type;}static u16 get_bufnum(u16 pipenum){ u16 bufnum = 0; if (pipenum == 0) bufnum = 0; else if (check_bulk_or_isoc(pipenum)) bufnum = 8 + (pipenum - 1) * R8A66597_BUF_BSIZE*2; else if (check_interrupt(pipenum)) bufnum = 4 + (pipenum - 6); else err("Illegal pipenum (%d)", pipenum); return bufnum;}static u16 get_buf_bsize(u16 pipenum){ u16 buf_bsize = 0; if (pipenum == 0) buf_bsize = 3; else if (check_bulk_or_isoc(pipenum)) buf_bsize = R8A66597_BUF_BSIZE - 1; else if (check_interrupt(pipenum)) buf_bsize = 0; else err("Illegal pipenum (%d)", pipenum); return buf_bsize;}/* this function must be called with interrupt disabled */static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597, struct r8a66597_device *dev, struct r8a66597_pipe *pipe, struct urb *urb){ int i; struct r8a66597_pipe_info *info = &pipe->info; if ((pipe->info.pipenum != 0) && (info->type != R8A66597_INT)) { for (i = 0; i < R8A66597_MAX_DMA_CHANNEL; i++) { if ((r8a66597->dma_map & (1 << i)) != 0) continue; info("address %d, EndpointAddress 0x%02x use DMA FIFO", usb_pipedevice(urb->pipe), info->dir_in ? USB_ENDPOINT_DIR_MASK + info->epnum : info->epnum); r8a66597->dma_map |= 1 << i; dev->dma_map |= 1 << i; set_pipe_reg_addr(pipe, i); cfifo_change(r8a66597, 0); r8a66597_mdfy(r8a66597, MBW | pipe->info.pipenum, MBW | CURPIPE, pipe->fifosel); r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE, pipe->info.pipenum); r8a66597_bset(r8a66597, BCLR, pipe->fifoctr); break; } }}/* this function must be called with interrupt disabled */static void enable_r8a66597_pipe(struct r8a66597 *r8a66597, struct urb *urb, struct usb_host_endpoint *hep, struct r8a66597_pipe_info *info){ struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb); struct r8a66597_pipe *pipe = hep->hcpriv; dbg("enable_pipe:"); pipe->info = *info; set_pipe_reg_addr(pipe, R8A66597_PIPE_NO_DMA); r8a66597->pipe_cnt[pipe->info.pipenum]++; dev->pipe_cnt[pipe->info.pipenum]++; enable_r8a66597_pipe_dma(r8a66597, dev, pipe, urb);}/* this function must be called with interrupt disabled */static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address){ struct r8a66597_td *td, *next; struct urb *urb; struct list_head *list = &r8a66597->pipe_queue[pipenum]; if (list_empty(list)) return; list_for_each_entry_safe(td, next, list, queue) { if (!td) continue; if (td->address != address) continue; urb = td->urb; list_del(&td->queue); kfree(td); if (urb) { usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); spin_unlock(&r8a66597->lock); usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb, -ENODEV); spin_lock(&r8a66597->lock); } break; }}/* this function must be called with interrupt disabled */static void disable_r8a66597_pipe_all(struct r8a66597 *r8a66597, struct r8a66597_device *dev){ int check_ep0 = 0; u16 pipenum; if (!dev) return; for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { if (!dev->pipe_cnt[pipenum]) continue; if (!check_ep0) { check_ep0 = 1; force_dequeue(r8a66597, 0, dev->address); } r8a66597->pipe_cnt[pipenum] -= dev->pipe_cnt[pipenum]; dev->pipe_cnt[pipenum] = 0; force_dequeue(r8a66597, pipenum, dev->address); } dbg("disable_pipe"); r8a66597->dma_map &= ~(dev->dma_map); dev->dma_map = 0;}/* this function must be called with interrupt disabled */static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb, struct usb_host_endpoint *hep, struct usb_endpoint_descriptor *ep){ struct r8a66597_pipe_info info; info.pipenum = get_empty_pipenum(r8a66597, ep); info.address = get_urb_to_r8a66597_addr(r8a66597, urb); info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; info.maxpacket = le16_to_cpu(ep->wMaxPacketSize); info.type = get_r8a66597_type(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); info.bufnum = get_bufnum(info.pipenum); info.buf_bsize = get_buf_bsize(info.pipenum); info.interval = ep->bInterval; if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) info.dir_in = 1; else info.dir_in = 0; enable_r8a66597_pipe(r8a66597, urb, hep, &info);}static void init_pipe_config(struct r8a66597 *r8a66597, struct urb *urb){ struct r8a66597_device *dev; dev = get_urb_to_r8a66597_dev(r8a66597, urb); dev->state = USB_STATE_CONFIGURED;}static void pipe_irq_enable(struct r8a66597 *r8a66597, struct urb *urb, u16 pipenum){ if (pipenum == 0 && usb_pipeout(urb->pipe)) enable_irq_empty(r8a66597, pipenum); else enable_irq_ready(r8a66597, pipenum); if (!usb_pipeisoc(urb->pipe)) enable_irq_nrdy(r8a66597, pipenum);}static void pipe_irq_disable(struct r8a66597 *r8a66597, u16 pipenum){ disable_irq_ready(r8a66597, pipenum); disable_irq_nrdy(r8a66597, pipenum);}/* this function must be called with interrupt disabled */static void r8a66597_usb_preconnect(struct r8a66597 *r8a66597, int port){ r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION) | (1 << USB_PORT_FEAT_C_CONNECTION); r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port)); r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));}/* this function must be called with interrupt disabled */static void r8a66597_usb_connect(struct r8a66597 *r8a66597, int port){ u16 speed = get_rh_usb_speed(r8a66597, port); struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; if (speed == HSMODE) rh->port |= (1 << USB_PORT_FEAT_HIGHSPEED); else if (speed == LSMODE) rh->port |= (1 << USB_PORT_FEAT_LOWSPEED); rh->port &= ~(1 << USB_PORT_FEAT_RESET); rh->port |= 1 << USB_PORT_FEAT_ENABLE;}/* this function must be called with interrupt disabled */static void r8a66597_usb_disconnect(struct r8a66597 *r8a66597, int port){ struct r8a66597_device *dev = r8a66597->root_hub[port].dev; r8a66597->root_hub[port].port &= ~(1 << USB_PORT_FEAT_CONNECTION); r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_C_CONNECTION); disable_r8a66597_pipe_all(r8a66597, dev); free_usb_address(r8a66597, dev); r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));}/* this function must be called with interrupt disabled */static void prepare_setup_packet(struct r8a66597 *r8a66597, struct r8a66597_td *td){ int i; u16 *p = (u16 *)td->urb->setup_packet; unsigned long setup_addr = USBREQ; r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket, DCPMAXP); r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1); for (i = 0; i < 4; i++) { r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr); setup_addr += 2; } r8a66597_write(r8a66597, SUREQ, DCPCTR);}/* this function must be called with interrupt disabled */static void prepare_packet_read(struct r8a66597 *r8a66597, struct r8a66597_td *td){ struct urb *urb = td->urb; if (usb_pipecontrol(urb->pipe)) { r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG); r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL); r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); if (urb->actual_length == 0) { r8a66597_pipe_toggle(r8a66597, td->pipe, 1); r8a66597_write(r8a66597, BCLR, CFIFOCTR); } pipe_irq_disable(r8a66597, td->pipenum); pipe_start(r8a66597, td->pipe); pipe_irq_enable(r8a66597, urb, td->pipenum); } else { if (urb->actual_length == 0) { pipe_irq_disable(r8a66597, td->pipenum); pipe_setting(r8a66597, td); pipe_stop(r8a66597, td->pipe); r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS); if (td->pipe->pipetre) { r8a66597_write(r8a66597, TRCLR, td->pipe->pipetre); r8a66597_write(r8a66597, (urb->transfer_buffer_length + td->maxpacket - 1) / td->maxpacket, td->pipe->pipetrn); r8a66597_bset(r8a66597, TRENB, td->pipe->pipetre); } pipe_start(r8a66597, td->pipe); pipe_irq_enable(r8a66597, urb, td->pipenum); } }}/* this function must be called with interrupt disabled */static void prepare_packet_write(struct r8a66597 *r8a66597, struct r8a66597_td *td){ u16 tmp; struct urb *urb = td->urb; if (usb_pipecontrol(urb->pipe)) { pipe_stop(r8a66597, td->pipe); r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG); r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL); r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); if (urb->actual_length == 0) { r8a66597_pipe_toggle(r8a66597, td->pipe, 1); r8a66597_write(r8a66597, BCLR, CFIFOCTR); } } else { if (urb->actual_length == 0) pipe_setting(r8a66597, td); if (td->pipe->pipetre) r8a66597_bclr(r8a66597, TRENB, td->pipe->pipetre); } r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS); fifo_change_from_pipe(r8a66597, td->pipe); tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); if (unlikely((tmp & FRDY) == 0)) pipe_irq_enable(r8a66597, urb, td->pipenum); else packet_write(r8a66597, td->pipenum); pipe_start(r8a66597, td->pipe);}/* this function must be called with interrupt disabled */static void prepare_status_packet(struct r8a66597 *r8a66597, struct r8a66597_td *td){ struct urb *urb = td->urb; r8a66597_pipe_toggle(r8a66597, td->pipe, 1); pipe_stop(r8a66597, td->pipe); if (urb->setup_packet[0] & USB_ENDPOINT_DIR_MASK) { r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG); r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL); r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); r8a66597_write(r8a66597, ~BEMP0, BEMPSTS); r8a66597_write(r8a66597, BCLR, CFIFOCTR); r8a66597_write(r8a66597, BVAL, CFIFOCTR); enable_irq_empty(r8a66597, 0); } else { r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG); r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL); r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); r8a66597_write(r8a66597, BCLR, CFIFOCTR); enable_irq_ready(r8a66597, 0); } enable_irq_nrdy(r8a66597, 0); pipe_start(r8a66597, td->pipe);}static int is_set_address(unsigned char *setup_packet){ if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) && setup_packet[1] == USB_REQ_SET_ADDRESS) return 1; else return 0;}/* this function must be called with interrupt disabled */static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td){ BUG_ON(!td); switch (td->type) { case USB_PID_SETUP: if (is_set_address(td->urb->setup_packet)) { td->set_address = 1; td->urb->setup_packet[2] = alloc_usb_address(r8a66597, td->urb); if (td->urb->setup_packet[2] == 0) return -EPIPE; } prepare_setup_packet(r8a66597, td); break; case USB_PID_IN: prepare_packet_read(r8a66597, td); break; case USB_PID_OUT: prepare_packet_write(r8a66597, td); break; case USB_PID_ACK: prepare_status_packet(r8a66597, td); break; default: err("invalid type."); break; } return 0;}static int check_transfer_finish(struct r8a66597_td *td, struct urb *urb){ if (usb_pipeisoc(urb->pipe)) { if (urb->number_of_packets == td->iso_cnt) return 1; } /* control or bulk or interrupt */ if ((urb->transfer_buffer_length <= urb->actual_length) || (td->short_packet) || (td->zero_packet)) return 1; return 0;}/* this function must be called with interrupt disabled */static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td){ unsigned long time; BUG_ON(!td); if (!list_empty(&r8a66597->pipe_queue[td->pipenum]) && !usb_pipecontrol(td->urb->pipe) && usb_pipein(td->urb->pipe)) { r8a66597->timeout_map |= 1 << td->pipenum; switch (usb_pipetype(td->urb->pipe)) { case PIPE_INTERRUPT: case PIPE_ISOCHRONOUS: time = 30; break; default: time = 300; break; } mod_timer(&r8a66597->td_timer[td->pipenum], jiffies + msecs_to_jiffies(time)); }}/* this function must be called with interrupt disabled */static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, u16 pipenum, struct urb *urb, int status)__releases(r8a66597->lock) __acquires(r8a66597->lock)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?