This source file includes following definitions.
- ueagle_match
- ueagle_attachhook
- ueagle_attach
- ueagle_detach
- ueagle_getesi
- ueagle_loadpage
- ueagle_request
- ueagle_dump_cmv
- ueagle_cr
- ueagle_cw
- ueagle_stat
- ueagle_stat_thread
- ueagle_boot
- ueagle_swap_intr
- ueagle_cmv_intr
- ueagle_intr
- ueagle_crc_update
- ueagle_push_cell
- ueagle_rxeof
- ueagle_txeof
- ueagle_encap
- ueagle_start
- ueagle_open_vcc
- ueagle_close_vcc
- ueagle_ioctl
- ueagle_open_pipes
- ueagle_close_pipes
- ueagle_init
- ueagle_stop
- ueagle_activate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
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
187
188
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
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
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;
253
254 sc->gone = 1;
255 ueagle_stop(ifp, 1);
256
257
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
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;
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
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
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
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
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:
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:
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:
534 DPRINTFN(4, ("%s: operational\n", sc->sc_dev.dv_xname));
535 break;
536
537 default:
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
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
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
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
657
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
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
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
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
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
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
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
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
1039
1040
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
1055
1056 memset(dst, 0, cellleft - AAL5_TRAILER_SIZE);
1057
1058
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
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
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
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
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
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
1420
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
1438 usb_rem_task(sc->sc_udev, &sc->sc_swap_task);
1439
1440
1441 ueagle_close_pipes(sc);
1442
1443
1444 if (sc->dsp != NULL) {
1445 free(sc->dsp, M_DEVBUF);
1446 sc->dsp = NULL;
1447 }
1448
1449
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
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
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 }