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