?? hc_crisv10.c
字號:
info("Dumping urb list for epid %d", epid); list_for_each_safe(entry, tmp, &urb_list[epid]) { urb_entry = list_entry(entry, urb_entry_t, list); info(" entry %d, urb = 0x%lx", i, (unsigned long)urb_entry->urb); }}static void init_rx_buffers(void);static int etrax_rh_unlink_urb(struct urb *urb);static void etrax_rh_send_irq(struct urb *urb);static void etrax_rh_init_int_timer(struct urb *urb);static void etrax_rh_int_timer_do(unsigned long ptr);static int etrax_usb_setup_epid(struct urb *urb);static int etrax_usb_lookup_epid(struct urb *urb);static int etrax_usb_allocate_epid(void);static void etrax_usb_free_epid(int epid);static int etrax_remove_from_sb_list(struct urb *urb);static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, unsigned mem_flags, dma_addr_t *dma);static void etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma);static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid);static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid);static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid);static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid);static int etrax_usb_submit_bulk_urb(struct urb *urb);static int etrax_usb_submit_ctrl_urb(struct urb *urb);static int etrax_usb_submit_intr_urb(struct urb *urb);static int etrax_usb_submit_isoc_urb(struct urb *urb);static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags);static int etrax_usb_unlink_urb(struct urb *urb, int status);static int etrax_usb_get_frame_number(struct usb_device *usb_dev);static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc);static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc);static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc);static void etrax_usb_hc_interrupt_bottom_half(void *data);static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data);/* The following is a list of interrupt handlers for the host controller interrupts we use. They are called from etrax_usb_hc_interrupt_bottom_half. */static void etrax_usb_hc_isoc_eof_interrupt(void);static void etrax_usb_hc_bulk_eot_interrupt(int timer_induced);static void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg);static void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg);static void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg);static int etrax_rh_submit_urb (struct urb *urb);/* Forward declaration needed because they are used in the rx interrupt routine. */static void etrax_usb_complete_urb(struct urb *urb, int status);static void etrax_usb_complete_bulk_urb(struct urb *urb, int status);static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status);static void etrax_usb_complete_intr_urb(struct urb *urb, int status);static void etrax_usb_complete_isoc_urb(struct urb *urb, int status);static int etrax_usb_hc_init(void);static void etrax_usb_hc_cleanup(void);static struct usb_operations etrax_usb_device_operations ={ .get_frame_number = etrax_usb_get_frame_number, .submit_urb = etrax_usb_submit_urb, .unlink_urb = etrax_usb_unlink_urb, .buffer_alloc = etrax_usb_buffer_alloc, .buffer_free = etrax_usb_buffer_free};/* Note that these functions are always available in their "__" variants, for use in error situations. The "__" missing variants are controlled by the USB_DEBUG_DESC/ USB_DEBUG_URB macros. */static void __dump_urb(struct urb* purb){ printk("\nurb :0x%08lx\n", (unsigned long)purb); printk("dev :0x%08lx\n", (unsigned long)purb->dev); printk("pipe :0x%08x\n", purb->pipe); printk("status :%d\n", purb->status); printk("transfer_flags :0x%08x\n", purb->transfer_flags); printk("transfer_buffer :0x%08lx\n", (unsigned long)purb->transfer_buffer); printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length); printk("actual_length :%d\n", purb->actual_length); printk("setup_packet :0x%08lx\n", (unsigned long)purb->setup_packet); printk("start_frame :%d\n", purb->start_frame); printk("number_of_packets :%d\n", purb->number_of_packets); printk("interval :%d\n", purb->interval); printk("error_count :%d\n", purb->error_count); printk("context :0x%08lx\n", (unsigned long)purb->context); printk("complete :0x%08lx\n\n", (unsigned long)purb->complete);}static void __dump_in_desc(volatile USB_IN_Desc_t *in){ printk("\nUSB_IN_Desc at 0x%08lx\n", (unsigned long)in); printk(" sw_len : 0x%04x (%d)\n", in->sw_len, in->sw_len); printk(" command : 0x%04x\n", in->command); printk(" next : 0x%08lx\n", in->next); printk(" buf : 0x%08lx\n", in->buf); printk(" hw_len : 0x%04x (%d)\n", in->hw_len, in->hw_len); printk(" status : 0x%04x\n\n", in->status);}static void __dump_sb_desc(volatile USB_SB_Desc_t *sb){ char tt = (sb->command & 0x30) >> 4; char *tt_string; switch (tt) { case 0: tt_string = "zout"; break; case 1: tt_string = "in"; break; case 2: tt_string = "out"; break; case 3: tt_string = "setup"; break; default: tt_string = "unknown (weird)"; } printk("\n USB_SB_Desc at 0x%08lx\n", (unsigned long)sb); printk(" command : 0x%04x\n", sb->command); printk(" rem : %d\n", (sb->command & 0x3f00) >> 8); printk(" full : %d\n", (sb->command & 0x40) >> 6); printk(" tt : %d (%s)\n", tt, tt_string); printk(" intr : %d\n", (sb->command & 0x8) >> 3); printk(" eot : %d\n", (sb->command & 0x2) >> 1); printk(" eol : %d\n", sb->command & 0x1); printk(" sw_len : 0x%04x (%d)\n", sb->sw_len, sb->sw_len); printk(" next : 0x%08lx\n", sb->next); printk(" buf : 0x%08lx\n\n", sb->buf);}static void __dump_ep_desc(volatile USB_EP_Desc_t *ep){ printk("\nUSB_EP_Desc at 0x%08lx\n", (unsigned long)ep); printk(" command : 0x%04x\n", ep->command); printk(" ep_id : %d\n", (ep->command & 0x1f00) >> 8); printk(" enable : %d\n", (ep->command & 0x10) >> 4); printk(" intr : %d\n", (ep->command & 0x8) >> 3); printk(" eof : %d\n", (ep->command & 0x2) >> 1); printk(" eol : %d\n", ep->command & 0x1); printk(" hw_len : 0x%04x (%d)\n", ep->hw_len, ep->hw_len); printk(" next : 0x%08lx\n", ep->next); printk(" sub : 0x%08lx\n\n", ep->sub);}static inline void __dump_ep_list(int pipe_type){ volatile USB_EP_Desc_t *ep; volatile USB_EP_Desc_t *first_ep; volatile USB_SB_Desc_t *sb; switch (pipe_type) { case PIPE_BULK: first_ep = &TxBulkEPList[0]; break; case PIPE_CONTROL: first_ep = &TxCtrlEPList[0]; break; case PIPE_INTERRUPT: first_ep = &TxIntrEPList[0]; break; case PIPE_ISOCHRONOUS: first_ep = &TxIsocEPList[0]; break; default: warn("Cannot dump unknown traffic type"); return; } ep = first_ep; printk("\n\nDumping EP list...\n\n"); do { __dump_ep_desc(ep); /* Cannot phys_to_virt on 0 as it turns into 80000000, which is != 0. */ sb = ep->sub ? phys_to_virt(ep->sub) : 0; while (sb) { __dump_sb_desc(sb); sb = sb->next ? phys_to_virt(sb->next) : 0; } ep = (volatile USB_EP_Desc_t *)(phys_to_virt(ep->next)); } while (ep != first_ep);}static inline void __dump_ept_data(int epid){ unsigned long flags; __u32 r_usb_ept_data; if (epid < 0 || epid > 31) { printk("Cannot dump ept data for invalid epid %d\n", epid); return; } save_flags(flags); cli(); *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); r_usb_ept_data = *R_USB_EPT_DATA; restore_flags(flags); printk("\nR_USB_EPT_DATA = 0x%x for epid %d :\n", r_usb_ept_data, epid); if (r_usb_ept_data == 0) { /* No need for more detailed printing. */ return; } printk(" valid : %d\n", (r_usb_ept_data & 0x80000000) >> 31); printk(" hold : %d\n", (r_usb_ept_data & 0x40000000) >> 30); printk(" error_count_in : %d\n", (r_usb_ept_data & 0x30000000) >> 28); printk(" t_in : %d\n", (r_usb_ept_data & 0x08000000) >> 27); printk(" low_speed : %d\n", (r_usb_ept_data & 0x04000000) >> 26); printk(" port : %d\n", (r_usb_ept_data & 0x03000000) >> 24); printk(" error_code : %d\n", (r_usb_ept_data & 0x00c00000) >> 22); printk(" t_out : %d\n", (r_usb_ept_data & 0x00200000) >> 21); printk(" error_count_out : %d\n", (r_usb_ept_data & 0x00180000) >> 19); printk(" max_len : %d\n", (r_usb_ept_data & 0x0003f800) >> 11); printk(" ep : %d\n", (r_usb_ept_data & 0x00000780) >> 7); printk(" dev : %d\n", (r_usb_ept_data & 0x0000003f));}static inline void __dump_ept_data_list(void){ int i; printk("Dumping the whole R_USB_EPT_DATA list\n"); for (i = 0; i < 32; i++) { __dump_ept_data(i); }}#ifdef USB_DEBUG_DESC#define dump_in_desc(...) __dump_in_desc(...)#define dump_sb_desc(...) __dump_sb_desc(...)#define dump_ep_desc(...) __dump_ep_desc(...)#else#define dump_in_desc(...) do {} while (0)#define dump_sb_desc(...) do {} while (0)#define dump_ep_desc(...) do {} while (0)#endif#ifdef USB_DEBUG_URB#define dump_urb(x) __dump_urb(x)#else#define dump_urb(x) do {} while (0)#endifstatic void init_rx_buffers(void){ int i; DBFENTER; for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) { RxDescList[i].sw_len = RX_DESC_BUF_SIZE; RxDescList[i].command = 0; RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); RxDescList[i].hw_len = 0; RxDescList[i].status = 0; /* DMA IN cache bug. (struct etrax_dma_descr has the same layout as USB_IN_Desc for the relevant fields.) */ prepare_rx_descriptor((struct etrax_dma_descr*)&RxDescList[i]); } RxDescList[i].sw_len = RX_DESC_BUF_SIZE; RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes); RxDescList[i].next = virt_to_phys(&RxDescList[0]); RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); RxDescList[i].hw_len = 0; RxDescList[i].status = 0; myNextRxDesc = &RxDescList[0]; myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; *R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc); *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start); DBFEXIT;}static void init_tx_bulk_ep(void){ int i; DBFENTER; for (i = 0; i < (NBR_OF_EPIDS - 1); i++) { CHECK_ALIGN(&TxBulkEPList[i]); TxBulkEPList[i].hw_len = 0; TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i); TxBulkEPList[i].sub = 0; TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[i + 1]); /* Initiate two EPs, disabled and with the eol flag set. No need for any preserved epid. */ /* The first one has the intr flag set so we get an interrupt when the DMA channel is about to become disabled. */ CHECK_ALIGN(&TxBulkDummyEPList[i][0]); TxBulkDummyEPList[i][0].hw_len = 0; TxBulkDummyEPList[i][0].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) | IO_STATE(USB_EP_command, eol, yes) | IO_STATE(USB_EP_command, intr, yes)); TxBulkDummyEPList[i][0].sub = 0; TxBulkDummyEPList[i][0].next = virt_to_phys(&TxBulkDummyEPList[i][1]); /* The second one. */ CHECK_ALIGN(&TxBulkDummyEPList[i][1]); TxBulkDummyEPList[i][1].hw_len = 0; TxBulkDummyEPList[i][1].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) | IO_STATE(USB_EP_command, eol, yes)); TxBulkDummyEPList[i][1].sub = 0; /* The last dummy's next pointer is the same as the current EP's next pointer. */ TxBulkDummyEPList[i][1].next = virt_to_phys(&TxBulkEPList[i + 1]); } /* Configure the last one. */ CHECK_ALIGN(&TxBulkEPList[i]); TxBulkEPList[i].hw_len = 0; TxBulkEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) | IO_FIELD(USB_EP_command, epid, i)); TxBulkEPList[i].sub = 0; TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[0]); /* No need configuring dummy EPs for the last one as it will never be used for bulk traffic (i == INVALD_EPID at this point). */ /* Set up to start on the last EP so we will enable it when inserting traffic for the first time (imitating the situation where the DMA has stopped because there was no more traffic). */ *R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[i]); /* No point in starting the bulk channel yet. *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */ DBFEXIT;}static void init_tx_ctrl_ep(void){ int i; DBFENTER; for (i = 0; i < (NBR_OF_EPIDS - 1); i++) { CHECK_ALIGN(&TxCtrlEPList[i]); TxCtrlEPList[i].hw_len = 0; TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i); TxCtrlEPList[i].sub = 0; TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[i + 1]); } CHECK_ALIGN(&TxCtrlEPList[i]); TxCtrlEPList[i].hw_len = 0; TxCtrlEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) | IO_FIELD(USB_EP_command, epid, i)); TxCtrlEPList[i].sub = 0; TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[0]); *R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]); *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start); DBFEXIT;}static void init_tx_intr_ep(void){ int i; DBFENTER; /* Read comment at zout_buffer declaration for an explanation to this. */ TxIntrSB_zout.sw_len = 1; TxIntrSB_zout.next = 0; TxIntrSB_zout.buf = virt_to_phys(&zout_buffer[0]); TxIntrSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) | IO_STATE(USB_SB_command, tt, zout) | IO_STATE(USB_SB_command, full, yes) | IO_STATE(USB_SB_command, eot, yes) | IO_STATE(USB_SB_command, eol, yes)); for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) { CHECK_ALIGN(&TxIntrEPList[i]); TxIntrEPList[i].hw_len = 0; TxIntrEPList[i].command = (IO_STATE(USB_EP_command, eof, yes) | IO_STATE(USB_EP_command, enable, yes) | IO_FIELD(USB_EP_command, epid, INVALID_EPID)); TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[i + 1]); } CHECK_ALIGN(&TxIntrEPList[i]); TxIntrEPList[i].hw_len = 0; TxIntrEPList[i].command = (IO_STATE(USB_EP_command, eof, yes) | IO_STATE(USB_EP_command, eol, yes) | IO_STATE(USB_EP_command, enable, yes) | IO_FIELD(USB_EP_command, epid, INVALID_EPID)); TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[0]); *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]); *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); DBFEXIT;}static void init_tx_isoc_ep(void){ int i; DBFENTER; /* Read comment at zout_buffer declaration for an explanation to this. */ TxIsocSB_zout.sw_len = 1; TxIsocSB_zout.next = 0; TxIsocSB_zout.buf = virt_to_phys(&zout_buffer[0]); TxIsocSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) | IO_STATE(USB_SB_command, tt, zout) |
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -