Annotation of sys/dev/usb/ueagle.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ueagle.c,v 1.21 2007/06/14 10:11:15 mbalmer Exp $ */
2:
3: /*-
4: * Copyright (c) 2003-2006
5: * Damien Bergamini <damien.bergamini@free.fr>
6: *
7: * Permission to use, copy, modify, and distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: */
19:
20: /*-
21: * Driver for Analog Devices Eagle chipset.
22: * http://www.analog.com/
23: */
24:
25: #include "bpfilter.h"
26:
27: #include <sys/param.h>
28: #include <sys/sysctl.h>
29: #include <sys/sockio.h>
30: #include <sys/mbuf.h>
31: #include <sys/kernel.h>
32: #include <sys/socket.h>
33: #include <sys/systm.h>
34: #include <sys/malloc.h>
35: #include <sys/device.h>
36: #include <sys/kthread.h>
37:
38: #include <net/bpf.h>
39: #include <net/if.h>
40: #include <net/if_atm.h>
41: #include <net/if_media.h>
42:
43: #ifdef INET
44: #include <netinet/in.h>
45: #include <netinet/if_atm.h>
46: #include <netinet/if_ether.h>
47: #endif
48:
49: #include <dev/usb/usb.h>
50: #include <dev/usb/usbdi.h>
51: #include <dev/usb/usbdi_util.h>
52: #include <dev/usb/ezload.h>
53: #include <dev/usb/usbdevs.h>
54:
55: #include <dev/usb/ueaglereg.h>
56: #include <dev/usb/ueaglevar.h>
57:
58: #ifdef USB_DEBUG
59: #define DPRINTF(x) do { if (ueagledebug > 0) printf x; } while (0)
60: #define DPRINTFN(n, x) do { if (ueagledebug >= (n)) printf x; } while (0)
61: int ueagledebug = 0;
62: #else
63: #define DPRINTF(x)
64: #define DPRINTFN(n, x)
65: #endif
66:
67: /* various supported device vendors/products */
68: static const struct ueagle_type {
69: struct usb_devno dev;
70: const char *fw;
71: } ueagle_devs[] = {
72: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEI }, NULL },
73: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEI_NF }, "ueagleI" },
74: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEII }, NULL },
75: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEII_NF }, "ueagleII" },
76: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIIC }, NULL },
77: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIIC_NF }, "ueagleII" },
78: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIII }, NULL },
79: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIII_NF }, "ueagleIII" },
80: { { USB_VENDOR_USR, USB_PRODUCT_USR_HEINEKEN_A }, NULL },
81: { { USB_VENDOR_USR, USB_PRODUCT_USR_HEINEKEN_A_NF }, "ueagleI" },
82: { { USB_VENDOR_USR, USB_PRODUCT_USR_HEINEKEN_B }, NULL },
83: { { USB_VENDOR_USR, USB_PRODUCT_USR_HEINEKEN_B_NF }, "ueagleI" },
84: { { USB_VENDOR_USR, USB_PRODUCT_USR_MILLER_A }, NULL },
85: { { USB_VENDOR_USR, USB_PRODUCT_USR_MILLER_A_NF }, "ueagleI" },
86: { { USB_VENDOR_USR, USB_PRODUCT_USR_MILLER_B }, NULL },
87: { { USB_VENDOR_USR, USB_PRODUCT_USR_MILLER_B_NF }, "ueagleI" }
88: };
89: #define ueagle_lookup(v, p) \
90: ((struct ueagle_type *)usb_lookup(ueagle_devs, v, p))
91:
92: void ueagle_attachhook(void *);
93: int ueagle_getesi(struct ueagle_softc *, uint8_t *);
94: void ueagle_loadpage(void *);
95: void ueagle_request(struct ueagle_softc *, uint16_t, uint16_t,
96: void *, int);
97: #ifdef USB_DEBUG
98: void ueagle_dump_cmv(struct ueagle_softc *, struct ueagle_cmv *);
99: #endif
100: int ueagle_cr(struct ueagle_softc *, uint32_t, uint16_t,
101: uint32_t *);
102: int ueagle_cw(struct ueagle_softc *, uint32_t, uint16_t, uint32_t);
103: int ueagle_stat(struct ueagle_softc *);
104: void ueagle_stat_thread(void *);
105: int ueagle_boot(struct ueagle_softc *);
106: void ueagle_swap_intr(struct ueagle_softc *, struct ueagle_swap *);
107: void ueagle_cmv_intr(struct ueagle_softc *, struct ueagle_cmv *);
108: void ueagle_intr(usbd_xfer_handle, usbd_private_handle,
109: usbd_status);
110: uint32_t ueagle_crc_update(uint32_t, uint8_t *, int);
111: void ueagle_push_cell(struct ueagle_softc *, uint8_t *);
112: void ueagle_rxeof(usbd_xfer_handle, usbd_private_handle,
113: usbd_status);
114: void ueagle_txeof(usbd_xfer_handle, usbd_private_handle,
115: usbd_status);
116: int ueagle_encap(struct ueagle_softc *, struct mbuf *);
117: void ueagle_start(struct ifnet *);
118: int ueagle_open_vcc(struct ueagle_softc *,
119: struct atm_pseudoioctl *);
120: int ueagle_close_vcc(struct ueagle_softc *,
121: struct atm_pseudoioctl *);
122: int ueagle_ioctl(struct ifnet *, u_long, caddr_t);
123: int ueagle_open_pipes(struct ueagle_softc *);
124: void ueagle_close_pipes(struct ueagle_softc *);
125: int ueagle_init(struct ifnet *);
126: void ueagle_stop(struct ifnet *, int);
127:
128: int ueagle_match(struct device *, void *, void *);
129: void ueagle_attach(struct device *, struct device *, void *);
130: int ueagle_detach(struct device *, int);
131: int ueagle_activate(struct device *, enum devact);
132:
133: struct cfdriver ueagle_cd = {
134: NULL, "ueagle", DV_DULL
135: };
136:
137: const struct cfattach ueagle_ca = {
138: sizeof(struct ueagle_softc),
139: ueagle_match,
140: ueagle_attach,
141: ueagle_detach,
142: ueagle_activate,
143: };
144:
145: int
146: ueagle_match(struct device *parent, void *match, void *aux)
147: {
148: struct usb_attach_arg *uaa = aux;
149:
150: if (uaa->iface != NULL)
151: return UMATCH_NONE;
152:
153: return (ueagle_lookup(uaa->vendor, uaa->product) != NULL) ?
154: UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
155: }
156:
157: void
158: ueagle_attachhook(void *xsc)
159: {
160: char *firmwares[2];
161: struct ueagle_softc *sc = xsc;
162:
163: firmwares[0] = (char *)sc->fw;
164: firmwares[1] = NULL;
165:
166: if (ezload_downloads_and_reset(sc->sc_udev, firmwares) != 0) {
167: printf("%s: could not download firmware\n",
168: sc->sc_dev.dv_xname);
169: return;
170: }
171: }
172:
173: void
174: ueagle_attach(struct device *parent, struct device *self, void *aux)
175: {
176: struct ueagle_softc *sc = (struct ueagle_softc *)self;
177: struct usb_attach_arg *uaa = aux;
178: struct ifnet *ifp = &sc->sc_if;
179: char *devinfop;
180: uint8_t addr[ETHER_ADDR_LEN];
181:
182: sc->sc_udev = uaa->device;
183: printf("\n");
184:
185: /*
186: * Pre-firmware modems must be flashed and reset first. They will
187: * automatically detach themselves from the bus and reattach later
188: * with a new product Id.
189: */
190: sc->fw = ueagle_lookup(uaa->vendor, uaa->product)->fw;
191: if (sc->fw != NULL) {
192: if (rootvp == NULL)
193: mountroothook_establish(ueagle_attachhook, sc);
194: else
195: ueagle_attachhook(sc);
196:
197: /* processing of pre-firmware modems ends here */
198: return;
199: }
200:
201: devinfop = usbd_devinfo_alloc(sc->sc_udev, 0);
202: printf("%s: %s\n", sc->sc_dev.dv_xname, devinfop);
203: usbd_devinfo_free(devinfop);
204:
205: if (usbd_set_config_no(sc->sc_udev, UEAGLE_CONFIG_NO, 0) != 0) {
206: printf("%s: could not set configuration no\n",
207: sc->sc_dev.dv_xname);
208: return;
209: }
210:
211: if (ueagle_getesi(sc, addr) != 0) {
212: printf("%s: could not read end system identifier\n",
213: sc->sc_dev.dv_xname);
214: return;
215: }
216:
217: printf("%s: address: %02x:%02x:%02x:%02x:%02x:%02x\n",
218: sc->sc_dev.dv_xname, addr[0], addr[1], addr[2], addr[3],
219: addr[4], addr[5]);
220:
221: usb_init_task(&sc->sc_swap_task, ueagle_loadpage, sc);
222:
223: ifp->if_softc = sc;
224: ifp->if_flags = IFF_SIMPLEX;
225: ifp->if_init = ueagle_init;
226: ifp->if_ioctl = ueagle_ioctl;
227: ifp->if_start = ueagle_start;
228: IFQ_SET_READY(&ifp->if_snd);
229: memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
230:
231: if_attach(ifp);
232: atm_ifattach(ifp);
233:
234: /* override default MTU value (9180 is too large for us) */
235: ifp->if_mtu = UEAGLE_IFMTU;
236:
237: #if NBPFILTER > 0
238: bpfattach(&ifp->if_bpf, ifp, DLT_RAW, 0);
239: #endif
240:
241: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
242: &sc->sc_dev);
243: }
244:
245: int
246: ueagle_detach(struct device *self, int flags)
247: {
248: struct ueagle_softc *sc = (struct ueagle_softc *)self;
249: struct ifnet *ifp = &sc->sc_if;
250:
251: if (sc->fw != NULL)
252: return 0; /* shortcut for pre-firmware devices */
253:
254: sc->gone = 1;
255: ueagle_stop(ifp, 1);
256:
257: /* wait for stat thread to exit properly */
258: if (sc->stat_thread != NULL) {
259: DPRINTFN(3, ("%s: waiting for stat thread to exit\n",
260: sc->sc_dev.dv_xname));
261:
262: tsleep(sc->stat_thread, PZERO, "ueaglestat", 0);
263:
264: DPRINTFN(3, ("%s: stat thread exited properly\n",
265: sc->sc_dev.dv_xname));
266: }
267:
268: if_detach(ifp);
269:
270: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
271: &sc->sc_dev);
272:
273: return 0;
274: }
275:
276: /*
277: * Retrieve the device End System Identifier (MAC address).
278: */
279: int
280: ueagle_getesi(struct ueagle_softc *sc, uint8_t *addr)
281: {
282: usb_string_descriptor_t us;
283: usbd_status error;
284: uint16_t c;
285: int i, len;
286:
287: error = usbd_get_string_desc(sc->sc_udev, UEAGLE_ESISTR, 0, &us, &len);
288: if (error != 0)
289: return error;
290:
291: if (us.bLength < (6 + 1) * 2)
292: return 1;
293:
294: for (i = 0; i < 6 * 2; i++) {
295: if ((c = UGETW(us.bString[i])) & 0xff00)
296: return 1; /* not 8-bit clean */
297:
298: if (i & 1)
299: addr[i / 2] <<= 4;
300: else
301: addr[i / 2] = 0;
302:
303: if (c >= '0' && c <= '9')
304: addr[i / 2] |= c - '0';
305: else if (c >= 'a' && c <= 'f')
306: addr[i / 2] |= c - 'a' + 10;
307: else if (c >= 'A' && c <= 'F')
308: addr[i / 2] |= c - 'A' + 10;
309: else
310: return 1;
311: }
312:
313: return 0;
314: }
315:
316: void
317: ueagle_loadpage(void *xsc)
318: {
319: struct ueagle_softc *sc = xsc;
320: usbd_xfer_handle xfer;
321: struct ueagle_block_info bi;
322: uint16_t pageno = sc->pageno;
323: uint16_t ovl = sc->ovl;
324: uint8_t pagecount, blockcount;
325: uint16_t blockaddr, blocksize;
326: uint32_t pageoffset;
327: uint8_t *p;
328: int i;
329:
330: p = sc->dsp;
331: pagecount = *p++;
332:
333: if (pageno >= pagecount) {
334: printf("%s: invalid page number %u requested\n",
335: sc->sc_dev.dv_xname, pageno);
336: return;
337: }
338:
339: p += 4 * pageno;
340: pageoffset = UGETDW(p);
341: if (pageoffset == 0)
342: return;
343:
344: p = sc->dsp + pageoffset;
345: blockcount = *p++;
346:
347: DPRINTF(("%s: sending %u blocks for fw page %u\n",
348: sc->sc_dev.dv_xname, blockcount, pageno));
349:
350: if ((xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) {
351: printf("%s: could not allocate xfer\n",
352: sc->sc_dev.dv_xname);
353: return;
354: }
355:
356: USETW(bi.wHdr, UEAGLE_BLOCK_INFO_HDR);
357: USETW(bi.wOvl, ovl);
358: USETW(bi.wOvlOffset, ovl | 0x8000);
359:
360: for (i = 0; i < blockcount; i++) {
361: blockaddr = UGETW(p); p += 2;
362: blocksize = UGETW(p); p += 2;
363:
364: USETW(bi.wSize, blocksize);
365: USETW(bi.wAddress, blockaddr);
366: USETW(bi.wLast, (i == blockcount - 1) ? 1 : 0);
367:
368: /* send block info through the IDMA pipe */
369: usbd_setup_xfer(xfer, sc->pipeh_idma, sc, &bi, sizeof bi, 0,
370: UEAGLE_IDMA_TIMEOUT, NULL);
371: if (usbd_sync_transfer(xfer) != 0) {
372: printf("%s: could not transfer block info\n",
373: sc->sc_dev.dv_xname);
374: break;
375: }
376:
377: /* send block data through the IDMA pipe */
378: usbd_setup_xfer(xfer, sc->pipeh_idma, sc, p, blocksize, 0,
379: UEAGLE_IDMA_TIMEOUT, NULL);
380: if (usbd_sync_transfer(xfer) != 0) {
381: printf("%s: could not transfer block data\n",
382: sc->sc_dev.dv_xname);
383: break;
384: }
385:
386: p += blocksize;
387: }
388:
389: usbd_free_xfer(xfer);
390: }
391:
392: void
393: ueagle_request(struct ueagle_softc *sc, uint16_t val, uint16_t index,
394: void *data, int len)
395: {
396: usb_device_request_t req;
397: usbd_status error;
398:
399: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
400: req.bRequest = UEAGLE_REQUEST;
401: USETW(req.wValue, val);
402: USETW(req.wIndex, index);
403: USETW(req.wLength, len);
404:
405: error = usbd_do_request_async(sc->sc_udev, &req, data);
406: if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
407: printf("%s: could not send request\n", sc->sc_dev.dv_xname);
408: }
409:
410: #ifdef USB_DEBUG
411: void
412: ueagle_dump_cmv(struct ueagle_softc *sc, struct ueagle_cmv *cmv)
413: {
414: printf(" Preamble: 0x%04x\n", UGETW(cmv->wPreamble));
415: printf(" Destination: %s (0x%02x)\n",
416: (cmv->bDst == UEAGLE_HOST) ? "Host" : "Modem", cmv->bDst);
417: printf(" Type: %u\n", cmv->bFunction >> 4);
418: printf(" Subtype: %u\n", cmv->bFunction & 0xf);
419: printf(" Index: %u\n", UGETW(cmv->wIndex));
420: printf(" Address: %c%c%c%c.%u\n",
421: cmv->dwSymbolicAddress[1], cmv->dwSymbolicAddress[0],
422: cmv->dwSymbolicAddress[3], cmv->dwSymbolicAddress[2],
423: UGETW(cmv->wOffsetAddress));
424: printf(" Data: 0x%08x\n", UGETDATA(cmv->dwData));
425: }
426: #endif
427:
428: int
429: ueagle_cr(struct ueagle_softc *sc, uint32_t address, uint16_t offset,
430: uint32_t *data)
431: {
432: struct ueagle_cmv cmv;
433: usbd_status error;
434: int s;
435:
436: USETW(cmv.wPreamble, UEAGLE_CMV_PREAMBLE);
437: cmv.bDst = UEAGLE_MODEM;
438: cmv.bFunction = UEAGLE_CR;
439: USETW(cmv.wIndex, sc->index);
440: USETW(cmv.wOffsetAddress, offset);
441: USETDW(cmv.dwSymbolicAddress, address);
442: USETDATA(cmv.dwData, 0);
443:
444: #ifdef USB_DEBUG
445: if (ueagledebug >= 15) {
446: printf("%s: reading CMV\n", sc->sc_dev.dv_xname);
447: ueagle_dump_cmv(sc, &cmv);
448: }
449: #endif
450:
451: s = splusb();
452:
453: ueagle_request(sc, UEAGLE_SETBLOCK, UEAGLE_MPTXSTART, &cmv, sizeof cmv);
454:
455: /* wait at most 2 seconds for an answer */
456: error = tsleep(UEAGLE_COND_CMV(sc), PZERO, "cmv", 2 * hz);
457: if (error != 0) {
458: printf("%s: timeout waiting for CMV ack\n",
459: sc->sc_dev.dv_xname);
460: splx(s);
461: return error;
462: }
463:
464: *data = sc->data;
465: splx(s);
466:
467: return 0;
468: }
469:
470: int
471: ueagle_cw(struct ueagle_softc *sc, uint32_t address, uint16_t offset,
472: uint32_t data)
473: {
474: struct ueagle_cmv cmv;
475: usbd_status error;
476: int s;
477:
478: USETW(cmv.wPreamble, UEAGLE_CMV_PREAMBLE);
479: cmv.bDst = UEAGLE_MODEM;
480: cmv.bFunction = UEAGLE_CW;
481: USETW(cmv.wIndex, sc->index);
482: USETW(cmv.wOffsetAddress, offset);
483: USETDW(cmv.dwSymbolicAddress, address);
484: USETDATA(cmv.dwData, data);
485:
486: #ifdef USB_DEBUG
487: if (ueagledebug >= 15) {
488: printf("%s: writing CMV\n", sc->sc_dev.dv_xname);
489: ueagle_dump_cmv(sc, &cmv);
490: }
491: #endif
492:
493: s = splusb();
494:
495: ueagle_request(sc, UEAGLE_SETBLOCK, UEAGLE_MPTXSTART, &cmv, sizeof cmv);
496:
497: /* wait at most 2 seconds for an answer */
498: error = tsleep(UEAGLE_COND_CMV(sc), PZERO, "cmv", 2 * hz);
499: if (error != 0) {
500: printf("%s: timeout waiting for CMV ack\n",
501: sc->sc_dev.dv_xname);
502: splx(s);
503: return error;
504: }
505:
506: splx(s);
507:
508: return 0;
509: }
510:
511: int
512: ueagle_stat(struct ueagle_softc *sc)
513: {
514: struct ifnet *ifp = &sc->sc_if;
515: uint32_t data;
516: usbd_status error;
517: #define CR(sc, address, offset, data) do { \
518: if ((error = ueagle_cr(sc, address, offset, data)) != 0) \
519: return error; \
520: } while (0)
521:
522: CR(sc, UEAGLE_CMV_STAT, 0, &sc->stats.phy.status);
523: switch ((sc->stats.phy.status >> 8) & 0xf) {
524: case 0: /* idle */
525: DPRINTFN(3, ("%s: waiting for synchronization\n",
526: sc->sc_dev.dv_xname));
527: return ueagle_cw(sc, UEAGLE_CMV_CNTL, 0, 2);
528:
529: case 1: /* initialization */
530: DPRINTFN(3, ("%s: initializing\n", sc->sc_dev.dv_xname));
531: return ueagle_cw(sc, UEAGLE_CMV_CNTL, 0, 2);
532:
533: case 2: /* operational */
534: DPRINTFN(4, ("%s: operational\n", sc->sc_dev.dv_xname));
535: break;
536:
537: default: /* fail ... */
538: DPRINTFN(3, ("%s: synchronization failed\n",
539: sc->sc_dev.dv_xname));
540: ueagle_init(ifp);
541: return 1;
542: }
543:
544: CR(sc, UEAGLE_CMV_DIAG, 1, &sc->stats.phy.flags);
545: if (sc->stats.phy.flags & 0x10) {
546: DPRINTF(("%s: delineation LOSS\n", sc->sc_dev.dv_xname));
547: sc->stats.phy.status = 0;
548: ueagle_init(ifp);
549: return 1;
550: }
551:
552: CR(sc, UEAGLE_CMV_RATE, 0, &data);
553: sc->stats.phy.dsrate = ((data >> 16) & 0x1ff) * 32;
554: sc->stats.phy.usrate = (data & 0xff) * 32;
555:
556: CR(sc, UEAGLE_CMV_DIAG, 23, &data);
557: sc->stats.phy.attenuation = (data & 0xff) / 2;
558:
559: CR(sc, UEAGLE_CMV_DIAG, 3, &sc->stats.atm.cells_crc_errors);
560: CR(sc, UEAGLE_CMV_DIAG, 22, &sc->stats.phy.dserror);
561: CR(sc, UEAGLE_CMV_DIAG, 25, &sc->stats.phy.dsmargin);
562: CR(sc, UEAGLE_CMV_DIAG, 46, &sc->stats.phy.userror);
563: CR(sc, UEAGLE_CMV_DIAG, 49, &sc->stats.phy.usmargin);
564: CR(sc, UEAGLE_CMV_DIAG, 51, &sc->stats.phy.rxflow);
565: CR(sc, UEAGLE_CMV_DIAG, 52, &sc->stats.phy.txflow);
566: CR(sc, UEAGLE_CMV_DIAG, 54, &sc->stats.phy.dsunc);
567: CR(sc, UEAGLE_CMV_DIAG, 58, &sc->stats.phy.usunc);
568: CR(sc, UEAGLE_CMV_INFO, 8, &sc->stats.phy.vidco);
569: CR(sc, UEAGLE_CMV_INFO, 14, &sc->stats.phy.vidcpe);
570:
571: if (sc->pipeh_tx != NULL)
572: return 0;
573:
574: return ueagle_open_pipes(sc);
575: #undef CR
576: }
577:
578: void
579: ueagle_stat_thread(void *arg)
580: {
581: struct ueagle_softc *sc = arg;
582:
583: for (;;) {
584: if (ueagle_stat(sc) != 0)
585: break;
586:
587: usbd_delay_ms(sc->sc_udev, 5000);
588: }
589:
590: wakeup(sc->stat_thread);
591:
592: kthread_exit(0);
593: }
594:
595: int
596: ueagle_boot(struct ueagle_softc *sc)
597: {
598: uint16_t zero = 0; /* ;-) */
599: usbd_status error;
600: #define CW(sc, address, offset, data) do { \
601: if ((error = ueagle_cw(sc, address, offset, data)) != 0) \
602: return error; \
603: } while (0)
604:
605: ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_BOOTIDMA, NULL, 0);
606: ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_STARTRESET, NULL, 0);
607:
608: usbd_delay_ms(sc->sc_udev, 200);
609:
610: ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_ENDRESET, NULL, 0);
611: ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_MPTXMAILBOX, &zero, 2);
612: ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_MPRXMAILBOX, &zero, 2);
613: ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_SWAPMAILBOX, &zero, 2);
614:
615: usbd_delay_ms(sc->sc_udev, 1000);
616:
617: sc->pageno = 0;
618: sc->ovl = 0;
619: ueagle_loadpage(sc);
620:
621: /* wait until modem reaches operationnal state */
622: error = tsleep(UEAGLE_COND_READY(sc), PZERO | PCATCH, "boot", 10 * hz);
623: if (error != 0) {
624: printf("%s: timeout waiting for operationnal state\n",
625: sc->sc_dev.dv_xname);
626: return error;
627: }
628:
629: CW(sc, UEAGLE_CMV_CNTL, 0, 1);
630:
631: /* send configuration options */
632: CW(sc, UEAGLE_CMV_OPTN, 0, UEAGLE_OPTN0);
633: CW(sc, UEAGLE_CMV_OPTN, 2, UEAGLE_OPTN2);
634: CW(sc, UEAGLE_CMV_OPTN, 7, UEAGLE_OPTN7);
635:
636: /* continue with synchronization */
637: CW(sc, UEAGLE_CMV_CNTL, 0, 2);
638:
639: return kthread_create(ueagle_stat_thread, sc, &sc->stat_thread,
640: sc->sc_dev.dv_xname);
641: #undef CW
642: }
643:
644: void
645: ueagle_swap_intr(struct ueagle_softc *sc, struct ueagle_swap *swap)
646: {
647: #define rotbr(v, n) ((v) >> (n) | (v) << (8 - (n)))
648: sc->pageno = swap->bPageNo;
649: sc->ovl = rotbr(swap->bOvl, 4);
650:
651: usb_add_task(sc->sc_udev, &sc->sc_swap_task);
652: #undef rotbr
653: }
654:
655: /*
656: * This function handles spontaneous CMVs and CMV acknowledgements sent by the
657: * modem on the interrupt pipe.
658: */
659: void
660: ueagle_cmv_intr(struct ueagle_softc *sc, struct ueagle_cmv *cmv)
661: {
662: #ifdef USB_DEBUG
663: if (ueagledebug >= 15) {
664: printf("%s: receiving CMV\n", sc->sc_dev.dv_xname);
665: ueagle_dump_cmv(sc, cmv);
666: }
667: #endif
668:
669: if (UGETW(cmv->wPreamble) != UEAGLE_CMV_PREAMBLE) {
670: printf("%s: received CMV with invalid preamble\n",
671: sc->sc_dev.dv_xname);
672: return;
673: }
674:
675: if (cmv->bDst != UEAGLE_HOST) {
676: printf("%s: received CMV with bad direction\n",
677: sc->sc_dev.dv_xname);
678: return;
679: }
680:
681: /* synchronize our current CMV index with the modem */
682: sc->index = UGETW(cmv->wIndex) + 1;
683:
684: switch (cmv->bFunction) {
685: case UEAGLE_MODEMREADY:
686: wakeup(UEAGLE_COND_READY(sc));
687: break;
688:
689: case UEAGLE_CR_ACK:
690: sc->data = UGETDATA(cmv->dwData);
691: /* FALLTHROUGH */
692: case UEAGLE_CW_ACK:
693: wakeup(UEAGLE_COND_CMV(sc));
694: break;
695: }
696: }
697:
698: void
699: ueagle_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
700: {
701: struct ueagle_softc *sc = priv;
702: struct ueagle_intr *intr;
703:
704: if (status != USBD_NORMAL_COMPLETION) {
705: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
706: return;
707:
708: printf("%s: abnormal interrupt status: %s\n",
709: sc->sc_dev.dv_xname, usbd_errstr(status));
710:
711: if (status == USBD_STALLED)
712: usbd_clear_endpoint_stall_async(sc->pipeh_intr);
713:
714: return;
715: }
716:
717: intr = (struct ueagle_intr *)sc->ibuf;
718: switch (UGETW(intr->wInterrupt)) {
719: case UEAGLE_INTR_SWAP:
720: ueagle_swap_intr(sc, (struct ueagle_swap *)(intr + 1));
721: break;
722:
723: case UEAGLE_INTR_CMV:
724: ueagle_cmv_intr(sc, (struct ueagle_cmv *)(intr + 1));
725: break;
726:
727: default:
728: printf("%s: caught unknown interrupt\n",
729: sc->sc_dev.dv_xname);
730: }
731: }
732:
733: static const uint32_t ueagle_crc32_table[256] = {
734: 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc,
735: 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f,
736: 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a,
737: 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
738: 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8,
739: 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
740: 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e,
741: 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
742: 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84,
743: 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027,
744: 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022,
745: 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
746: 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077,
747: 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c,
748: 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1,
749: 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
750: 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb,
751: 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
752: 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d,
753: 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
754: 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f,
755: 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044,
756: 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689,
757: 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
758: 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683,
759: 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59,
760: 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c,
761: 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
762: 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e,
763: 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
764: 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48,
765: 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
766: 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2,
767: 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601,
768: 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604,
769: 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
770: 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6,
771: 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad,
772: 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7,
773: 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
774: 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd,
775: 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
776: 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b,
777: 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
778: 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679,
779: 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12,
780: 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af,
781: 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
782: 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5,
783: 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06,
784: 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03,
785: 0xb1f740b4
786: };
787:
788: uint32_t
789: ueagle_crc_update(uint32_t crc, uint8_t *buf, int len)
790: {
791: for (; len != 0; len--, buf++)
792: crc = ueagle_crc32_table[(crc >> 24) ^ *buf] ^ (crc << 8);
793:
794: return crc;
795: }
796:
797: /*
798: * Reassembly part of the software ATM AAL5 SAR.
799: */
800: void
801: ueagle_push_cell(struct ueagle_softc *sc, uint8_t *cell)
802: {
803: struct ueagle_vcc *vcc = &sc->vcc;
804: struct ifnet *ifp;
805: struct mbuf *m;
806: uint32_t crc;
807: uint16_t pdulen, totlen;
808: int s;
809:
810: sc->stats.atm.cells_received++;
811:
812: if (!(vcc->flags & UEAGLE_VCC_ACTIVE) ||
813: ATM_CH_GETVPI(cell) != vcc->vpi ||
814: ATM_CH_GETVCI(cell) != vcc->vci) {
815: sc->stats.atm.vcc_no_conn++;
816: return;
817: }
818:
819: if (vcc->flags & UEAGLE_VCC_DROP) {
820: if (ATM_CH_ISLASTCELL(cell)) {
821: vcc->flags &= ~UEAGLE_VCC_DROP;
822: sc->stats.atm.cspdus_dropped++;
823: }
824:
825: sc->stats.atm.cells_dropped++;
826: return;
827: }
828:
829: if (vcc->m == NULL) {
830: MGETHDR(m, M_DONTWAIT, MT_DATA);
831: if (m == NULL) {
832: vcc->flags |= UEAGLE_VCC_DROP;
833: return;
834: }
835:
836: MCLGET(m, M_DONTWAIT);
837: if (!(m->m_flags & M_EXT)) {
838: vcc->flags |= UEAGLE_VCC_DROP;
839: m_freem(m);
840: return;
841: }
842:
843: vcc->m = m;
844: vcc->dst = mtod(m, uint8_t *);
845: vcc->limit = vcc->dst + MCLBYTES - ATM_CELL_PAYLOAD_SIZE;
846: }
847:
848: if (vcc->dst > vcc->limit) {
849: vcc->flags |= UEAGLE_VCC_DROP;
850: sc->stats.atm.cells_dropped++;
851: goto fail;
852: }
853:
854: memcpy(vcc->dst, cell + ATM_CELL_HEADER_SIZE, ATM_CELL_PAYLOAD_SIZE);
855: vcc->dst += ATM_CELL_PAYLOAD_SIZE;
856:
857: if (!ATM_CH_ISLASTCELL(cell))
858: return;
859:
860: /*
861: * Handle the last cell of the AAL5 CPCS-PDU.
862: */
863: m = vcc->m;
864:
865: totlen = vcc->dst - mtod(m, uint8_t *);
866: pdulen = AAL5_TR_GETPDULEN(cell);
867:
868: if (totlen < pdulen + AAL5_TRAILER_SIZE) {
869: sc->stats.atm.cspdus_dropped++;
870: goto fail;
871: }
872:
873: if (totlen >= pdulen + ATM_CELL_PAYLOAD_SIZE + AAL5_TRAILER_SIZE) {
874: sc->stats.atm.cspdus_dropped++;
875: goto fail;
876: }
877:
878: crc = ueagle_crc_update(CRC_INITIAL, mtod(m, uint8_t *), totlen);
879: if (crc != CRC_MAGIC) {
880: sc->stats.atm.cspdus_crc_errors++;
881: goto fail;
882: }
883:
884: /* finalize mbuf */
885: ifp = &sc->sc_if;
886: m->m_pkthdr.rcvif = ifp;
887: m->m_pkthdr.len = m->m_len = pdulen;
888:
889: sc->stats.atm.cspdus_received++;
890:
891: s = splnet();
892:
893: #if NBPFILTER > 0
894: if (ifp->if_bpf != NULL)
895: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
896: #endif
897:
898: /* send the AAL5 CPCS-PDU to the ATM layer */
899: ifp->if_ipackets++;
900: atm_input(ifp, &vcc->aph, m, vcc->rxhand);
901: vcc->m = NULL;
902:
903: splx(s);
904:
905: return;
906:
907: fail: m_freem(vcc->m);
908: vcc->m = NULL;
909: }
910:
911: void
912: ueagle_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv,
913: usbd_status status)
914: {
915: struct ueagle_isoreq *req = priv;
916: struct ueagle_softc *sc = req->sc;
917: uint32_t count;
918: uint8_t *p;
919: int i;
920:
921: if (status == USBD_CANCELLED)
922: return;
923:
924: for (i = 0; i < UEAGLE_NISOFRMS; i++) {
925: count = req->frlengths[i];
926: p = req->offsets[i];
927:
928: while (count >= ATM_CELL_SIZE) {
929: ueagle_push_cell(sc, p);
930: p += ATM_CELL_SIZE;
931: count -= ATM_CELL_SIZE;
932: }
933: #ifdef DIAGNOSTIC
934: if (count > 0) {
935: printf("%s: truncated cell (%u bytes)\n",
936: sc->sc_dev.dv_xname, count);
937: }
938: #endif
939: req->frlengths[i] = sc->isize;
940: }
941:
942: usbd_setup_isoc_xfer(req->xfer, sc->pipeh_rx, req, req->frlengths,
943: UEAGLE_NISOFRMS, USBD_NO_COPY, ueagle_rxeof);
944: usbd_transfer(xfer);
945: }
946:
947: void
948: ueagle_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
949: usbd_status status)
950: {
951: struct ueagle_txreq *req = priv;
952: struct ueagle_softc *sc = req->sc;
953: struct ifnet *ifp = &sc->sc_if;
954: int s;
955:
956: if (status != USBD_NORMAL_COMPLETION) {
957: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
958: return;
959:
960: printf("%s: could not transmit buffer: %s\n",
961: sc->sc_dev.dv_xname, usbd_errstr(status));
962:
963: if (status == USBD_STALLED)
964: usbd_clear_endpoint_stall_async(sc->pipeh_tx);
965:
966: ifp->if_oerrors++;
967: return;
968: }
969:
970: s = splnet();
971:
972: ifp->if_opackets++;
973: ifp->if_flags &= ~IFF_OACTIVE;
974: ueagle_start(ifp);
975:
976: splx(s);
977: }
978:
979: /*
980: * Segmentation part of the software ATM AAL5 SAR.
981: */
982: int
983: ueagle_encap(struct ueagle_softc *sc, struct mbuf *m0)
984: {
985: struct ueagle_vcc *vcc = &sc->vcc;
986: struct ueagle_txreq *req;
987: struct mbuf *m;
988: uint8_t *src, *dst;
989: uint32_t crc;
990: int n, cellleft, mleft;
991: usbd_status error;
992:
993: req = &sc->txreqs[0];
994:
995: m_adj(m0, sizeof (struct atm_pseudohdr));
996:
997: dst = req->buf;
998: cellleft = 0;
999: crc = CRC_INITIAL;
1000:
1001: for (m = m0; m != NULL; m = m->m_next) {
1002: src = mtod(m, uint8_t *);
1003: mleft = m->m_len;
1004:
1005: crc = ueagle_crc_update(crc, src, mleft);
1006:
1007: if (cellleft != 0) {
1008: n = min(mleft, cellleft);
1009:
1010: memcpy(dst, src, n);
1011: dst += n;
1012: src += n;
1013: cellleft -= n;
1014: mleft -= n;
1015: }
1016:
1017: while (mleft >= ATM_CELL_PAYLOAD_SIZE) {
1018: memcpy(dst, vcc->ch, ATM_CELL_HEADER_SIZE);
1019: dst += ATM_CELL_HEADER_SIZE;
1020: memcpy(dst, src, ATM_CELL_PAYLOAD_SIZE);
1021: dst += ATM_CELL_PAYLOAD_SIZE;
1022: src += ATM_CELL_PAYLOAD_SIZE;
1023: mleft -= ATM_CELL_PAYLOAD_SIZE;
1024: sc->stats.atm.cells_transmitted++;
1025: }
1026:
1027: if (mleft != 0) {
1028: memcpy(dst, vcc->ch, ATM_CELL_HEADER_SIZE);
1029: dst += ATM_CELL_HEADER_SIZE;
1030: memcpy(dst, src, mleft);
1031: dst += mleft;
1032: cellleft = ATM_CELL_PAYLOAD_SIZE - mleft;
1033: sc->stats.atm.cells_transmitted++;
1034: }
1035: }
1036:
1037: /*
1038: * If there is not enough space to put the AAL5 trailer into this cell,
1039: * pad the content of this cell with zeros and create a new cell which
1040: * will contain no data except the AAL5 trailer itself.
1041: */
1042: if (cellleft < AAL5_TRAILER_SIZE) {
1043: memset(dst, 0, cellleft);
1044: crc = ueagle_crc_update(crc, dst, cellleft);
1045: dst += cellleft;
1046:
1047: memcpy(dst, vcc->ch, ATM_CELL_HEADER_SIZE);
1048: dst += ATM_CELL_HEADER_SIZE;
1049: cellleft = ATM_CELL_PAYLOAD_SIZE;
1050: sc->stats.atm.cells_transmitted++;
1051: }
1052:
1053: /*
1054: * Fill the AAL5 CPCS-PDU trailer.
1055: */
1056: memset(dst, 0, cellleft - AAL5_TRAILER_SIZE);
1057:
1058: /* src now points to the beginning of the last cell */
1059: src = dst + cellleft - ATM_CELL_SIZE;
1060: ATM_CH_SETPTFLAGS(src, 1);
1061:
1062: AAL5_TR_SETCPSUU(src, 0);
1063: AAL5_TR_SETCPI(src, 0);
1064: AAL5_TR_SETPDULEN(src, m0->m_pkthdr.len);
1065:
1066: crc = ~ueagle_crc_update(crc, dst, cellleft - 4);
1067: AAL5_TR_SETCRC(src, crc);
1068:
1069: usbd_setup_xfer(req->xfer, sc->pipeh_tx, req, req->buf,
1070: dst + cellleft - req->buf, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
1071: UEAGLE_TX_TIMEOUT, ueagle_txeof);
1072:
1073: error = usbd_transfer(req->xfer);
1074: if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
1075: return error;
1076:
1077: sc->stats.atm.cspdus_transmitted++;
1078:
1079: return 0;
1080: }
1081:
1082: void
1083: ueagle_start(struct ifnet *ifp)
1084: {
1085: struct ueagle_softc *sc = ifp->if_softc;
1086: struct mbuf *m0;
1087:
1088: /* nothing goes out until modem is synchronized and VCC is opened */
1089: if (!(sc->vcc.flags & UEAGLE_VCC_ACTIVE))
1090: return;
1091:
1092: if (sc->pipeh_tx == NULL)
1093: return;
1094:
1095: IFQ_POLL(&ifp->if_snd, m0);
1096: if (m0 == NULL)
1097: return;
1098: IFQ_DEQUEUE(&ifp->if_snd, m0);
1099:
1100: if (ueagle_encap(sc, m0) != 0) {
1101: m_freem(m0);
1102: return;
1103: }
1104:
1105: #if NBPFILTER > 0
1106: if (ifp->if_bpf != NULL)
1107: bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
1108: #endif
1109:
1110: m_freem(m0);
1111:
1112: ifp->if_flags |= IFF_OACTIVE;
1113: }
1114:
1115: int
1116: ueagle_open_vcc(struct ueagle_softc *sc, struct atm_pseudoioctl *api)
1117: {
1118: struct ueagle_vcc *vcc = &sc->vcc;
1119:
1120: DPRINTF(("%s: opening ATM VCC\n", sc->sc_dev.dv_xname));
1121:
1122: vcc->vpi = ATM_PH_VPI(&api->aph);
1123: vcc->vci = ATM_PH_VCI(&api->aph);
1124: vcc->rxhand = api->rxhand;
1125: vcc->m = NULL;
1126: vcc->aph = api->aph;
1127: vcc->flags = UEAGLE_VCC_ACTIVE;
1128:
1129: /* pre-calculate cell headers (HEC field is set by hardware) */
1130: ATM_CH_FILL(vcc->ch, 0, vcc->vpi, vcc->vci, 0, 0, 0);
1131:
1132: return 0;
1133: }
1134:
1135: int
1136: ueagle_close_vcc(struct ueagle_softc *sc, struct atm_pseudoioctl *api)
1137: {
1138: DPRINTF(("%s: closing ATM VCC\n", sc->sc_dev.dv_xname));
1139:
1140: sc->vcc.flags &= ~UEAGLE_VCC_ACTIVE;
1141:
1142: return 0;
1143: }
1144:
1145: int
1146: ueagle_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1147: {
1148: struct ueagle_softc *sc = ifp->if_softc;
1149: struct atm_pseudoioctl *api;
1150: struct ifaddr *ifa;
1151: struct ifreq *ifr;
1152: int s, error = 0;
1153:
1154: s = splnet();
1155:
1156: switch (cmd) {
1157: case SIOCSIFADDR:
1158: ifa = (struct ifaddr *)data;
1159: ifp->if_flags |= IFF_UP;
1160:
1161: ueagle_init(ifp);
1162: #ifdef INET
1163: ifa->ifa_rtrequest = atm_rtrequest;
1164: #endif
1165: break;
1166:
1167: case SIOCSIFFLAGS:
1168: if (ifp->if_flags & IFF_UP) {
1169: if (!(ifp->if_flags & IFF_RUNNING))
1170: ueagle_init(ifp);
1171: } else {
1172: if (ifp->if_flags & IFF_RUNNING)
1173: ueagle_stop(ifp, 1);
1174: }
1175: break;
1176:
1177: case SIOCSIFMTU:
1178: ifr = (struct ifreq *)data;
1179:
1180: if (ifr->ifr_mtu > UEAGLE_IFMTU)
1181: error = EINVAL;
1182: else
1183: ifp->if_mtu = ifr->ifr_mtu;
1184: break;
1185:
1186: case SIOCATMENA:
1187: api = (struct atm_pseudoioctl *)data;
1188: error = ueagle_open_vcc(sc, api);
1189: break;
1190:
1191: case SIOCATMDIS:
1192: api = (struct atm_pseudoioctl *)data;
1193: error = ueagle_close_vcc(sc, api);
1194: break;
1195:
1196: default:
1197: error = EINVAL;
1198: }
1199:
1200: splx(s);
1201:
1202: return error;
1203: }
1204:
1205: int
1206: ueagle_open_pipes(struct ueagle_softc *sc)
1207: {
1208: usb_endpoint_descriptor_t *edesc;
1209: usbd_interface_handle iface;
1210: struct ueagle_txreq *txreq;
1211: struct ueagle_isoreq *isoreq;
1212: usbd_status error;
1213: uint8_t *buf;
1214: int i, j;
1215:
1216: error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_US_IFACE_NO,
1217: &iface);
1218: if (error != 0) {
1219: printf("%s: could not get tx interface handle\n",
1220: sc->sc_dev.dv_xname);
1221: goto fail;
1222: }
1223:
1224: error = usbd_open_pipe(iface, UEAGLE_TX_PIPE, USBD_EXCLUSIVE_USE,
1225: &sc->pipeh_tx);
1226: if (error != 0) {
1227: printf("%s: could not open tx pipe\n", sc->sc_dev.dv_xname);
1228: goto fail;
1229: }
1230:
1231: for (i = 0; i < UEAGLE_TX_LIST_CNT; i++) {
1232: txreq = &sc->txreqs[i];
1233:
1234: txreq->sc = sc;
1235:
1236: txreq->xfer = usbd_alloc_xfer(sc->sc_udev);
1237: if (txreq->xfer == NULL) {
1238: printf("%s: could not allocate tx xfer\n",
1239: sc->sc_dev.dv_xname);
1240: error = ENOMEM;
1241: goto fail;
1242: }
1243:
1244: txreq->buf = usbd_alloc_buffer(txreq->xfer, UEAGLE_TXBUFLEN);
1245: if (txreq->buf == NULL) {
1246: printf("%s: could not allocate tx buffer\n",
1247: sc->sc_dev.dv_xname);
1248: error = ENOMEM;
1249: goto fail;
1250: }
1251: }
1252:
1253: error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_DS_IFACE_NO,
1254: &iface);
1255: if (error != 0) {
1256: printf("%s: could not get rx interface handle\n",
1257: sc->sc_dev.dv_xname);
1258: goto fail;
1259: }
1260:
1261: /* XXX: alternative interface number sould depend on downrate */
1262: error = usbd_set_interface(iface, 8);
1263: if (error != 0) {
1264: printf("%s: could not set rx alternative interface\n",
1265: sc->sc_dev.dv_xname);
1266: goto fail;
1267: }
1268:
1269: edesc = usbd_get_endpoint_descriptor(iface, UEAGLE_RX_PIPE);
1270: if (edesc == NULL) {
1271: printf("%s: could not get rx endpoint descriptor\n",
1272: sc->sc_dev.dv_xname);
1273: error = EIO;
1274: goto fail;
1275: }
1276:
1277: sc->isize = UGETW(edesc->wMaxPacketSize);
1278:
1279: error = usbd_open_pipe(iface, UEAGLE_RX_PIPE, USBD_EXCLUSIVE_USE,
1280: &sc->pipeh_rx);
1281: if (error != 0) {
1282: printf("%s: could not open rx pipe\n", sc->sc_dev.dv_xname);
1283: goto fail;
1284: }
1285:
1286: for (i = 0; i < UEAGLE_NISOREQS; i++) {
1287: isoreq = &sc->isoreqs[i];
1288:
1289: isoreq->sc = sc;
1290:
1291: isoreq->xfer = usbd_alloc_xfer(sc->sc_udev);
1292: if (isoreq->xfer == NULL) {
1293: printf("%s: could not allocate rx xfer\n",
1294: sc->sc_dev.dv_xname);
1295: error = ENOMEM;
1296: goto fail;
1297: }
1298:
1299: buf = usbd_alloc_buffer(isoreq->xfer,
1300: sc->isize * UEAGLE_NISOFRMS);
1301: if (buf == NULL) {
1302: printf("%s: could not allocate rx buffer\n",
1303: sc->sc_dev.dv_xname);
1304: error = ENOMEM;
1305: goto fail;
1306: }
1307:
1308: for (j = 0; j < UEAGLE_NISOFRMS; j++) {
1309: isoreq->frlengths[j] = sc->isize;
1310: isoreq->offsets[j] = buf + j * sc->isize;
1311: }
1312:
1313: usbd_setup_isoc_xfer(isoreq->xfer, sc->pipeh_rx, isoreq,
1314: isoreq->frlengths, UEAGLE_NISOFRMS, USBD_NO_COPY,
1315: ueagle_rxeof);
1316: usbd_transfer(isoreq->xfer);
1317: }
1318:
1319: ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_LOOPBACKOFF, NULL, 0);
1320:
1321: return 0;
1322:
1323: fail: ueagle_close_pipes(sc);
1324: return error;
1325: }
1326:
1327: void
1328: ueagle_close_pipes(struct ueagle_softc *sc)
1329: {
1330: int i;
1331:
1332: ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_LOOPBACKON, NULL, 0);
1333:
1334: /* free Tx resources */
1335: if (sc->pipeh_tx != NULL) {
1336: usbd_abort_pipe(sc->pipeh_tx);
1337: usbd_close_pipe(sc->pipeh_tx);
1338: sc->pipeh_tx = NULL;
1339: }
1340:
1341: for (i = 0; i < UEAGLE_TX_LIST_CNT; i++) {
1342: if (sc->txreqs[i].xfer != NULL) {
1343: usbd_free_xfer(sc->txreqs[i].xfer);
1344: sc->txreqs[i].xfer = NULL;
1345: }
1346: }
1347:
1348: /* free Rx resources */
1349: if (sc->pipeh_rx != NULL) {
1350: usbd_abort_pipe(sc->pipeh_rx);
1351: usbd_close_pipe(sc->pipeh_rx);
1352: sc->pipeh_rx = NULL;
1353: }
1354:
1355: for (i = 0; i < UEAGLE_NISOREQS; i++) {
1356: if (sc->isoreqs[i].xfer != NULL) {
1357: usbd_free_xfer(sc->isoreqs[i].xfer);
1358: sc->isoreqs[i].xfer = NULL;
1359: }
1360: }
1361: }
1362:
1363: int
1364: ueagle_init(struct ifnet *ifp)
1365: {
1366: struct ueagle_softc *sc = ifp->if_softc;
1367: usbd_interface_handle iface;
1368: usbd_status error;
1369: size_t len;
1370:
1371: ueagle_stop(ifp, 0);
1372:
1373: error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_US_IFACE_NO,
1374: &iface);
1375: if (error != 0) {
1376: printf("%s: could not get idma interface handle\n",
1377: sc->sc_dev.dv_xname);
1378: goto fail;
1379: }
1380:
1381: error = usbd_open_pipe(iface, UEAGLE_IDMA_PIPE, USBD_EXCLUSIVE_USE,
1382: &sc->pipeh_idma);
1383: if (error != 0) {
1384: printf("%s: could not open idma pipe\n",
1385: sc->sc_dev.dv_xname);
1386: goto fail;
1387: }
1388:
1389: error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_INTR_IFACE_NO,
1390: &iface);
1391: if (error != 0) {
1392: printf("%s: could not get interrupt interface handle\n",
1393: sc->sc_dev.dv_xname);
1394: goto fail;
1395: }
1396:
1397: error = loadfirmware("ueagle-dsp", &sc->dsp, &len);
1398: if (error != 0) {
1399: printf("%s: could not load firmware\n", sc->sc_dev.dv_xname);
1400: goto fail;
1401: }
1402:
1403: error = usbd_open_pipe_intr(iface, UEAGLE_INTR_PIPE, USBD_SHORT_XFER_OK,
1404: &sc->pipeh_intr, sc, sc->ibuf, UEAGLE_INTR_MAXSIZE, ueagle_intr,
1405: UEAGLE_INTR_INTERVAL);
1406: if (error != 0) {
1407: printf("%s: could not open interrupt pipe\n",
1408: sc->sc_dev.dv_xname);
1409: goto fail;
1410: }
1411:
1412: error = ueagle_boot(sc);
1413: if (error != 0) {
1414: printf("%s: could not boot modem\n", sc->sc_dev.dv_xname);
1415: goto fail;
1416: }
1417:
1418: /*
1419: * Opening of tx and rx pipes if deferred after synchronization is
1420: * established.
1421: */
1422:
1423: ifp->if_flags |= IFF_RUNNING;
1424: ifp->if_flags &= ~IFF_OACTIVE;
1425:
1426: return 0;
1427:
1428: fail: ueagle_stop(ifp, 1);
1429: return error;
1430: }
1431:
1432: void
1433: ueagle_stop(struct ifnet *ifp, int disable)
1434: {
1435: struct ueagle_softc *sc = ifp->if_softc;
1436:
1437: /* stop any pending task */
1438: usb_rem_task(sc->sc_udev, &sc->sc_swap_task);
1439:
1440: /* free Tx and Rx resources */
1441: ueagle_close_pipes(sc);
1442:
1443: /* free firmware */
1444: if (sc->dsp != NULL) {
1445: free(sc->dsp, M_DEVBUF);
1446: sc->dsp = NULL;
1447: }
1448:
1449: /* free interrupt resources */
1450: if (sc->pipeh_intr != NULL) {
1451: usbd_abort_pipe(sc->pipeh_intr);
1452: usbd_close_pipe(sc->pipeh_intr);
1453: sc->pipeh_intr = NULL;
1454: }
1455:
1456: /* free IDMA resources */
1457: if (sc->pipeh_idma != NULL) {
1458: usbd_abort_pipe(sc->pipeh_idma);
1459: usbd_close_pipe(sc->pipeh_idma);
1460: sc->pipeh_idma = NULL;
1461: }
1462:
1463: /* reset statistics */
1464: memset(&sc->stats, 0, sizeof (struct ueagle_stats));
1465:
1466: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1467: }
1468:
1469: int
1470: ueagle_activate(struct device *self, enum devact act)
1471: {
1472: struct ueagle_softc *sc = (struct ueagle_softc *)self;
1473:
1474: switch (act) {
1475: case DVACT_ACTIVATE:
1476: break;
1477:
1478: case DVACT_DEACTIVATE:
1479: sc->gone = 1;
1480: break;
1481: }
1482:
1483: return 0;
1484: }
CVSweb