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