Date: Tue, 25 Dec 2007 23:48:53 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 131636 for review Message-ID: <200712252348.lBPNmrqb083251@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=131636 Change 131636 by hselasky@hselasky_laptop001 on 2007/12/25 23:48:19 This commit is device side related. Fix the AT91 series full speed USB Device Controller driver so that it works ! Some more testing remains. At least the Control Endpoint is working excellent. o Reading string descriptor test yielded: 5000 bytes per second at 154 transactions per second. Affected files ... .. //depot/projects/usb/src/sys/dev/usb/at9100_dci.c#4 edit .. //depot/projects/usb/src/sys/dev/usb/at9100_dci.h#3 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/at9100_dci.c#4 (text+ko) ==== @@ -38,8 +38,11 @@ */ /* - * NOTE: the "fifo_bank" is not reset in hardware when the endpoint is + * NOTE: The "fifo_bank" is not reset in hardware when the endpoint is * reset ! + * + * NOTE: When the chip detects BUS-reset it will also reset the + * endpoints, Function-address and more. */ #include <sys/param.h> @@ -109,7 +112,8 @@ */ #define AT91_CSR_ACK(csr, what) do { \ (csr) &= ~((AT91_UDP_CSR_FORCESTALL| \ - AT91_UDP_CSR_TXPKTRDY) ^ (what)); \ + AT91_UDP_CSR_TXPKTRDY| \ + AT91_UDP_CSR_RXBYTECNT) ^ (what));\ (csr) |= ((AT91_UDP_CSR_RX_DATA_BK0| \ AT91_UDP_CSR_RX_DATA_BK1| \ AT91_UDP_CSR_TXCOMP| \ @@ -197,6 +201,8 @@ if (sc->sc_flags.clocks_off && sc->sc_flags.port_powered) { + DPRINTFN(4, "\n"); + if (sc->sc_clocks_on) { (sc->sc_clocks_on) (sc->sc_clocks_arg); } @@ -213,6 +219,8 @@ { if (!sc->sc_flags.clocks_off) { + DPRINTFN(4, "\n"); + /* disable Transceiver */ AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS); @@ -227,6 +235,8 @@ static void at9100_dci_pull_up(struct at9100_dci_softc *sc) { + /* pullup D+, if possible */ + if (!sc->sc_flags.d_pulled_up && sc->sc_flags.port_powered) { sc->sc_flags.d_pulled_up = 1; @@ -238,6 +248,8 @@ static void at9100_dci_pull_down(struct at9100_dci_softc *sc) { + /* pulldown D+, if possible */ + if (sc->sc_flags.d_pulled_up) { sc->sc_flags.d_pulled_up = 0; (sc->sc_pull_down) (sc->sc_pull_arg); @@ -265,66 +277,106 @@ return; } +static void +at9100_dci_set_address(struct at9100_dci_softc *sc, uint8_t addr) +{ + DPRINTFN(4, "addr=%d\n", addr); + + AT91_UDP_WRITE_4(sc, AT91_UDP_FADDR, addr | + AT91_UDP_FADDR_EN); + + return; +} + static uint8_t at9100_dci_setup_rx(struct at9100_dci_td *td) { - struct usbd_page_search buf_res; + struct at9100_dci_softc *sc; + usb_device_request_t req; uint32_t csr; + uint32_t temp; uint16_t count; /* read out FIFO status */ csr = bus_space_read_4(td->io_tag, td->io_hdl, td->status_reg); - DPRINTFN(4, "csr=0x%08x\n", csr); + DPRINTFN(4, "csr=0x%08x rem=%d\n", csr, td->remainder); + + temp = csr; + temp &= (AT91_UDP_CSR_RX_DATA_BK0 | + AT91_UDP_CSR_RX_DATA_BK1 | + AT91_UDP_CSR_STALLSENT | + AT91_UDP_CSR_RXSETUP | + AT91_UDP_CSR_TXCOMP); - /* check status */ if (!(csr & AT91_UDP_CSR_RXSETUP)) { - return (1); /* not complete */ + /* abort any ongoing transfer */ + if (!td->did_stall) { + DPRINTFN(4, "stalling\n"); + temp |= AT91_UDP_CSR_FORCESTALL; + td->did_stall = 1; + } + goto not_complete; } /* get the packet byte count */ count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; /* verify data length */ if (count != td->remainder) { - DPRINTFN(0, "Invalid SETUP packet " + DPRINTFN(-1, "Invalid SETUP packet " + "length, %d bytes\n", count); + goto not_complete; + } + if (count != sizeof(req)) { + DPRINTFN(-1, "Unsupported SETUP packet " "length, %d bytes\n", count); - td->error = 1; - return (0); /* we are complete */ + goto not_complete; } - while (count > 0) { - usbd_get_page(td->pc, td->offset, &buf_res); + /* receive data */ + bus_space_read_multi_1(td->io_tag, td->io_hdl, + td->fifo_reg, (void *)&req, sizeof(req)); + + /* copy data into real buffer */ + usbd_copy_in(td->pc, 0, &req, sizeof(req)); + + td->offset = sizeof(req); + td->remainder = 0; - /* get correct length */ - if (buf_res.length > count) { - buf_res.length = count; - } - /* receive data */ - bus_space_read_multi_1(td->io_tag, td->io_hdl, - td->fifo_reg, buf_res.buffer, buf_res.length); + /* get pointer to softc */ + sc = td->pc->xfer->usb_sc; - if (td->offset == 0) { - /* sneak peek the endpoint direction */ - if ((*(uint8_t *)(buf_res.buffer)) & UE_DIR_IN) { - csr |= AT91_UDP_CSR_DIR; - } else { - csr &= ~AT91_UDP_CSR_DIR; - } - } - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; + /* sneak peek the set address */ + if ((req.bmRequestType == UT_WRITE_DEVICE) && + (req.bRequest == UR_SET_ADDRESS)) { + sc->sc_dv_addr = req.wValue[0] & 0x7F; + } else { + sc->sc_dv_addr = 0xFF; } - /* clear RXSETUP */ - AT91_CSR_ACK(csr, AT91_UDP_CSR_RXSETUP); + /* sneak peek the endpoint direction */ + if (req.bmRequestType & UE_DIR_IN) { + csr |= AT91_UDP_CSR_DIR; + } else { + csr &= ~AT91_UDP_CSR_DIR; + } - /* write command */ + /* write the direction of the control transfer */ + AT91_CSR_ACK(csr, temp); bus_space_write_4(td->io_tag, td->io_hdl, td->status_reg, csr); + return (0); /* complete */ + +not_complete: + /* clear interrupts, if any */ + if (temp) { + DPRINTFN(4, "clearing 0x%08x\n", temp); + AT91_CSR_ACK(csr, temp); + bus_space_write_4(td->io_tag, td->io_hdl, + td->status_reg, csr); + } + return (1); /* not complete */ - return (0); /* complete */ } static uint8_t @@ -332,93 +384,122 @@ { struct usbd_page_search buf_res; uint32_t csr; + uint32_t temp; uint16_t count; uint8_t to; to = 2; /* don't loop forever! */ /* check if any of the FIFO banks have data */ - do { - /* read out FIFO status */ - csr = bus_space_read_4(td->io_tag, td->io_hdl, - td->status_reg); +repeat: + /* read out FIFO status */ + csr = bus_space_read_4(td->io_tag, td->io_hdl, + td->status_reg); - DPRINTFN(4, "csr=0x%08x\n", csr); + DPRINTFN(4, "csr=0x%08x\n", csr); - /* check status */ - if (!(csr & (AT91_UDP_CSR_RX_DATA_BK0 | - AT91_UDP_CSR_RX_DATA_BK1))) { - break; + if (csr & AT91_UDP_CSR_RXSETUP) { + if (td->remainder == 0) { + /* + * We are actually complete and have + * received the next SETUP + */ + DPRINTFN(4, "faking complete\n"); + return (0); /* complete */ } - /* get the packet byte count */ - count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; + /* + * USB Host Aborted the transfer. + */ + td->error = 1; + return (0); /* complete */ + } + /* Make sure that "STALLSENT" gets cleared */ + temp = csr; + temp &= AT91_UDP_CSR_STALLSENT; - /* verify the packet byte count */ - if (count != td->max_packet_size) { - if (count < td->max_packet_size) { - /* we have a short packet */ - td->short_pkt = 1; - } else { - /* invalid USB packet */ - td->error = 1; - return (0); /* we are complete */ - } + /* check status */ + if (!(csr & (AT91_UDP_CSR_RX_DATA_BK0 | + AT91_UDP_CSR_RX_DATA_BK1))) { + if (temp) { + /* write command */ + AT91_CSR_ACK(csr, temp); + bus_space_write_4(td->io_tag, td->io_hdl, + td->status_reg, csr); } - /* verify the packet byte count */ - if (count > td->remainder) { + return (1); /* not complete */ + } + /* get the packet byte count */ + count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; + + /* verify the packet byte count */ + if (count != td->max_packet_size) { + if (count < td->max_packet_size) { + /* we have a short packet */ + td->short_pkt = 1; + } else { /* invalid USB packet */ td->error = 1; return (0); /* we are complete */ } - while (count > 0) { - usbd_get_page(td->pc, td->offset, &buf_res); + } + /* verify the packet byte count */ + if (count > td->remainder) { + /* invalid USB packet */ + td->error = 1; + return (0); /* we are complete */ + } + while (count > 0) { + usbd_get_page(td->pc, td->offset, &buf_res); - /* get correct length */ - if (buf_res.length > count) { - buf_res.length = count; - } - /* receive data */ - bus_space_read_multi_1(td->io_tag, td->io_hdl, - td->fifo_reg, buf_res.buffer, buf_res.length); + /* get correct length */ + if (buf_res.length > count) { + buf_res.length = count; + } + /* receive data */ + bus_space_read_multi_1(td->io_tag, td->io_hdl, + td->fifo_reg, buf_res.buffer, buf_res.length); - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; - } + /* update counters */ + count -= buf_res.length; + td->offset += buf_res.length; + td->remainder -= buf_res.length; + } - /* clear status bits */ - if (td->support_multi_buffer) { - if (td->fifo_bank) { - td->fifo_bank = 0; - AT91_CSR_ACK(csr, AT91_UDP_CSR_RX_DATA_BK1); - } else { - td->fifo_bank = 1; - AT91_CSR_ACK(csr, AT91_UDP_CSR_RX_DATA_BK0); - } + /* clear status bits */ + if (td->support_multi_buffer) { + if (td->fifo_bank) { + td->fifo_bank = 0; + temp |= AT91_UDP_CSR_RX_DATA_BK1; } else { - AT91_CSR_ACK(csr, AT91_UDP_CSR_RX_DATA_BK0 | - AT91_UDP_CSR_RX_DATA_BK1); + td->fifo_bank = 1; + temp |= AT91_UDP_CSR_RX_DATA_BK0; } + } else { + temp |= (AT91_UDP_CSR_RX_DATA_BK0 | + AT91_UDP_CSR_RX_DATA_BK1); + } - /* write command */ - bus_space_write_4(td->io_tag, td->io_hdl, - td->status_reg, csr); + /* write command */ + AT91_CSR_ACK(csr, temp); + bus_space_write_4(td->io_tag, td->io_hdl, + td->status_reg, csr); - /* - * NOTE: We may have to delay a little bit before - * proceeding after clearing the DATA_BK bits. - */ + /* + * NOTE: We may have to delay a little bit before + * proceeding after clearing the DATA_BK bits. + */ - /* check if we are complete */ - if (td->remainder == 0) { - if (td->short_pkt) { - /* we are complete */ - return (0); - } - /* else need to receive a zero length packet */ + /* check if we are complete */ + if (td->remainder == 0) { + if (td->short_pkt) { + /* we are complete */ + return (0); } - } while (--to); + /* else need to receive a zero length packet */ + } + if (--to) { + goto repeat; + } return (1); /* not complete */ } @@ -427,70 +508,94 @@ { struct usbd_page_search buf_res; uint32_t csr; + uint32_t temp; uint16_t count; + uint8_t to; + + to = 2; /* don't loop forever! */ + +repeat: /* read out FIFO status */ csr = bus_space_read_4(td->io_tag, td->io_hdl, td->status_reg); - DPRINTFN(4, "csr=0x%08x\n", csr); + DPRINTFN(4, "csr=0x%08x rem=%d\n", csr, td->remainder); + + if (csr & AT91_UDP_CSR_RXSETUP) { + /* + * The current transfer was aborted + * by the USB Host + */ + td->error = 1; + return (0); /* complete */ + } + /* Make sure that "STALLSENT" gets cleared */ + temp = csr; + temp &= AT91_UDP_CSR_STALLSENT; - /* check status */ if (csr & AT91_UDP_CSR_TXPKTRDY) { - return (1); /* not complete - wait for interrupt */ - } - /* clear TXCOMP and set TXPKTRDY */ - AT91_CSR_ACK(csr, AT91_UDP_CSR_TXCOMP | - AT91_UDP_CSR_TXPKTRDY); + /* check for double buffering */ + if (td->support_multi_buffer && + (!td->did_multi_buffer)) { + td->did_multi_buffer = 1; + + /* only set TXPKTRDY next time */ + temp |= AT91_UDP_CSR_TXPKTRDY; - while (1) { - count = td->max_packet_size; - if (td->remainder < count) { - /* we have a short packet */ - td->short_pkt = 1; - count = td->remainder; + } else if (temp) { + /* write command */ + AT91_CSR_ACK(csr, temp); + bus_space_write_4(td->io_tag, td->io_hdl, + td->status_reg, csr); + return (1); /* not complete */ + } else { + return (1); /* not complete */ } - while (count > 0) { + } else { + /* clear TXCOMP and set TXPKTRDY */ + temp |= (AT91_UDP_CSR_TXCOMP | + AT91_UDP_CSR_TXPKTRDY); + } - usbd_get_page(td->pc, td->offset, &buf_res); + count = td->max_packet_size; + if (td->remainder < count) { + /* we have a short packet */ + td->short_pkt = 1; + count = td->remainder; + } + while (count > 0) { - /* get correct length */ - if (buf_res.length > count) { - buf_res.length = count; - } - /* transmit data */ - bus_space_write_multi_1(td->io_tag, td->io_hdl, - td->fifo_reg, buf_res.buffer, buf_res.length); + usbd_get_page(td->pc, td->offset, &buf_res); - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; + /* get correct length */ + if (buf_res.length > count) { + buf_res.length = count; } + /* transmit data */ + bus_space_write_multi_1(td->io_tag, td->io_hdl, + td->fifo_reg, buf_res.buffer, buf_res.length); + + /* update counters */ + count -= buf_res.length; + td->offset += buf_res.length; + td->remainder -= buf_res.length; + } - /* write command */ - bus_space_write_4(td->io_tag, td->io_hdl, - td->status_reg, csr); + /* write command */ + AT91_CSR_ACK(csr, temp); + bus_space_write_4(td->io_tag, td->io_hdl, + td->status_reg, csr); - /* check remainder */ - if (td->remainder == 0) { - if (td->short_pkt) { - return (0); /* complete */ - } - /* else we need to transmit a short packet */ + /* check remainder */ + if (td->remainder == 0) { + if (td->short_pkt) { + return (0); /* complete */ } - /* check for double buffering */ - if (!td->support_multi_buffer) { - break; - } - /* check if we can do a multi buffer */ - if (td->did_multi_buffer) { - break; - } - td->did_multi_buffer = 1; - - /* only set TXPKTRDY next time */ - AT91_CSR_ACK(csr, AT91_UDP_CSR_TXPKTRDY); + /* else we need to transmit a short packet */ + } + if (--to) { + goto repeat; } return (1); /* not complete */ } @@ -498,8 +603,11 @@ static uint8_t at9100_dci_data_tx_sync(struct at9100_dci_td *td) { - struct usbd_xfer *xfer; + struct at9100_dci_softc *sc; uint32_t csr; + uint32_t temp; + +repeat: /* read out FIFO status */ csr = bus_space_read_4(td->io_tag, td->io_hdl, @@ -507,26 +615,49 @@ DPRINTFN(4, "csr=0x%08x\n", csr); + if (csr & AT91_UDP_CSR_RXSETUP) { + DPRINTFN(4, "faking complete\n"); + /* Race condition */ + return (0); /* complete */ + } + temp = csr; + temp &= (AT91_UDP_CSR_STALLSENT | + AT91_UDP_CSR_TXCOMP); + /* check status */ if (csr & AT91_UDP_CSR_TXPKTRDY) { - return (1); /* not complete - wait for interrupt */ + goto not_complete; + } + if (!(csr & AT91_UDP_CSR_TXCOMP)) { + goto not_complete; + } + sc = td->pc->xfer->usb_sc; + if (sc->sc_dv_addr != 0xFF) { + /* + * The AT91 has a special requirement with regard to + * setting the address and that is to write the new + * address before clearing TXCOMP: + */ + at9100_dci_set_address(sc, sc->sc_dv_addr); } - if (csr & AT91_UDP_CSR_TXCOMP) { + /* write command */ + AT91_CSR_ACK(csr, temp); + bus_space_write_4(td->io_tag, td->io_hdl, + td->status_reg, csr); - /* clear TXCOMP */ - AT91_CSR_ACK(csr, AT91_UDP_CSR_TXCOMP); + if (td->did_multi_buffer) { + /* wait for the second and final interrupt */ + td->did_multi_buffer = 0; + goto repeat; + } + return (0); /* complete */ +not_complete: + if (temp) { /* write command */ + AT91_CSR_ACK(csr, temp); bus_space_write_4(td->io_tag, td->io_hdl, td->status_reg, csr); - - if (!td->did_multi_buffer) { - /* restore double buffer flag */ - xfer = td->pc->xfer; - return (0); /* complete */ - } - /* wait for the second and final interrupt */ - td->did_multi_buffer = 0; } return (1); /* not complete */ } @@ -538,6 +669,8 @@ struct at9100_dci_td *td; uint8_t temp; + DPRINTFN(8, "\n"); + td = xfer->td_transfer_cache; while (1) { if ((td->func) (td)) { @@ -578,7 +711,7 @@ done: sc = xfer->usb_sc; - temp = (xfer->pipe->edesc->bEndpointAddress & UE_ADDR); + temp = (xfer->endpoint & UE_ADDR); /* update FIFO bank flag and multi buffer */ if (td->fifo_bank) { @@ -661,17 +794,22 @@ mtx_lock(&(sc->sc_bus.mtx)); status = AT91_UDP_READ_4(sc, AT91_UDP_ISR); + status &= AT91_UDP_INT_DEFAULT; + + if (!status) { + mtx_unlock(&(sc->sc_bus.mtx)); + return; + } + /* acknowledge interrupts */ + AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, status); + /* check for any bus state change interrupts */ if (status & AT91_UDP_INT_BUS) { DPRINTFN(4, "real bus interrupt 0x%08x\n", status); - /* acknowledge interrupts */ - - AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, status & AT91_UDP_INT_BUS); - if (status & AT91_UDP_INT_END_BR) { sc->sc_flags.status_bus_reset = 1; sc->sc_flags.status_suspend = 0; @@ -732,6 +870,7 @@ td->fifo_bank = 0; td->error = 0; td->did_multi_buffer = 0; + td->did_stall = 0; td->short_pkt = temp->short_pkt; td->alt_next = temp->setup_alt_next; return; @@ -753,8 +892,9 @@ temp.max_frame_size = xfer->max_frame_size; - xfer->td_transfer_first = xfer->td_start; - xfer->td_transfer_cache = xfer->td_start; + td = xfer->td_start[0]; + xfer->td_transfer_first = td; + xfer->td_transfer_cache = td; /* setup temp */ @@ -762,9 +902,9 @@ temp.td_next = xfer->td_start[0]; temp.setup_alt_next = xfer->flags_int.short_frames_ok; temp.offset = 0; - temp.pc = NULL; - need_sync = 0; + sc = xfer->usb_sc; + ep_no = (xfer->endpoint & UE_ADDR); /* check if we should prepend a setup message */ @@ -789,10 +929,14 @@ need_sync = 1; } else { temp.func = &at9100_dci_data_rx; + need_sync = 0; } + + /* setup "pc" pointer */ + temp.pc = xfer->frbuffers + x; + } else { + need_sync = 0; } - /* always setup a valid "pc" pointer */ - temp.pc = xfer->frbuffers + x; while (x != xfer->nframes) { @@ -828,6 +972,19 @@ } } + /* always setup a valid "pc" pointer for status and sync */ + temp.pc = xfer->frbuffers + 0; + + /* check if we need to sync */ + if (need_sync && !xfer->flags_int.isochronous_xfr) { + + /* we need a SYNC point after TX */ + temp.func = &at9100_dci_data_tx_sync; + temp.len = 0; + temp.short_pkt = 0; + + at9100_dci_setup_standard_chain_sub(&temp); + } /* check if we should append a status stage */ if (xfer->flags_int.control_xfr && @@ -839,6 +996,7 @@ */ if (xfer->endpoint & UE_DIR_IN) { temp.func = &at9100_dci_data_rx; + need_sync = 0; } else { temp.func = &at9100_dci_data_tx; need_sync = 1; @@ -847,27 +1005,19 @@ temp.short_pkt = 0; at9100_dci_setup_standard_chain_sub(&temp); - } - if (need_sync && !xfer->flags_int.isochronous_xfr) { + if (need_sync) { + /* we need a SYNC point after TX */ + temp.func = &at9100_dci_data_tx_sync; + temp.len = 0; + temp.short_pkt = 0; - /* we need a SYNC point */ - temp.func = &at9100_dci_data_tx_sync; - temp.len = 0; - temp.short_pkt = 0; - - at9100_dci_setup_standard_chain_sub(&temp); - - td = temp.td; - } else { - td = temp.td; + at9100_dci_setup_standard_chain_sub(&temp); + } } - /* must have at least one frame! */ + td = temp.td; xfer->td_transfer_last = td; - sc = xfer->usb_sc; - ep_no = (xfer->pipe->edesc->bEndpointAddress & UE_ADDR); - /* setup the correct fifo bank */ if (sc->sc_ep_flags[ep_no].fifo_bank) { td = xfer->td_transfer_first; @@ -904,8 +1054,23 @@ static void at9100_dci_start_standard_chain(struct usbd_xfer *xfer) { + DPRINTFN(8, "\n"); + /* poll one time */ if (at9100_dci_xfer_do_fifo(xfer)) { + + struct at9100_dci_softc *sc = xfer->usb_sc; + uint8_t ep_no = xfer->endpoint & UE_ADDR; + + /* + * Only enable the endpoint interrupt when we are actually + * waiting for data, hence we are dealing with level + * triggered interrupts ! + */ + AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_EP(ep_no)); + + DPRINTFN(14, "enable interrupts on endpoint %d\n", ep_no); + /* queue up transfer on interrupt list */ usbd_transfer_intr_enqueue(xfer); @@ -916,7 +1081,10 @@ (void *)&at9100_dci_timeout, xfer); } } else { - /* queue callback for execution */ + /* + * The USB transfer is complete. Queue callback for + * execution: + */ usbd_callback_wrapper(xfer, NULL, USBD_CONTEXT_CALLBACK); } @@ -929,6 +1097,8 @@ { struct at9100_dci_softc *sc = xfer->usb_sc; + DPRINTFN(8, "\n"); + mtx_assert(&sc->sc_bus.mtx, MA_OWNED); if (std->state != USBD_STD_ROOT_TR_PRE_DATA) { @@ -956,6 +1126,8 @@ uint32_t len; uint8_t error; + DPRINTFN(8, "\n"); + td = xfer->td_transfer_cache; do { @@ -1064,11 +1236,22 @@ static void at9100_dci_device_done(struct usbd_xfer *xfer, usbd_status_t error) { + struct at9100_dci_softc *sc = xfer->usb_sc; + uint8_t ep_no; + mtx_assert(&sc->sc_bus.mtx, MA_OWNED); DPRINTFN(1, "xfer=%p, pipe=%p, error=%d\n", xfer, xfer->pipe, error); + if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { + ep_no = (xfer->endpoint & UE_ADDR); + + /* disable endpoint interrupt */ + AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, AT91_UDP_INT_EP(ep_no)); + + DPRINTFN(14, "disable interrupts on endpoint %d\n", ep_no); + } /* dequeue transfer and start next transfer */ usbd_transfer_dequeue(xfer, error); return; @@ -1082,6 +1265,10 @@ uint32_t csr_val; uint8_t csr_reg; + mtx_assert(&(udev->bus->mtx), MA_OWNED); + + DPRINTFN(4, "\n"); + if (xfer) { /* cancel any ongoing transfers */ at9100_dci_device_done(xfer, USBD_STALLED); @@ -1102,6 +1289,10 @@ struct at9100_dci_softc *sc; uint32_t rst_val; + mtx_assert(&(udev->bus->mtx), MA_OWNED); + + DPRINTFN(4, "\n"); + /* reset pipe state */ sc = AT9100_DCI_BUS2SC(udev->bus); @@ -1135,6 +1326,12 @@ uint8_t ep_type; uint8_t ep_dir; + mtx_assert(&(udev->bus->mtx), MA_OWNED); + + if (udev->flags.usb_mode == USB_MODE_HOST) { + /* this is the Root HUB */ + return; + } sc = AT9100_DCI_BUS2SC(udev->bus); AT91_CSR_ACK(csr_val, 0); @@ -1196,19 +1393,6 @@ return; } -static void -at9100_dci_set_address(struct usbd_device *udev, uint8_t addr) -{ - struct at9100_dci_softc *sc; - - sc = AT9100_DCI_BUS2SC(udev->bus); - - AT91_UDP_WRITE_4(sc, AT91_UDP_FADDR, (addr & 0x7F) | - AT91_UDP_FADDR_EN); - - return; -} - usbd_status_t at9100_dci_init(struct at9100_dci_softc *sc) { @@ -1223,14 +1407,25 @@ mtx_lock(&(sc->sc_bus.mtx)); + /* turn on clocks */ + + if (sc->sc_clocks_on) { + (sc->sc_clocks_on) (sc->sc_clocks_arg); + } + /* wait a little for things to stabilise */ + DELAY(1000); + + /* enable Transceiver */ + AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, 0); + + /* disable and clear all interrupts */ + AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF); + AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF); + csr_val = 0; AT91_CSR_ACK(csr_val, 0); - /* reset device address */ - - AT91_UDP_WRITE_4(sc, AT91_UDP_FADDR, 0); - - /* disable everything */ + /* disable and reset all endpoints */ for (n = 0; n != AT91_UDP_EP_MAX; n++) { @@ -1242,25 +1437,18 @@ AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0); } - /* enable control endpoint */ + /* enable the interrupts we want */ - csr_val |= (AT91_UDP_CSR_ET_CTRL | AT91_UDP_CSR_EPEDS); + AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_BUS); - AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(0), csr_val); - - /* disable all interrupts */ - - AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF); + /* turn off clocks */ - /* enable the interrupts we want */ - - AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, AT91_UDP_INT_DEFAULT); - at9100_dci_clocks_off(sc); mtx_unlock(&(sc->sc_bus.mtx)); /* catch any lost interrupts */ + at9100_dci_do_poll(&(sc->sc_bus)); return (0); /* success */ @@ -1604,13 +1792,12 @@ 0x09, 0x04, /* American English */ #define STRING_VENDOR \ - 'A', 0, 'T', 0, 'M', 0, 'E', 0, 'L' + 'A', 0, 'T', 0, 'M', 0, 'E', 0, 'L', 0 #define STRING_PRODUCT \ - 'A', 0, 'T', 0, 'M', 0, 'E', 0, 'L', 0, \ - ' ', 0, 'D', 0, 'e', 0, 'v', 0, 'i', 0, \ - 'c', 0, 'e', 0, 'R', 0, 'o', 0, 'o', 0, \ - 't', 0, ' ', 0, 'H', 0, 'U', 0, 'B', 0, + 'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \ + 'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \ + 'U', 0, 'B', 0, USB_MAKE_STRING_DESC(STRING_LANG, at9100_dci_langtab); USB_MAKE_STRING_DESC(STRING_VENDOR, at9100_dci_vendor); @@ -1885,7 +2072,7 @@ if (value & 0xFF00) { goto tr_stalled; } - sc->sc_addr = value; + sc->sc_rt_addr = value; goto tr_valid; >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200712252348.lBPNmrqb083251>