diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2007-02-13 18:32:58 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2007-02-13 18:32:58 +0000 |
commit | d11a73972d840513bd5e9b38f0f7c21aea43b81c (patch) | |
tree | b1c2d58042cbc8169c116ae90feca07a6e0fe35e /sys | |
parent | 203287ccbb0e74abe77aba0e7e6d3e80928632c9 (diff) |
USB client mode with cdce function driver is coming along, RX and TX kinda work.
Limitations include failing to recieve packets that are a multiple of 64 bytes
and sending packets longer than 128 bytes appears to be messed up.
Work in progress.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/arm/xscale/pxa27x_udc.c | 246 | ||||
-rw-r--r-- | sys/arch/arm/xscale/pxa27x_udcreg.h | 5 | ||||
-rw-r--r-- | sys/dev/usb/if_cdcef.c | 347 | ||||
-rw-r--r-- | sys/dev/usb/usbf_subr.c | 4 |
4 files changed, 560 insertions, 42 deletions
diff --git a/sys/arch/arm/xscale/pxa27x_udc.c b/sys/arch/arm/xscale/pxa27x_udc.c index 5c4d8d28ffe..bd8a43ab568 100644 --- a/sys/arch/arm/xscale/pxa27x_udc.c +++ b/sys/arch/arm/xscale/pxa27x_udc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pxa27x_udc.c,v 1.10 2007/02/12 16:11:11 drahn Exp $ */ +/* $OpenBSD: pxa27x_udc.c,v 1.11 2007/02/13 18:32:57 drahn Exp $ */ /* * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> @@ -74,6 +74,10 @@ struct pxaudc_softc { u_int32_t sc_otgisr; /* XXX deferred interrupts */ struct pxaudc_pipe *sc_pipe[PXAUDC_NEP]; int sc_npipe; + + int sc_cn; + int sc_in; + int sc_isn; }; int pxaudc_match(struct device *, void *, void *); @@ -90,13 +94,16 @@ void pxaudc_show(struct pxaudc_softc *); void pxaudc_enable(struct pxaudc_softc *); void pxaudc_disable(struct pxaudc_softc *); void pxaudc_read_ep0(struct pxaudc_softc *, usbf_xfer_handle); +void pxaudc_read_epN(struct pxaudc_softc *sc, int ep); void pxaudc_write_ep0(struct pxaudc_softc *, usbf_xfer_handle); void pxaudc_write(struct pxaudc_softc *, usbf_xfer_handle); +void pxaudc_write_epN(struct pxaudc_softc *sc, int ep); int pxaudc_connect_intr(void *); int pxaudc_intr(void *); void pxaudc_intr1(struct pxaudc_softc *); void pxaudc_ep0_intr(struct pxaudc_softc *); +void pxaudc_epN_intr(struct pxaudc_softc *sc, int ep); usbf_status pxaudc_open(struct usbf_pipe *); void pxaudc_softintr(void *); @@ -171,7 +178,7 @@ struct usbf_pipe_methods pxaudc_bulk_methods = { #ifndef PXAUDC_DEBUG #define DPRINTF(l, x) do {} while (0) #else -int pxaudcdebug = 0; +int pxaudcdebug = 5; #define DPRINTF(l, x) if ((l) <= pxaudcdebug) printf x; else {} #endif @@ -366,7 +373,7 @@ pxaudc_enable(struct pxaudc_softc *sc) { int i; - DPRINTF(0,("pxaudc_enable\n")); + DPRINTF(10,("pxaudc_enable\n")); /* Start the clocks. */ pxa2x0_clkman_config(CKEN_USBDC, 1); @@ -445,7 +452,7 @@ pxaudc_enable(struct pxaudc_softc *sc) void pxaudc_disable(struct pxaudc_softc *sc) { - DPRINTF(0,("pxaudc_disable\n")); + DPRINTF(10,("pxaudc_disable\n")); /* Disable the controller. */ CSR_CLR_4(sc, USBDC_UDCCR, USBDC_UDCCR_UDE); @@ -508,6 +515,94 @@ pxaudc_read_ep0(struct pxaudc_softc *sc, usbf_xfer_handle xfer) } void +pxaudc_read_epN(struct pxaudc_softc *sc, int ep) +{ + size_t len, tlen; + u_int8_t *p; + struct pxaudc_pipe *ppipe; + usbf_pipe_handle pipe = NULL; + usbf_xfer_handle xfer = NULL; + int count; + u_int32_t csr; + + ppipe = sc->sc_pipe[ep]; + + if (ppipe == NULL) { + return; + } + pipe = &ppipe->pipe; +again: + xfer = SIMPLEQ_FIRST(&pipe->queue); + + if (xfer == NULL) + return; + + count = CSR_READ_4(sc, USBDC_UDCBCR(ep)); + tlen = len = MIN(count, xfer->length - xfer->actlen); + p = xfer->buffer + xfer->actlen; + csr = CSR_READ_4(sc, USBDC_UDCCSR(ep)); + +#if 0 + if ((csr & (USBDC_UDCCSR_SP|USBDC_UDCCSR_PC)) == + (USBDC_UDCCSR_SP|USBDC_UDCCSR_PC) + && count == 0) +#else + if ((csr & USBDC_UDCCSR_PC) && count == 0) +#endif + { +#ifdef DEBUG_RX + printf("trans1 complete\n"); +#endif + xfer->status = USBF_NORMAL_COMPLETION; + usbf_transfer_complete(xfer); + } + +#ifdef DEBUG_RX + printf("reading data from endpoint %x, len %x csr %x", + ep, count, csr); +#endif + + while (CSR_READ_4(sc, USBDC_UDCCSR(ep)) & USBDC_UDCCSR_BNE) { + u_int32_t v = CSR_READ_4(sc, USBDC_UDCDR(ep)); + + /* double buffering? */ + if (len > 0) { + if (((unsigned)p & 0x3) == 0) + *(u_int32_t *)p = v; + else { + *(p+0) = v & 0xff; + *(p+1) = (v >> 8) & 0xff; + *(p+2) = (v >> 16) & 0xff; + *(p+3) = (v >> 24) & 0xff; + } + p += 4; + len -= 4; + xfer->actlen += 4; + } + count -= 4; + } +#ifdef DEBUG_RX + printf(" remain %x\n", len); +#endif + CSR_SET_4(sc, USBDC_UDCCSR(ep), USBDC_UDCCSR_PC); + + + if (xfer->length == xfer->actlen || (tlen == 0 && xfer->actlen != 0) || + csr & USBDC_UDCCSR_SP) { +#ifdef DEBUG_RX + printf("trans2 complete\n"); +#endif + xfer->status = USBF_NORMAL_COMPLETION; + usbf_transfer_complete(xfer); + } + csr = CSR_READ_4(sc, USBDC_UDCCSR(ep)); + printf("csr now %x len %x\n", + csr, CSR_READ_4(sc, USBDC_UDCBCR(ep))); + if (csr & USBDC_UDCCSR_PC) + goto again; +} + +void pxaudc_write_ep0(struct pxaudc_softc *sc, usbf_xfer_handle xfer) { struct pxaudc_xfer *lxfer = (struct pxaudc_xfer *)xfer; @@ -519,7 +614,7 @@ pxaudc_write_ep0(struct pxaudc_softc *sc, usbf_xfer_handle xfer) lxfer->frmlen = 0; } - DPRINTF(1,("%s: ep0 ctrl-in, xfer=%p, len=%u, actlen=%u\n", + DPRINTF(11,("%s: ep0 ctrl-in, xfer=%p, len=%u, actlen=%u\n", DEVNAME(sc), xfer, xfer->length, xfer->actlen)); if (xfer->actlen >= xfer->length) { @@ -566,7 +661,59 @@ pxaudc_write_ep0(struct pxaudc_softc *sc, usbf_xfer_handle xfer) void pxaudc_write(struct pxaudc_softc *sc, usbf_xfer_handle xfer) { - printf("pxaudc_write: XXX\n"); + u_int8_t *p; + int ep = usbf_endpoint_index(xfer->pipe->endpoint); + int tlen = 0; + + if (xfer->actlen == xfer->length) { +#if 0 + if ((xfer->actlen % 64) != 0) + CSR_SET_4(sc, USBDC_UDCCSR(ep), USBDC_UDCCSR_SP); +#endif + xfer->status = USBF_NORMAL_COMPLETION; + usbf_transfer_complete(xfer); + return; + } + + p = xfer->buffer + xfer->actlen; + + printf("writing data to endpoint %x, xlen %x xact %x", + ep, xfer->length, xfer->actlen); + + if (CSR_READ_4(sc, USBDC_UDCCSR(ep)) & USBDC_UDCCSR_PC) + CSR_SET_4(sc, USBDC_UDCCSR(ep), USBDC_UDCCSR_PC); + + while (CSR_READ_4(sc, USBDC_UDCCSR(ep)) & USBDC_UDCCSR_BNF) { + u_int32_t v; + + if (xfer->actlen >= xfer->length) + break; + + if (((unsigned)p & 0x3) == 0) + v = *(u_int32_t *)p; + else { + v = *(p+0); + v |= *(p+1) << 8; + v |= *(p+2) << 16; + v |= *(p+3) << 24; + } + CSR_WRITE_4(sc, USBDC_UDCDR(ep), v); + + p += 4; + xfer->actlen += 4; + + tlen += 4; + } + printf(" wrote tlen %x %x\n", tlen, xfer->actlen); + if (xfer->actlen >= xfer->length) { + if ((xfer->actlen % 64) != 0) { + CSR_SET_4(sc, USBDC_UDCCSR(ep), USBDC_UDCCSR_SP); + CSR_SET_4(sc, USBDC_UDCCSR(ep), USBDC_UDCCSR_SP); + printf("setting short packet on %x csr\n", ep, + CSR_READ_4(sc, USBDC_UDCCSR(ep))); + } + xfer->actlen = xfer->length; /* no overflow */ + } } /* @@ -578,7 +725,7 @@ pxaudc_connect_intr(void *v) { struct pxaudc_softc *sc = v; - DPRINTF(0,("pxaudc_connect_intr: connect=%d device=%d\n", + DPRINTF(10,("pxaudc_connect_intr: connect=%d device=%d\n", pxa2x0_gpio_get_bit(C3000_USB_CONNECT_PIN), pxa2x0_gpio_get_bit(C3000_USB_DEVICE_PIN))); @@ -603,7 +750,7 @@ pxaudc_intr(void *v) isr1 = CSR_READ_4(sc, USBDC_UDCISR1); otgisr = CSR_READ_4(sc, USBDC_UDCOTGISR); - DPRINTF(0,("pxaudc_intr: isr0=%b, isr1=%b, otgisr=%b\n", + DPRINTF(10,("pxaudc_intr: isr0=%b, isr1=%b, otgisr=%b\n", isr0, USBDC_UDCISR0_BITS, isr1, USBDC_UDCISR1_BITS, otgisr, USBDC_UDCOTGISR_BITS)); @@ -644,25 +791,31 @@ pxaudc_intr1(struct pxaudc_softc *sc) sc->sc_bus.intr_context++; if (isr1 & USBDC_UDCISR1_IRCC) { + u_int32_t ccr; CSR_SET_4(sc, USBDC_UDCCR, USBDC_UDCCR_SMAC); - /* wait for reconfig to finish (SMAC auto clears */ + /* wait for reconfig to finish (SMAC auto clears) */ while (CSR_READ_4(sc, USBDC_UDCCR) & USBDC_UDCCR_SMAC) delay(10); + ccr = CSR_READ_4(sc, USBDC_UDCCR); + sc->sc_cn = USBDC_UDCCR_ACNr(ccr); + sc->sc_in = USBDC_UDCCR_AINr(ccr); + sc->sc_isn = USBDC_UDCCR_AAISNr(ccr); + goto ret; } + printf("pxaudc_intr: isr0=%b, isr1=%b, otgisr=%b\n", + isr0, USBDC_UDCISR0_BITS, isr1, USBDC_UDCISR1_BITS, + otgisr, USBDC_UDCOTGISR_BITS); + for (i = 1; i < 24; i++) { - int x; if (i < 16) { if (isr0 & USBDC_UDCISR0_IR(i)) - printf("interrupt pending ep[%d]\n", i); + pxaudc_epN_intr(sc, i); } else { if (isr1 & USBDC_UDCISR1_IR(i-16)) - printf("interrupt pending ep[%d]\n", i); + pxaudc_epN_intr(sc, i); } - x = CSR_READ_4(sc, USBDC_UDCBCR(i)); - if( x != 0) - printf("data present in ep %d %d\n", i, x); } /* Handle USB RESET condition. */ @@ -689,6 +842,49 @@ ret: } void +pxaudc_epN_intr(struct pxaudc_softc *sc, int ep) +{ + /* should not occur before device is configured */ + if (sc->sc_cn == 0) + return; + + /* faster method of determining direction? */ + struct pxaudc_pipe *ppipe; + usbf_pipe_handle pipe = NULL; + int dir; + ppipe = sc->sc_pipe[ep]; + + if (ppipe == NULL) + return; + pipe = &ppipe->pipe; + dir = usbf_endpoint_dir(pipe->endpoint); + + if (dir == UE_DIR_IN) { + pxaudc_write_epN(sc, ep); + } else { + pxaudc_read_epN(sc, ep); + } + +} + +void +pxaudc_write_epN(struct pxaudc_softc *sc, int ep) +{ + struct pxaudc_pipe *ppipe; + usbf_pipe_handle pipe = NULL; + usbf_xfer_handle xfer = NULL; + + ppipe = sc->sc_pipe[ep]; + + if (ppipe == NULL) { + return; + } + pipe = &ppipe->pipe; + xfer = SIMPLEQ_FIRST(&pipe->queue); + if (xfer != NULL) + pxaudc_write(sc, xfer); +} +void pxaudc_ep0_intr(struct pxaudc_softc *sc) { struct pxaudc_pipe *ppipe; @@ -697,7 +893,7 @@ pxaudc_ep0_intr(struct pxaudc_softc *sc) u_int32_t csr0; csr0 = CSR_READ_4(sc, USBDC_UDCCSR0); - DPRINTF(0,("pxaudc_ep0_intr: csr0=%b\n", csr0, USBDC_UDCCSR0_BITS)); + DPRINTF(10,("pxaudc_ep0_intr: csr0=%b\n", csr0, USBDC_UDCCSR0_BITS)); ppipe = sc->sc_pipe[0]; if (ppipe != NULL) { @@ -707,12 +903,12 @@ pxaudc_ep0_intr(struct pxaudc_softc *sc) if (sc->sc_ep0state == EP0_SETUP && (csr0 & USBDC_UDCCSR0_OPC)) { if (pipe == NULL) { - DPRINTF(0,("pxaudc_ep0_intr: no control pipe\n")); + DPRINTF(10,("pxaudc_ep0_intr: no control pipe\n")); return; } if (xfer == NULL) { - DPRINTF(0,("pxaudc_ep0_intr: no xfer\n")); + DPRINTF(10,("pxaudc_ep0_intr: no xfer\n")); return; } @@ -737,7 +933,7 @@ pxaudc_open(struct usbf_pipe *pipe) if (usbf_endpoint_index(pipe->endpoint) >= PXAUDC_NEP) return USBF_BAD_ADDRESS; - DPRINTF(0,("pxaudc_open\n")); + DPRINTF(10,("pxaudc_open\n")); s = splhardusb(); switch (usbf_endpoint_type(pipe->endpoint)) { @@ -844,7 +1040,7 @@ pxaudc_ctrl_start(usbf_xfer_handle xfer) else { /* XXX boring message, this case is normally reached if * XXX the xfer for a device request is being queued. */ - DPRINTF(0,("%s: ep[%x] ctrl-out, xfer=%p, len=%u, " + DPRINTF(10,("%s: ep[%x] ctrl-out, xfer=%p, len=%u, " "actlen=%u\n", DEVNAME(sc), usbf_endpoint_address(xfer->pipe->endpoint), xfer, xfer->length, @@ -867,7 +1063,7 @@ pxaudc_ctrl_abort(usbf_xfer_handle xfer) int type = usbf_endpoint_type(pipe->endpoint); #endif - DPRINTF(0,("%s: ep%d %s-%s abort, xfer=%p\n", DEVNAME(sc), index, + DPRINTF(10,("%s: ep%d %s-%s abort, xfer=%p\n", DEVNAME(sc), index, type == UE_CONTROL ? "ctrl" : "bulk", dir == UE_DIR_IN ? "in" : "out", xfer)); @@ -939,7 +1135,7 @@ pxaudc_bulk_start(usbf_xfer_handle xfer) { struct usbf_pipe *pipe = xfer->pipe; struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus; - int iswrite = usbf_endpoint_dir(pipe->endpoint) == UE_DIR_IN; + int iswrite = (usbf_endpoint_dir(pipe->endpoint) == UE_DIR_IN); int s; DPRINTF(0,("%s: ep%d bulk-%s start, xfer=%p, len=%u\n", DEVNAME(sc), @@ -966,6 +1162,12 @@ pxaudc_bulk_abort(usbf_xfer_handle xfer) void pxaudc_bulk_done(usbf_xfer_handle xfer) { +#if 0 + int ep = usbf_endpoint_address(xfer->pipe->endpoint); + struct usbf_pipe *pipe = xfer->pipe; + struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus; + +#endif } void diff --git a/sys/arch/arm/xscale/pxa27x_udcreg.h b/sys/arch/arm/xscale/pxa27x_udcreg.h index 8905e62187c..4e4ca7db7b9 100644 --- a/sys/arch/arm/xscale/pxa27x_udcreg.h +++ b/sys/arch/arm/xscale/pxa27x_udcreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pxa27x_udcreg.h,v 1.3 2007/02/07 16:26:49 drahn Exp $ */ +/* $OpenBSD: pxa27x_udcreg.h,v 1.4 2007/02/13 18:32:57 drahn Exp $ */ /* * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> @@ -35,8 +35,11 @@ #define USBDC_UDCCR_EMCE (1<<3) /* Endpoint Mem Config Error */ #define USBDC_UDCCR_SMAC (1<<4) /* Switch EndPt Mem to Active Config */ #define USBDC_UDCCR_AAISN (7<<5) /* Active UDC Alt Iface Setting */ +#define USBDC_UDCCR_AAISNr(x) ((x>>5)&7) /* Active UDC Config */ #define USBDC_UDCCR_AIN (7<<8) /* Active UDC Iface */ +#define USBDC_UDCCR_AINr(x) ((x>>8)&7) /* Active UDC Config */ #define USBDC_UDCCR_ACN (7<<11) /* Active UDC Config */ +#define USBDC_UDCCR_ACNr(x) ((x>>11)&7) /* Active UDC Config */ #define USBDC_UDCCR_DWRE (1<<16) /* Device Remote Wake-Up Feature */ #define USBDC_UDCCR_BHNP (1<<28) /* B-Device Host Neg Proto Enable */ #define USBDC_UDCCR_AHNP (1<<29) /* A-Device Host NEg Proto Support */ diff --git a/sys/dev/usb/if_cdcef.c b/sys/dev/usb/if_cdcef.c index 5491bc057a6..49f300e95c7 100644 --- a/sys/dev/usb/if_cdcef.c +++ b/sys/dev/usb/if_cdcef.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_cdcef.c,v 1.2 2007/02/07 16:26:49 drahn Exp $ */ +/* $OpenBSD: if_cdcef.c,v 1.3 2007/02/13 18:32:56 drahn Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -20,11 +20,14 @@ * USB Communication Device Class Ethernet Emulation Model function driver * (counterpart of the host-side cdce(4) driver) */ +#include <bpfilter.h> + #include <sys/param.h> #include <sys/device.h> #include <sys/socket.h> #include <sys/systm.h> +#include <sys/mbuf.h> #include <net/if.h> @@ -33,6 +36,17 @@ #include <dev/usb/usbf.h> #include <dev/usb/usbcdc.h> +#if NBPFILTER > 0 +#include <net/bpf.h> +#endif + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> + + #define CDCEF_VENDOR_ID 0x0001 #define CDCEF_PRODUCT_ID 0x0001 #define CDCEF_DEVICE_CODE 0x0100 @@ -54,6 +68,15 @@ struct cdcef_softc { usbf_xfer_handle sc_xfer_out; void *sc_buffer_in; void *sc_buffer_out; + + struct mbuf *sc_xmit_mbuf; + + struct arpcom sc_arpcom; +#define GET_IFP(sc) (&(sc)->sc_arpcom.ac_if) + + int sc_rxeof_errors; + int sc_unit; + int sc_attached; }; int cdcef_match(struct device *, void *, void *); @@ -68,6 +91,12 @@ void cdcef_txeof(usbf_xfer_handle, usbf_private_handle, usbf_status); void cdcef_rxeof(usbf_xfer_handle, usbf_private_handle, usbf_status); +int cdcef_ioctl(struct ifnet *ifp, u_long command, caddr_t data); +void cdcef_watchdog(struct ifnet *ifp); +void cdcef_init(struct cdcef_softc *); +void cdcef_stop(struct cdcef_softc *); +int cdcef_encap(struct cdcef_softc *sc, struct mbuf *m, int idx); +struct mbuf * cdcef_newbuf(void); struct cfattach cdcef_ca = { sizeof(struct cdcef_softc), cdcef_match, cdcef_attach @@ -105,8 +134,12 @@ USB_ATTACH(cdcef) struct usbf_attach_arg *uaa = aux; usbf_device_handle dev = uaa->device; char *devinfop; + struct ifnet *ifp; usbf_status err; usb_cdc_union_descriptor_t udesc; + int s; + u_int16_t macaddr_hi; + /* Set the device identification according to the function. */ usbf_devinfo_setup(dev, UDCLASS_IN_INTERFACE, 0, 0, CDCEF_VENDOR_ID, @@ -194,14 +227,41 @@ USB_ATTACH(cdcef) usbf_endpoint_address(sc->sc_ep_out)); /* Get ready to receive packets. */ - usbf_setup_xfer(sc->sc_xfer_out, sc->sc_pipe_out, (void *)sc, - sc->sc_buffer_out, CDCEF_BUFSZ, 0, 0, cdcef_rxeof); + usbf_setup_xfer(sc->sc_xfer_out, sc->sc_pipe_out, sc, + sc->sc_buffer_out, CDCEF_BUFSZ, USBD_SHORT_XFER_OK, 0, cdcef_rxeof); err = usbf_transfer(sc->sc_xfer_out); if (err && err != USBF_IN_PROGRESS) { printf("%s: usbf_transfer failed\n", DEVNAME(sc)); USB_ATTACH_ERROR_RETURN; } + s = splnet(); + + macaddr_hi = htons(0x2acb); + bcopy(&macaddr_hi, &sc->sc_arpcom.ac_enaddr[0], sizeof(u_int16_t)); + bcopy(&ticks, &sc->sc_arpcom.ac_enaddr[2], sizeof(u_int32_t)); + sc->sc_arpcom.ac_enaddr[5] = (u_int8_t)(sc->sc_unit); + + printf("%s: address %s\n", DEVNAME(sc), + ether_sprintf(sc->sc_arpcom.ac_enaddr)); + + ifp = GET_IFP(sc); + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = cdcef_ioctl; + ifp->if_start = cdcef_start; + ifp->if_watchdog = cdcef_watchdog; + strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); + + IFQ_SET_READY(&ifp->if_snd); + + if_attach(ifp); + Ether_ifattach(ifp, sc->cdcef_arpcom.ac_enaddr); + + sc->sc_attached = 1; + splx(s); + + USB_ATTACH_SUCCESS_RETURN; } @@ -216,6 +276,31 @@ cdcef_do_request(usbf_function_handle fun, usb_device_request_t *req, void cdcef_start(struct ifnet *ifp) { + struct cdcef_softc *sc = ifp->if_softc; + struct mbuf *m_head = NULL; + + if(ifp->if_flags & IFF_OACTIVE) + return; + IFQ_POLL(&ifp->if_snd, m_head); + if (m_head == NULL) { + return; + } + + if (cdcef_encap(sc, m_head, 0)) { + ifp->if_flags |= IFF_OACTIVE; + return; + } + + IFQ_DEQUEUE(&ifp->if_snd, m_head); + +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT); +#endif + + ifp->if_flags |= IFF_OACTIVE; + + ifp->if_timer = 6; } void @@ -223,35 +308,263 @@ cdcef_txeof(usbf_xfer_handle xfer, usbf_private_handle priv, usbf_status err) { struct cdcef_softc *sc = priv; + struct ifnet *ifp = GET_IFP(sc); + int s; + s = splnet(); printf("cdcef_txeof: xfer=%p, priv=%p, %s\n", xfer, priv, usbf_errstr(err)); - /* Setup another xfer. */ - usbf_setup_xfer(xfer, sc->sc_pipe_in, (void *)sc, - sc->sc_buffer_in, CDCEF_BUFSZ, 0, 0, cdcef_txeof); - err = usbf_transfer(xfer); - if (err && err != USBF_IN_PROGRESS) { - printf("%s: usbf_transfer failed\n", DEVNAME(sc)); - USB_ATTACH_ERROR_RETURN; + ifp->if_timer = 0; + ifp->if_flags &= ~IFF_OACTIVE; + + if (sc->sc_xmit_mbuf != NULL) { + m_freem(sc->sc_xmit_mbuf); + sc->sc_xmit_mbuf = NULL; } + + if (err) + ifp->if_oerrors++; + else + ifp->if_opackets++; + + if (IFQ_IS_EMPTY(&ifp->if_snd) == 0) + cdcef_start(ifp); + + splx(s); } void cdcef_rxeof(usbf_xfer_handle xfer, usbf_private_handle priv, - usbf_status err) + usbf_status status) { - struct cdcef_softc *sc = priv; + struct cdcef_softc *sc = priv; + int total_len = 0; + struct ifnet *ifp = GET_IFP(sc); + struct mbuf *m = NULL; + + int s; + +#if 0 printf("cdcef_rxeof: xfer=%p, priv=%p, %s\n", xfer, priv, - usbf_errstr(err)); + usbf_errstr(status)); +#endif + + if (status != USBF_NORMAL_COMPLETION) { + if (status == USBF_NOT_STARTED || status == USBF_CANCELLED) + return; + if (sc->sc_rxeof_errors == 0) + printf("%s: usb error on rx: %s\n", + DEVNAME(sc), usbf_errstr(status)); + /* XXX - no stalls on client */ + if (sc->sc_rxeof_errors++ > 10) { + printf("%s: too many errors, disabling\n", + DEVNAME(sc)); + /* sc->sc_dying = 1; */ + // return; + } + goto done; + } + sc->sc_rxeof_errors = 0; + + usbf_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); + + printf("recieved %d bytes\n", total_len); + + /* total_len -= 4; Strip off CRC added for Zaurus - XXX*/ + if (total_len <= 1) + goto done; + + if (total_len < sizeof(struct ether_header)) { + ifp->if_ierrors++; + goto done; + } + + s = splnet(); + if (ifp->if_flags & IFF_RUNNING) { + m = cdcef_newbuf(); + if (m == NULL) { + /* message? */ + goto done1; + } + + /* XXX - buffer big enough? */ + m->m_pkthdr.len = m->m_len = total_len; + bcopy(sc->sc_buffer_out, mtod(m, char *), total_len); + m->m_pkthdr.rcvif = ifp; + + ifp->if_ipackets++; + +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); +#endif + IF_INPUT(ifp, m); + } + +done1: + splx(s); + +done: /* Setup another xfer. */ - usbf_setup_xfer(xfer, sc->sc_pipe_out, (void *)sc, - sc->sc_buffer_out, CDCEF_BUFSZ, 0, 0, cdcef_rxeof); - err = usbf_transfer(xfer); - if (err && err != USBF_IN_PROGRESS) { + usbf_setup_xfer(xfer, sc->sc_pipe_out, sc, sc->sc_buffer_out, + CDCEF_BUFSZ, USBD_SHORT_XFER_OK, 0, cdcef_rxeof); + + status = usbf_transfer(xfer); + if (status && status != USBF_IN_PROGRESS) { printf("%s: usbf_transfer failed\n", DEVNAME(sc)); USB_ATTACH_ERROR_RETURN; } } + +struct mbuf * +cdcef_newbuf(void) +{ + struct mbuf *m; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + return (NULL); + + MCLGET(m, M_DONTWAIT); + if (!(m->m_flags & M_EXT)) { + m_freem(m); + return (NULL); + } + + m->m_len = m->m_pkthdr.len = MCLBYTES; + m_adj(m, ETHER_ALIGN); + + return (m); +} + +int +cdcef_ioctl(struct ifnet *ifp, u_long command, caddr_t data) +{ + struct cdcef_softc *sc = ifp->if_softc; + struct ifaddr *ifa = (struct ifaddr *)data; + struct ifreq *ifr = (struct ifreq *)data; + int s, error = 0; + + s = splnet(); + + switch (command) { + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + cdcef_init(sc); + switch (ifa->ifa_addr->sa_family) { + case AF_INET: + arp_ifinit(&sc->sc_arpcom, ifa); + break; + } + break; + + case SIOCSIFMTU: + if (ifr->ifr_mtu > ETHERMTU) + error = EINVAL; + else + ifp->if_mtu = ifr->ifr_mtu; + break; + + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_flags & IFF_RUNNING)) + cdcef_init(sc); + } else { + if (ifp->if_flags & IFF_RUNNING) + cdcef_stop(sc); + } + error = 0; + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + error = (command == SIOCADDMULTI) ? + ether_addmulti(ifr, &sc->sc_arpcom) : + ether_delmulti(ifr, &sc->sc_arpcom); + + if (error == ENETRESET) + error = 0; + break; + + default: + error = EINVAL; + break; + } + + splx(s); + + return (error); +} + +void +cdcef_watchdog(struct ifnet *ifp) +{ + struct cdcef_softc *sc = ifp->if_softc; + +#if 0 + if (sc->sc_dying) + return; +#endif + + ifp->if_oerrors++; + printf("%s: watchdog timeout\n", DEVNAME(sc)); +} + +void +cdcef_init(struct cdcef_softc *sc) +{ + int s; + struct ifnet *ifp = GET_IFP(sc); + if (ifp->if_flags & IFF_RUNNING) + return; + s = splnet(); + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + splx(s); +} + +int +cdcef_encap(struct cdcef_softc *sc, struct mbuf *m, int idx) +{ + usbf_status err; + + printf("encap len %x m %x\n", m->m_pkthdr.len, m); + m_copydata(m, 0, m->m_pkthdr.len, sc->sc_buffer_in); + /* NO CRC */ + + usbf_setup_xfer(sc->sc_xfer_in, sc->sc_pipe_in, sc, sc->sc_buffer_in, + m->m_pkthdr.len, USBD_NO_COPY, 10000, cdcef_txeof); + + err = usbf_transfer(sc->sc_xfer_in); + if (err && err != USBD_IN_PROGRESS) { + printf("encap error\n"); + cdcef_stop(sc); + return (EIO); + } + sc->sc_xmit_mbuf = m; + printf("encap finished\n"); + + return (0); +} + + +void +cdcef_stop(struct cdcef_softc *sc) +{ + struct ifnet *ifp = GET_IFP(sc); + + ifp->if_timer = 0; + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + + /* cancel recieve pipe? */ + + if (sc->sc_xmit_mbuf != NULL) { + m_freem(sc->sc_xmit_mbuf); + sc->sc_xmit_mbuf = NULL; + } +} diff --git a/sys/dev/usb/usbf_subr.c b/sys/dev/usb/usbf_subr.c index ffedaf5ed29..80e304fcb39 100644 --- a/sys/dev/usb/usbf_subr.c +++ b/sys/dev/usb/usbf_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: usbf_subr.c,v 1.2 2007/02/07 16:26:49 drahn Exp $ */ +/* $OpenBSD: usbf_subr.c,v 1.3 2007/02/13 18:32:57 drahn Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -58,7 +58,7 @@ usbf_errstr(usbf_status err) { static char buffer[5]; - if (err < USBD_ERROR_MAX) + if (err < USBF_ERROR_MAX) return usbf_error_strs[err]; snprintf(buffer, sizeof buffer, "%d", err); |