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