xref: /netbsd/sys/dev/pci/oboe.c (revision bf9ec67e)
1 /*	$NetBSD: oboe.c,v 1.5 2001/12/11 21:34:06 augustss Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jan Sparud.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Toshiba OBOE IrDA SIR/FIR driver.
41  *
42  * Based on information from the Linux driver, thus the magic hex numbers.
43  */
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/device.h>
49 #include <sys/malloc.h>
50 #include <sys/tty.h>
51 #include <sys/vnode.h>
52 #include <sys/poll.h>
53 
54 #include <dev/ir/ir.h>
55 #include <dev/ir/irdaio.h>
56 #include <dev/ir/irframevar.h>
57 #include <dev/ir/sir.h>
58 
59 #include <dev/pci/pcidevs.h>
60 #include <dev/pci/pcivar.h>
61 
62 #include <machine/bus.h>
63 #include <machine/intr.h>
64 #include <uvm/uvm_extern.h>
65 
66 #include <dev/pci/oboereg.h>
67 
68 int oboe_match(struct device *parent, struct cfdata *match, void *aux);
69 void oboe_attach(struct device *parent, struct device *self, void *aux);
70 int oboe_activate(struct device *self, enum devact act);
71 int oboe_detach(struct device *self, int flags);
72 
73 int oboe_open(void *h, int flag, int mode, struct proc *p);
74 int oboe_close(void *h, int flag, int mode, struct proc *p);
75 int oboe_read(void *h, struct uio *uio, int flag);
76 int oboe_write(void *h, struct uio *uio, int flag);
77 int oboe_set_params(void *h, struct irda_params *params);
78 int oboe_get_speeds(void *h, int *speeds);
79 int oboe_get_turnarounds(void *h, int *times);
80 int oboe_poll(void *h, int events, struct proc *p);
81 
82 #ifdef OBOE_DEBUG
83 #define DPRINTF(x)	if (oboedebug) printf x
84 int oboedebug = 1;
85 #else
86 #define DPRINTF(x)
87 #endif
88 
89 struct oboe_dma;
90 
91 struct oboe_softc {
92 	struct device		sc_dev;
93 	struct device		*sc_child;
94 	struct pci_attach_args	sc_pa;
95 	pci_intr_handle_t *	sc_ih;
96 	unsigned int		sc_revision;	/* PCI Revision ID */
97 	/* I/O Base device */
98 	bus_space_tag_t		sc_iot;
99 	bus_space_handle_t	sc_ioh;
100 	bus_dma_tag_t		sc_dmatag;
101 	struct selinfo		sc_rsel;
102 
103 	int			sc_state;
104 #define	OBOE_RSLP		0x01	/* waiting for data (read) */
105 #define	OBOE_WSLP		0x02	/* waiting for data (write) */
106 #define OBOE_CLOSING		0x04	/* waiting for output to drain */
107 
108 	int			sc_speeds;
109 	int			sc_flags;
110 	int			sc_speed;
111 	int			sc_ebofs;
112 
113 	struct oboe_dma		*sc_dmas;
114 	struct OboeTaskFile	*sc_taskfile;    /* The taskfile   */
115 	u_char *		sc_xmit_bufs[TX_SLOTS];
116 	u_char *		sc_recv_bufs[RX_SLOTS];
117 	void *			sc_xmit_stores[TX_SLOTS];
118 	void *			sc_recv_stores[RX_SLOTS];
119 	int			sc_txs; /* Current transmit slot number */
120 	int			sc_rxs; /* Current receive slot number */
121 	int			sc_saved; /* number of saved frames */
122 	int			sc_lens[RX_SLOTS];
123 
124 	int			sc_txpending;
125 
126 	/* Statistics */
127 	int			sc_txpackets;
128 	int			sc_rxpackets;
129 	int			sc_txerrors;
130 	int			sc_rxerrors;
131 };
132 
133 static int oboe_intr(void *handle);
134 static int oboe_reset(struct oboe_softc *);
135 
136 struct oboe_dma {
137 	bus_dmamap_t map;
138 	caddr_t addr;
139 	bus_dma_segment_t segs[1];
140 	int nsegs;
141 	size_t size;
142 	struct oboe_dma *next;
143 };
144 
145 #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
146 #define KERNADDR(p) ((void *)((p)->addr))
147 
148 static int oboe_alloc_taskfile(struct oboe_softc *);
149 static void oboe_init_taskfile(struct oboe_softc *);
150 static void oboe_startchip(struct oboe_softc *);
151 static void oboe_stopchip(struct oboe_softc *);
152 static int oboe_setbaud(struct oboe_softc *, int);
153 
154 struct cfattach oboe_ca = {
155 	sizeof(struct oboe_softc), oboe_match, oboe_attach,
156 	oboe_detach, oboe_activate
157 };
158 
159 struct irframe_methods oboe_methods = {
160 	oboe_open, oboe_close, oboe_read, oboe_write, oboe_poll,
161 	oboe_set_params, oboe_get_speeds, oboe_get_turnarounds
162 };
163 
164 int
165 oboe_match(struct device *parent, struct cfdata *match, void *aux)
166 {
167 	struct pci_attach_args *pa = aux;
168 
169 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TOSHIBA2 &&
170 	    (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_TOSHIBA2_OBOE ||
171 	     PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_TOSHIBA2_DONAUOBOE))
172 		return (1);
173 	return 0;
174 }
175 
176 void
177 oboe_attach(struct device *parent, struct device *self, void *aux)
178 {
179 	struct oboe_softc *sc = (struct oboe_softc *)self;
180 	struct pci_attach_args *pa = aux;
181 	pci_intr_handle_t ih;
182 	struct ir_attach_args ia;
183 	const char *intrstring;
184 
185 	sc->sc_revision = PCI_REVISION(pa->pa_class);
186 	printf(": Toshiba Fast Infrared Type O, revision %d\n",
187 	       sc->sc_revision);
188 
189 	/* Map I/O registers. */
190 	if (pci_mapreg_map(pa, IO_BAR, PCI_MAPREG_TYPE_IO, 0,
191 	    &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) {
192 		printf("%s: can't map I/O space\n", sc->sc_dev.dv_xname);
193 		return;
194 	}
195 
196 	sc->sc_dmatag = pa->pa_dmat;
197 
198 	ia.ia_type = IR_TYPE_IRFRAME;
199 	ia.ia_methods = &oboe_methods;
200 	ia.ia_handle = sc;
201 
202 	sc->sc_state = 0;
203 	sc->sc_speed = IRDA_SPEED_9600;
204 
205 	/* Enable the device */
206 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
207 	    pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
208 	    PCI_COMMAND_MASTER_ENABLE);
209 
210 	/* Reset the device; bail out upon failure. */
211 	if (oboe_reset(sc) != 0) {
212 		printf("%s: can't reset\n", sc->sc_dev.dv_xname);
213 		return;
214 	}
215 	/* Map and establish the interrupt. */
216 	if (pci_intr_map(pa, &ih)) {
217 		printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
218 		return;
219 	}
220 	intrstring = pci_intr_string(pa->pa_pc, ih);
221 	sc->sc_ih  = pci_intr_establish(pa->pa_pc, ih, IPL_IR, oboe_intr, sc);
222 	if (sc->sc_ih == NULL) {
223 		printf("%s: couldn't establish interrupt",
224 		    sc->sc_dev.dv_xname);
225 		if (intrstring != NULL)
226 			printf(" at %s", intrstring);
227 		printf("\n");
228 		return;
229 	}
230 	printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstring);
231 
232 	sc->sc_txs = 0;
233 	sc->sc_rxs = 0;
234 
235 	sc->sc_speeds =
236 		IRDA_SPEED_2400   | IRDA_SPEED_9600    | IRDA_SPEED_19200 |
237 		IRDA_SPEED_38400  | IRDA_SPEED_57600   | IRDA_SPEED_115200 |
238 		IRDA_SPEED_576000 | IRDA_SPEED_1152000 | IRDA_SPEED_4000000;
239 
240 	oboe_alloc_taskfile(sc);
241 
242 	sc->sc_child = config_found((void *)sc, &ia, ir_print);
243 }
244 
245 int
246 oboe_activate(struct device *self, enum devact act)
247 {
248 	struct oboe_softc *sc = (struct oboe_softc *)self;
249 	int error;
250 
251 	DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
252 
253 	switch (act) {
254 	case DVACT_ACTIVATE:
255 		return (EOPNOTSUPP);
256 		break;
257 
258 	case DVACT_DEACTIVATE:
259 		if (sc->sc_child != NULL)
260 			error = config_deactivate(sc->sc_child);
261 		else
262 			error = 0;
263 		break;
264 	}
265 	return (error);
266 }
267 
268 int
269 oboe_detach(struct device *self, int flags)
270 {
271 #if 0
272 	struct oboe_softc *sc = (struct oboe_softc *)self;
273 #endif
274 	/* XXX needs reference counting for proper detach. */
275 	DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
276 	return (0);
277 }
278 
279 int
280 oboe_open(void *h, int flag, int mode, struct proc *p)
281 {
282 	struct oboe_softc *sc = h;
283 
284 	DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
285 
286 	sc->sc_state = 0;
287 	sc->sc_saved = 0;
288 	oboe_init_taskfile(sc);
289 	oboe_startchip(sc);
290 
291 	return (0);
292 }
293 
294 int
295 oboe_close(void *h, int flag, int mode, struct proc *p)
296 {
297 	struct oboe_softc *sc = h;
298 	int error = 0;
299 	int s = splir();
300 
301 	DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
302 	/* Wait for output to drain */
303 
304 	if (sc->sc_txpending > 0) {
305 		sc->sc_state |= OBOE_CLOSING;
306 		error = tsleep(&sc->sc_state, PZERO | PCATCH, "oboecl", hz/10);
307 	}
308 	splx(s);
309 
310 	oboe_stopchip(sc);
311 	return (error);
312 }
313 
314 int
315 oboe_read(void *h, struct uio *uio, int flag)
316 {
317 	struct oboe_softc *sc = h;
318 	int error = 0;
319 	int s;
320 	int slot;
321 
322 	DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
323 		 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
324 		 (long)uio->uio_offset));
325 
326 	s = splir();
327 	while (sc->sc_saved == 0) {
328 		if (flag & IO_NDELAY) {
329 			splx(s);
330 			return (EWOULDBLOCK);
331 		}
332 		sc->sc_state |= OBOE_RSLP;
333 		DPRINTF(("oboe_read: sleep\n"));
334 		error = tsleep(&sc->sc_rxs, PZERO | PCATCH, "oboerd", 0);
335 		DPRINTF(("oboe_read: woke, error=%d\n", error));
336 		if (error) {
337 			sc->sc_state &= ~OBOE_RSLP;
338 			break;
339 		}
340 	}
341 
342 	/* Do just one frame transfer per read */
343 
344 	if (!error) {
345 		slot = (sc->sc_rxs - sc->sc_saved + RX_SLOTS) % RX_SLOTS;
346 		if (uio->uio_resid < sc->sc_lens[slot]) {
347 			DPRINTF(("oboe_read: uio buffer smaller than frame size"
348 			    "(%d < %d)\n", uio->uio_resid, sc->sc_lens[slot]));
349 			error = EINVAL;
350 		} else {
351 			DPRINTF(("oboe_read: moving %d bytes from %p\n",
352 				 sc->sc_lens[slot],
353 				 sc->sc_recv_stores[slot]));
354 			error = uiomove(sc->sc_recv_stores[slot],
355 					sc->sc_lens[slot], uio);
356 		}
357 	}
358 	sc->sc_saved--;
359 	splx(s);
360 
361 	return (error);
362 }
363 
364 int
365 oboe_write(void *h, struct uio *uio, int flag)
366 {
367 	struct oboe_softc *sc = h;
368 	int error = 0;
369 	int n;
370 	int s = splir();
371 
372 	DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
373 	while (sc->sc_txpending == TX_SLOTS) {
374 		if (flag & IO_NDELAY) {
375 			splx(s);
376 			return (EWOULDBLOCK);
377 		}
378 		sc->sc_state |= OBOE_WSLP;
379 		DPRINTF(("oboe_write: sleep\n"));
380 		error = tsleep(&sc->sc_txs, PZERO | PCATCH, "oboewr", 0);
381 		DPRINTF(("oboe_write: woke up, error=%d\n", error));
382 		if (error) {
383 			sc->sc_state &= ~OBOE_WSLP;
384 			break;
385 		}
386 	}
387 	if (error)
388 		goto err;
389 	if (sc->sc_taskfile->xmit[sc->sc_txs].control) {
390 		DPRINTF(("oboe_write: slot overrun\n"));
391 	}
392 
393 	n = irda_sir_frame(sc->sc_xmit_bufs[sc->sc_txs], TX_BUF_SZ, uio,
394 			   sc->sc_ebofs);
395 	if (n < 0) {
396 		error = -n;
397 		goto err;
398 	}
399 	sc->sc_taskfile->xmit[sc->sc_txs].len = n;
400 
401 	OUTB(sc, 0, OBOE_RST);
402 	OUTB(sc, 0x1e, OBOE_REG_11);
403 
404 	sc->sc_taskfile->xmit[sc->sc_txs].control = 0x84;
405 
406 	/* XXX Need delay here??? */
407 	delay(1000);
408 
409 	sc->sc_txpending++;
410 	OUTB(sc, 0x80, OBOE_RST);
411 	OUTB(sc, 1, OBOE_REG_9);
412 	sc->sc_txs++;
413 	sc->sc_txs %= TX_SLOTS;
414 
415  err:
416 	splx(s);
417 	return (error);
418 }
419 
420 int
421 oboe_set_params(void *h, struct irda_params *p)
422 {
423 	struct oboe_softc *sc = h;
424 	int error;
425 
426 	if (p->speed > 0) {
427 		error = oboe_setbaud(sc, p->speed);
428 		if (error)
429 			return (error);
430 	}
431 	sc->sc_ebofs = p->ebofs;
432 
433 	/* XXX ignore ebofs and maxsize for now */
434 	return (0);
435 }
436 
437 int
438 oboe_get_speeds(void *h, int *speeds)
439 {
440 	struct oboe_softc *sc = h;
441 	*speeds = sc->sc_speeds;
442 	return (0);
443 }
444 
445 int
446 oboe_get_turnarounds(void *h, int *turnarounds)
447 {
448 #if 0
449 	struct oboe_softc *sc = h;
450 #endif
451 	DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
452 	/* XXX Linux driver sets all bits */
453 	*turnarounds = IRDA_TURNT_10000; /* 10ms */
454 	return (0);
455 }
456 
457 int
458 oboe_poll(void *h, int events, struct proc *p)
459 {
460 	struct oboe_softc *sc = h;
461 	int revents = 0;
462 	int s;
463 
464 	DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
465 
466 	s = splir();
467 	if (events & (POLLOUT | POLLWRNORM))
468 		revents |= events & (POLLOUT | POLLWRNORM);
469 	if (events & (POLLIN | POLLRDNORM)) {
470 		if (sc->sc_saved > 0) {
471 			DPRINTF(("%s: have data\n", __FUNCTION__));
472 			revents |= events & (POLLIN | POLLRDNORM);
473 		} else {
474 			DPRINTF(("%s: recording select\n", __FUNCTION__));
475 			selrecord(p, &sc->sc_rsel);
476 		}
477 	}
478 	splx(s);
479 
480 	return (revents);
481 }
482 
483 
484 static int
485 oboe_reset(struct oboe_softc *sc)
486 {
487 #if 0
488 	OUTB(sc, 0x00, OBOE_RST);
489 	OUTB(sc, 0x80, OBOE_RST);
490 #endif
491 	return 0;
492 }
493 
494 static int
495 oboe_intr(void *p)
496 {
497 	struct oboe_softc *sc = p;
498 	uint8_t irqstat	= INB(sc, OBOE_ISR);
499 
500 	if (!(irqstat & 0xf8))
501 		return (0); /* Not for me? */
502 
503 	DPRINTF(("oboe_intr stat=0x%x\n", irqstat));
504 
505 	OUTB(sc, irqstat, OBOE_ISR);
506 
507 	if (irqstat & OBOE_ISR_RXDONE) {
508 		while (sc->sc_taskfile->recv[sc->sc_rxs].control == 0) {
509 			int len = sc->sc_taskfile->recv[sc->sc_rxs].len;
510 			if (sc->sc_saved == RX_SLOTS) {
511 				DPRINTF(("oboe_intr: all buffers filled\n"));
512 				return 0;
513 			}
514 
515 			if (len > 2)
516 				len -= 2; /* JSP: skip check sum? */
517 
518 			DPRINTF(("oboe_intr: moving %d bytes to %p\n", len,
519 				 sc->sc_recv_stores[sc->sc_rxs]));
520 			memcpy(sc->sc_recv_stores[sc->sc_rxs],
521 			       sc->sc_recv_bufs[sc->sc_rxs],
522 			       len);
523 			sc->sc_lens[sc->sc_rxs] = len;
524 			sc->sc_saved++;
525 #if 0
526 			(void)b_to_q(sc->sc_recv_bufs[sc->sc_rxs],
527 				     len, &sc->sc_q);
528 #endif
529 			sc->sc_taskfile->recv[sc->sc_rxs].control = 0x83;
530 			sc->sc_taskfile->recv[sc->sc_rxs].len = 0x0;
531 			sc->sc_rxs = (sc->sc_rxs + 1) % RX_SLOTS;
532 			DPRINTF(("oboe_intr new rxs=%d\n", sc->sc_rxs));
533 		}
534 		DPRINTF(("oboe_intr no more frames available\n"));
535 		if (sc->sc_state & OBOE_RSLP) {
536 			DPRINTF(("oboe_intr changing state to ~OBOE_RSLP\n"));
537 			sc->sc_state &= ~OBOE_RSLP;
538 			DPRINTF(("oboe_intr: waking up reader\n"));
539 			wakeup(&sc->sc_rxs);
540 		}
541 		selwakeup(&sc->sc_rsel);
542 		DPRINTF(("oboe_intr returning\n"));
543 	}
544 	if (irqstat & OBOE_ISR_TXDONE) {
545 	        DPRINTF(("oboe_intr: write done\n"));
546 		sc->sc_txpending--;
547 		sc->sc_txpackets++;
548 
549 		if ((sc->sc_state & OBOE_CLOSING) && sc->sc_txpending == 0) {
550 			wakeup(&sc->sc_state);
551 			return 1;
552 		}
553 
554 		if (sc->sc_state & OBOE_WSLP) {
555 			DPRINTF(("oboe_intr changing state to ~OBOE_WSLP\n"));
556 			sc->sc_state &= ~OBOE_WSLP;
557 			DPRINTF(("oboe_intr: waking up writer\n"));
558 			wakeup(&sc->sc_txs);
559 		}
560 	}
561 	return (1);
562 }
563 
564 /* XXX vtophys must go! */
565 static void
566 oboe_init_taskfile(struct oboe_softc *sc)
567 {
568 	int i;
569 	int s = splir();
570 
571 	for (i = 0; i < TX_SLOTS; ++i) {
572 		sc->sc_taskfile->xmit[i].len = 0;
573 		sc->sc_taskfile->xmit[i].control = 0x00;
574 		sc->sc_taskfile->xmit[i].buffer =
575 			vtophys((u_int)sc->sc_xmit_bufs[i]); /* u_int? */
576 	}
577 
578 	for (i = 0; i < RX_SLOTS; ++i) {
579 		sc->sc_taskfile->recv[i].len = 0;
580 		sc->sc_taskfile->recv[i].control = 0x83;
581 		sc->sc_taskfile->recv[i].buffer =
582 			vtophys((u_int)sc->sc_recv_bufs[i]); /* u_int? */
583 	}
584 
585 	sc->sc_txpending = 0;
586 
587 	splx(s);
588 }
589 
590 static int
591 oboe_alloc_taskfile(struct oboe_softc *sc)
592 {
593 	int i;
594 	/* XXX */
595 	uint32_t addr = (uint32_t)malloc(OBOE_TASK_BUF_LEN, M_DEVBUF, M_WAITOK);
596 	if (addr == NULL) {
597 		goto bad;
598 	}
599 	addr &= ~(sizeof (struct OboeTaskFile) - 1);
600 	addr += sizeof (struct OboeTaskFile);
601 	sc->sc_taskfile = (struct OboeTaskFile *) addr;
602 
603 	for (i = 0; i < TX_SLOTS; ++i) {
604 		sc->sc_xmit_bufs[i] =
605 			malloc(TX_BUF_SZ, M_DEVBUF, M_WAITOK);
606 		sc->sc_xmit_stores[i] =
607 			malloc(TX_BUF_SZ, M_DEVBUF, M_WAITOK);
608 		if (sc->sc_xmit_bufs[i] == NULL ||
609 		    sc->sc_xmit_stores[i] == NULL) {
610 			goto bad;
611 		}
612 	}
613 	for (i = 0; i < RX_SLOTS; ++i) {
614 		sc->sc_recv_bufs[i] =
615 			malloc(RX_BUF_SZ, M_DEVBUF, M_WAITOK);
616 		sc->sc_recv_stores[i] =
617 			malloc(RX_BUF_SZ, M_DEVBUF, M_WAITOK);
618 		if (sc->sc_recv_bufs[i] == NULL ||
619 		    sc->sc_recv_stores[i] == NULL) {
620 			goto bad;
621 		}
622 	}
623 
624 	return 0;
625 bad:
626 	printf("oboe: malloc for buffers failed()\n");
627 	return 1;
628 }
629 
630 static void
631 oboe_startchip (struct oboe_softc *sc)
632 {
633 	uint32_t physaddr;
634 
635 	OUTB(sc, 0, OBOE_LOCK);
636 	OUTB(sc, 0, OBOE_RST);
637 	OUTB(sc, OBOE_NTR_VAL, OBOE_NTR);
638 	OUTB(sc, 0xf0, OBOE_REG_D);
639 	OUTB(sc, 0xff, OBOE_ISR);
640 	OUTB(sc, 0x0f, OBOE_REG_1A);
641 	OUTB(sc, 0xff, OBOE_REG_1B);
642 
643 	physaddr = vtophys((u_int)sc->sc_taskfile); /* u_int? */
644 
645 	OUTB(sc, (physaddr >> 0x0a) & 0xff, OBOE_TFP0);
646 	OUTB(sc, (physaddr >> 0x12) & 0xff, OBOE_TFP1);
647 	OUTB(sc, (physaddr >> 0x1a) & 0x3f, OBOE_TFP2);
648 
649 	OUTB(sc, 0x0e, OBOE_REG_11);
650 	OUTB(sc, 0x80, OBOE_RST);
651 
652 	(void)oboe_setbaud(sc, 9600);
653 
654 	sc->sc_rxs = INB(sc, OBOE_RCVT);
655 	if (sc->sc_rxs < 0 || sc->sc_rxs >= RX_SLOTS)
656 		sc->sc_rxs = 0;
657 	sc->sc_txs = INB(sc, OBOE_XMTT) - OBOE_XMTT_OFFSET;
658 	if (sc->sc_txs < 0 || sc->sc_txs >= TX_SLOTS)
659 		sc->sc_txs = 0;
660 }
661 
662 static void
663 oboe_stopchip (struct oboe_softc *sc)
664 {
665 	OUTB(sc, 0x0e, OBOE_REG_11);
666 	OUTB(sc, 0x00, OBOE_RST);
667 	OUTB(sc, 0x3f, OBOE_TFP2);     /* Write the taskfile address */
668 	OUTB(sc, 0xff, OBOE_TFP1);
669 	OUTB(sc, 0xff, OBOE_TFP0);
670 	OUTB(sc, 0x0f, OBOE_REG_1B);
671 	OUTB(sc, 0xff, OBOE_REG_1A);
672 	OUTB(sc, 0x00, OBOE_ISR); /* XXX: should i do this to disable ints? */
673 	OUTB(sc, 0x80, OBOE_RST);
674 	OUTB(sc, 0x0e, OBOE_LOCK);
675 }
676 
677 #define SPEEDCASE(speed, type, divisor) \
678 case speed: \
679 OUTB(sc, OBOE_PMDL_##type, OBOE_PMDL); \
680 OUTB(sc, OBOE_SMDL_##type, OBOE_SMDL); \
681 OUTB(sc, divisor, OBOE_UDIV); \
682 break
683 
684 static int
685 oboe_setbaud(struct oboe_softc *sc, int baud)
686 {
687 	int s;
688 
689 	DPRINTF(("oboe: setting baud to %d\n", baud));
690 
691 	s = splir();
692 
693 	switch (baud) {
694 	SPEEDCASE(   2400, SIR, 0xbf);
695 	SPEEDCASE(   9600, SIR, 0x2f);
696 	SPEEDCASE(  19200, SIR, 0x17);
697 	SPEEDCASE(  38400, SIR, 0x0b);
698 	SPEEDCASE(  57600, SIR, 0x07);
699 	SPEEDCASE( 115200, SIR, 0x03);
700 	SPEEDCASE(1152000, MIR, 0x01);
701 	SPEEDCASE(4000000, FIR, 0x00);
702 	default:
703 		DPRINTF(("oboe: cannot set speed to %d\n", baud));
704 		splx(s);
705 		return (EINVAL);
706 	}
707 
708 	OUTB(sc, 0x00, OBOE_RST);
709 	OUTB(sc, 0x80, OBOE_RST);
710 	OUTB(sc, 0x01, OBOE_REG_9);
711 
712 	sc->sc_speed = baud;
713 
714 	splx(s);
715 
716 	return (0);
717 }
718