summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/arm/xscale/pxa27x_udc.c246
-rw-r--r--sys/arch/arm/xscale/pxa27x_udcreg.h5
-rw-r--r--sys/dev/usb/if_cdcef.c347
-rw-r--r--sys/dev/usb/usbf_subr.c4
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);