gusc.c revision 53553
1183370Simp/*-
2183370Simp * Copyright (c) 1999 Seigo Tanimura
3183370Simp * Copyright (c) 1999 Ville-Pertti Keinonen
4183370Simp * All rights reserved.
5183370Simp *
6183370Simp * Redistribution and use in source and binary forms, with or without
7183370Simp * modification, are permitted provided that the following conditions
8183370Simp * are met:
9183370Simp * 1. Redistributions of source code must retain the above copyright
10183370Simp *    notice, this list of conditions and the following disclaimer.
11183370Simp * 2. Redistributions in binary form must reproduce the above copyright
12183370Simp *    notice, this list of conditions and the following disclaimer in the
13183370Simp *    documentation and/or other materials provided with the distribution.
14183370Simp *
15183370Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16183370Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17183370Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18183370Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19183370Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20183370Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21183370Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22183370Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23183370Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24183370Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25183370Simp * SUCH DAMAGE.
26183370Simp *
27183370Simp * $FreeBSD: head/sys/dev/sound/isa/gusc.c 53553 1999-11-22 06:07:49Z tanimura $
28183370Simp */
29183370Simp
30183370Simp#include "gusc.h"
31183370Simp#include "isa.h"
32183370Simp#include "pnp.h"
33183370Simp
34183370Simp#include <sys/param.h>
35183370Simp#include <sys/systm.h>
36183370Simp#include <sys/kernel.h>
37183370Simp#include <sys/bus.h>
38183370Simp#include <sys/malloc.h>
39183370Simp#include <sys/module.h>
40183370Simp#include <machine/resource.h>
41183370Simp#include <machine/bus.h>
42183370Simp#include <machine/clock.h>
43183370Simp#include <sys/rman.h>
44183370Simp#include <sys/soundcard.h>
45183370Simp#include <dev/sound/pcm/sound.h>
46183370Simp#include <dev/sound/chip.h>
47183370Simp#include "bus_if.h"
48183370Simp
49183370Simp
50183370Simp#if NISA > 0
51183370Simp#include <isa/isavar.h>
52183370Simp#include <isa/isa_common.h>
53183370Simp#ifdef __alpha__		/* XXX workaround a stupid warning */
54183370Simp#include <alpha/isa/isavar.h>
55183370Simp#endif
56183370Simp#endif /* NISA > 0 */
57183370Simp
58183370Simp#if NGUSC > 0
59183370Simp
60183370Simp#define LOGICALID_PCM  0x0000561e
61183370Simp#define LOGICALID_OPL  0x0300561e
62183370Simp#define LOGICALID_MIDI 0x0400561e
63183370Simp
64183370Simp/* Interrupt handler.  */
65183370Simpstruct gusc_ihandler {
66183370Simp	void (*intr)(void *);
67183370Simp	void *arg;
68183370Simp};
69183370Simp
70183370Simp/* Here is the parameter structure per a device. */
71183370Simpstruct gusc_softc {
72183370Simp	device_t dev; /* device */
73183370Simp	int io_rid[3]; /* io port rids */
74183370Simp	struct resource *io[3]; /* io port resources */
75183370Simp	int io_alloced[3]; /* io port alloc flag */
76183370Simp	int irq_rid; /* irq rids */
77183370Simp	struct resource *irq; /* irq resources */
78183370Simp	int irq_alloced; /* irq alloc flag */
79183370Simp	int drq_rid[2]; /* drq rids */
80183370Simp	struct resource *drq[2]; /* drq resources */
81183370Simp	int drq_alloced[2]; /* drq alloc flag */
82183370Simp
83183370Simp	/* Interrupts are shared (XXX non-PnP only?) */
84183370Simp	struct gusc_ihandler midi_intr;
85183370Simp	struct gusc_ihandler pcm_intr;
86183370Simp};
87183370Simp
88183370Simptypedef struct gusc_softc *sc_p;
89183370Simp
90183370Simp#if NISA > 0
91183370Simpstatic int gusc_probe(device_t dev);
92183370Simpstatic int gusc_attach(device_t dev);
93183370Simpstatic int gusisa_probe(device_t dev);
94183370Simpstatic void gusc_intr(void *);
95183370Simp#endif /* NISA > 0 */
96183370Simpstatic struct resource *gusc_alloc_resource(device_t bus, device_t child, int type, int *rid,
97183370Simp					      u_long start, u_long end, u_long count, u_int flags);
98183370Simpstatic int gusc_release_resource(device_t bus, device_t child, int type, int rid,
99183370Simp				   struct resource *r);
100183370Simp
101183370Simp#if notyet
102183370Simpstatic device_t find_masterdev(sc_p scp);
103183370Simp#endif /* notyet */
104183370Simpstatic int alloc_resource(sc_p scp);
105183370Simpstatic int release_resource(sc_p scp);
106183370Simp
107183370Simpstatic devclass_t gusc_devclass;
108183370Simp
109183370Simp#if NISA > 0
110183370Simp
111183370Simpstatic int
112183370Simpgusc_probe(device_t dev)
113183370Simp{
114183370Simp	u_int32_t vend_id, logical_id;
115183370Simp	char *s;
116183370Simp	struct sndcard_func *func;
117183370Simp
118183370Simp	vend_id = isa_get_vendorid(dev);
119183370Simp	if (vend_id == 0)
120183370Simp		return gusisa_probe(dev);
121183370Simp
122183370Simp#if NPNP > 0
123183370Simp	logical_id = isa_get_logicalid(dev);
124183370Simp	s = NULL;
125183370Simp
126183370Simp	if (vend_id == 0x0100561e) { /* Gravis */
127183370Simp		switch (logical_id) {
128183370Simp		case LOGICALID_PCM:
129183370Simp			s = "Gravis UltraSound Plug & Play PCM";
130183370Simp			func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
131183370Simp			if (func == NULL)
132183370Simp				return (ENOMEM);
133183370Simp			bzero(func, sizeof(*func));
134183370Simp			func->func = SCF_PCM;
135183370Simp			device_add_child(dev, "pcm", -1, func);
136183370Simp			break;
137183370Simp#if notyet
138183370Simp		case LOGICALID_OPL:
139183370Simp			s = "Gravis UltraSound Plug & Play OPL";
140183370Simp			func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
141183370Simp			if (func == NULL)
142183370Simp				return (ENOMEM);
143183370Simp			bzero(func, sizeof(*func));
144183370Simp			func->func = SCF_SYNTH;
145183370Simp			device_add_child(dev, "midi", -1, func);
146183370Simp			break;
147183370Simp		case LOGICALID_MIDI:
148183370Simp			s = "Gravis UltraSound Plug & Play MIDI";
149183370Simp			func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
150183370Simp			if (func == NULL)
151183370Simp				return (ENOMEM);
152183370Simp			bzero(func, sizeof(*func));
153183370Simp			func->func = SCF_MIDI;
154183370Simp			device_add_child(dev, "midi", -1, func);
155183370Simp			break;
156183370Simp#endif /* notyet */
157183370Simp		}
158183370Simp	}
159183370Simp
160183370Simp	if (s != NULL) {
161183370Simp		device_set_desc(dev, s);
162183370Simp		return (0);
163183370Simp	}
164183370Simp#endif /* NPNP > 0 */
165183370Simp
166183370Simp	return (ENXIO);
167183370Simp}
168183370Simp
169183370Simpstatic void
170183370Simpport_wr(struct resource *r, int i, unsigned char v)
171183370Simp{
172183370Simp	bus_space_write_1(rman_get_bustag(r), rman_get_bushandle(r), i, v);
173183370Simp}
174183370Simp
175183370Simpstatic int
176183370Simpport_rd(struct resource *r, int i)
177183370Simp{
178183370Simp	return bus_space_read_1(rman_get_bustag(r), rman_get_bushandle(r), i);
179183370Simp}
180183370Simp
181183370Simp/*
182183370Simp * Probe for an old (non-PnP) GUS card on the ISA bus.
183183370Simp */
184183370Simp
185183370Simpstatic int
186183370Simpgusisa_probe(device_t dev)
187183370Simp{
188183370Simp	struct resource *res, *res2;
189183370Simp	int base, rid, rid2, s, flags;
190183370Simp	unsigned char val;
191183370Simp
192183370Simp	base = isa_get_port(dev);
193183370Simp	flags = device_get_flags(dev);
194183370Simp	rid = 1;
195183370Simp	res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, base + 0x100,
196183370Simp				 base + 0x107, 8, RF_ACTIVE);
197183370Simp
198183370Simp	if (res == NULL)
199183370Simp		return ENXIO;
200
201	res2 = NULL;
202
203	/*
204	 * Check for the presence of some GUS card.  Reset the card,
205	 * then see if we can access the memory on it.
206	 */
207
208	port_wr(res, 3, 0x4c);
209	port_wr(res, 5, 0);
210	DELAY(30 * 1000);
211
212	port_wr(res, 3, 0x4c);
213	port_wr(res, 5, 1);
214	DELAY(30 * 1000);
215
216	s = splhigh();
217
218	/* Write to DRAM.  */
219
220	port_wr(res, 3, 0x43);		/* Register select */
221	port_wr(res, 4, 0);		/* Low addr */
222	port_wr(res, 5, 0);		/* Med addr */
223
224	port_wr(res, 3, 0x44);		/* Register select */
225	port_wr(res, 4, 0);		/* High addr */
226	port_wr(res, 7, 0x55);		/* DRAM */
227
228	/* Read from DRAM.  */
229
230	port_wr(res, 3, 0x43);		/* Register select */
231	port_wr(res, 4, 0);		/* Low addr */
232	port_wr(res, 5, 0);		/* Med addr */
233
234	port_wr(res, 3, 0x44);		/* Register select */
235	port_wr(res, 4, 0);		/* High addr */
236	val = port_rd(res, 7);		/* DRAM */
237
238	splx(s);
239
240	if (val != 0x55)
241		goto fail;
242
243	rid2 = 0;
244	res2 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid2, base, base, 1,
245				  RF_ACTIVE);
246
247	if (res2 == NULL)
248		goto fail;
249
250	s = splhigh();
251	port_wr(res2, 0x0f, 0x20);
252	val = port_rd(res2, 0x0f);
253	splx(s);
254
255	if (val == 0xff || (val & 0x06) == 0)
256		val = 0;
257	else {
258		val = port_rd(res2, 0x506);	/* XXX Out of range.  */
259		if (val == 0xff)
260			val = 0;
261	}
262
263	bus_release_resource(dev, SYS_RES_IOPORT, rid2, res2);
264	bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
265
266	if (val >= 10) {
267		struct sndcard_func *func;
268
269		/* Looks like a GUS MAX.  Set the rest of the resources.  */
270
271		bus_set_resource(dev, SYS_RES_IOPORT, 2, base + 0x10c, 8);
272
273		if (flags & DV_F_DUAL_DMA)
274			bus_set_resource(dev, SYS_RES_DRQ, 1,
275					 flags & DV_F_DRQ_MASK, 1);
276
277#if notyet
278		/* We can support the CS4231 and MIDI devices.  */
279
280		func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
281		if (func == NULL)
282			return ENOMEM;
283		bzero(func, sizeof *func);
284		func->func = SCF_MIDI;
285		device_add_child(dev, "midi", -1, func);
286#endif /* notyet */
287
288		func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
289		if (func == NULL)
290			printf("xxx: gus pcm not attached, out of memory\n");
291		else {
292			bzero(func, sizeof *func);
293			func->func = SCF_PCM;
294			device_add_child(dev, "pcm", -1, func);
295		}
296		device_set_desc(dev, "Gravis UltraSound MAX");
297		return 0;
298	} else {
299
300		/*
301		 * TODO: Support even older GUS cards.  MIDI should work on
302		 * all models.
303		 */
304		return ENXIO;
305	}
306
307fail:
308	bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
309	return ENXIO;
310}
311
312static int
313gusc_attach(device_t dev)
314{
315	sc_p scp;
316	int unit;
317	void *ih;
318
319	scp = device_get_softc(dev);
320	unit = device_get_unit(dev);
321
322	bzero(scp, sizeof(*scp));
323
324	scp->dev = dev;
325	if (alloc_resource(scp)) {
326		release_resource(scp);
327		return (ENXIO);
328	}
329
330	bus_setup_intr(dev, scp->irq, INTR_TYPE_TTY, gusc_intr, scp, &ih);
331	bus_generic_attach(dev);
332
333	return (0);
334}
335
336/*
337 * Handle interrupts on GUS devices until there aren't any left.
338 */
339static void
340gusc_intr(void *arg)
341{
342	sc_p scp = (sc_p)arg;
343	int did_something;
344
345	do {
346		did_something = 0;
347		if (scp->pcm_intr.intr != NULL &&
348		    (port_rd(scp->io[2], 2) & 1)) {
349			(*scp->pcm_intr.intr)(scp->pcm_intr.arg);
350			did_something = 1;
351		}
352#if notyet
353		if (scp->midi_intr.intr != NULL &&
354		    (port_rd(scp->io[1], 0) & 0x80)) {
355			(*scp->midi_intr.intr)(scp->midi_intr.arg);
356			did_something = 1;
357		}
358#endif /* notyet */
359	} while (did_something != 0);
360}
361#endif /* NISA > 0 */
362
363static struct resource *
364gusc_alloc_resource(device_t bus, device_t child, int type, int *rid,
365		      u_long start, u_long end, u_long count, u_int flags)
366{
367	sc_p scp;
368	int *alloced, rid_max, alloced_max;
369	struct resource **res;
370
371	scp = device_get_softc(bus);
372	switch (type) {
373	case SYS_RES_IOPORT:
374		alloced = scp->io_alloced;
375		res = scp->io;
376		rid_max = 2;
377		alloced_max = 2; /* pcm + midi (more to include synth) */
378		break;
379	case SYS_RES_IRQ:
380		alloced = &scp->irq_alloced;
381		res = &scp->irq;
382		rid_max = 0;
383		alloced_max = 2; /* pcm and midi share the single irq. */
384		break;
385	case SYS_RES_DRQ:
386		alloced = scp->drq_alloced;
387		res = scp->drq;
388		rid_max = 1;
389		alloced_max = 1;
390		break;
391	default:
392		return (NULL);
393	}
394
395	if (*rid > rid_max || alloced[*rid] == alloced_max)
396		return (NULL);
397
398	alloced[*rid]++;
399	return (res[*rid]);
400}
401
402static int
403gusc_release_resource(device_t bus, device_t child, int type, int rid,
404			struct resource *r)
405{
406	sc_p scp;
407	int *alloced, rid_max;
408
409	scp = device_get_softc(bus);
410	switch (type) {
411	case SYS_RES_IOPORT:
412		alloced = scp->io_alloced;
413		rid_max = 2;
414		break;
415	case SYS_RES_IRQ:
416		alloced = &scp->irq_alloced;
417		rid_max = 0;
418		break;
419	case SYS_RES_DRQ:
420		alloced = scp->drq_alloced;
421		rid_max = 1;
422		break;
423	default:
424		return (1);
425	}
426
427	if (rid > rid_max || alloced[rid] == 0)
428		return (1);
429
430	alloced[rid]--;
431	return (0);
432}
433
434static int
435gusc_setup_intr(device_t dev, device_t child, struct resource *irq,
436		int flags, driver_intr_t *intr, void *arg, void **cookiep)
437{
438	sc_p scp = (sc_p)device_get_softc(dev);
439	devclass_t devclass;
440
441	devclass = device_get_devclass(child);
442	if (strcmp(devclass_get_name(devclass), "midi") == 0) {
443		scp->midi_intr.intr = intr;
444		scp->midi_intr.arg = arg;
445		return 0;
446	} else if (strcmp(devclass_get_name(devclass), "pcm") == 0) {
447		scp->pcm_intr.intr = intr;
448		scp->pcm_intr.arg = arg;
449		return 0;
450	}
451	return bus_generic_setup_intr(dev, child, irq, flags, intr,
452				      arg, cookiep);
453}
454
455#if notyet
456static device_t
457find_masterdev(sc_p scp)
458{
459	int i, units;
460	devclass_t devclass;
461	device_t dev;
462
463	devclass = device_get_devclass(scp->dev);
464	units = devclass_get_maxunit(devclass);
465	dev = NULL;
466	for (i = 0 ; i < units ; i++) {
467		dev = devclass_get_device(devclass, i);
468		if (isa_get_vendorid(dev) == isa_get_vendorid(scp->dev)
469		    && isa_get_logicalid(dev) == LOGICALID_PCM
470		    && isa_get_serial(dev) == isa_get_serial(scp->dev))
471			break;
472	}
473	if (i == units)
474		return (NULL);
475
476	return (dev);
477}
478#endif /* notyet */
479
480static int io_range[3] = {0x10, 0x4, 0x4};
481static int
482alloc_resource(sc_p scp)
483{
484	int i;
485#if notyet
486	device_t dev;
487#endif /* notyet */
488
489	switch(isa_get_logicalid(scp->dev)) {
490	case LOGICALID_PCM:
491	default:		/* XXX Non-PnP */
492		for (i = 0 ; i < sizeof(scp->io) / sizeof(*scp->io) ; i++) {
493			if (scp->io[i] == NULL) {
494				scp->io_rid[i] = i;
495				scp->io[i] = bus_alloc_resource(scp->dev, SYS_RES_IOPORT, &scp->io_rid[i],
496								0, ~0, io_range[i], RF_ACTIVE);
497				if (scp->io[i] == NULL)
498					return (1);
499				scp->io_alloced[i] = 0;
500			}
501		}
502		if (scp->irq == NULL) {
503			scp->irq_rid = 0;
504			scp->irq = bus_alloc_resource(scp->dev, SYS_RES_IRQ, &scp->irq_rid,
505						      0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
506			if (scp->irq == NULL)
507				return (1);
508			scp->irq_alloced = 0;
509		}
510		for (i = 0 ; i < sizeof(scp->drq) / sizeof(*scp->drq) ; i++) {
511			if (scp->drq[i] == NULL) {
512				scp->drq_rid[i] = i;
513				scp->drq[i] = bus_alloc_resource(scp->dev, SYS_RES_DRQ, &scp->drq_rid[i],
514								 0, ~0, 1, RF_ACTIVE);
515				if (scp->drq[i] == NULL)
516					return (1);
517				scp->drq_alloced[i] = 0;
518			}
519		}
520		break;
521#if notyet
522	case LOGICALID_OPL:
523		if (scp->io[0] == NULL) {
524			scp->io_rid[0] = 0;
525			scp->io[0] = bus_alloc_resource(scp->dev, SYS_RES_IOPORT, &scp->io_rid[0],
526							0, ~0, io_range[0], RF_ACTIVE);
527			if (scp->io[0] == NULL)
528				return (1);
529			scp->io_alloced[0] = 0;
530		}
531		break;
532	case LOGICALID_MIDI:
533		if (scp->io[0] == NULL) {
534			scp->io_rid[0] = 0;
535			scp->io[0] = bus_alloc_resource(scp->dev, SYS_RES_IOPORT, &scp->io_rid[0],
536							0, ~0, io_range[0], RF_ACTIVE);
537			if (scp->io[0] == NULL)
538				return (1);
539			scp->io_alloced[0] = 0;
540		}
541		if (scp->irq == NULL) {
542			/* The irq is shared with pcm audio. */
543			dev = find_masterdev(scp);
544			if (dev == NULL)
545				return (1);
546			scp->irq_rid = 0;
547			scp->irq = BUS_ALLOC_RESOURCE(dev, NULL, SYS_RES_IRQ, &scp->irq_rid,
548						      0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
549			if (scp->irq == NULL)
550				return (1);
551			scp->irq_alloced = 0;
552		}
553		break;
554#endif /* notyet */
555	}
556	return (0);
557}
558
559static int
560release_resource(sc_p scp)
561{
562	int i;
563#if notyet
564	device_t dev;
565#endif /* notyet */
566
567	switch(isa_get_logicalid(scp->dev)) {
568	case LOGICALID_PCM:
569	default:		/* XXX Non-PnP */
570		for (i = 0 ; i < sizeof(scp->io) / sizeof(*scp->io) ; i++) {
571			if (scp->io[i] != NULL) {
572				bus_release_resource(scp->dev, SYS_RES_IOPORT, scp->io_rid[i], scp->io[i]);
573				scp->io[i] = NULL;
574			}
575		}
576		if (scp->irq != NULL) {
577			bus_release_resource(scp->dev, SYS_RES_IRQ, scp->irq_rid, scp->irq);
578			scp->irq = NULL;
579		}
580		for (i = 0 ; i < sizeof(scp->drq) / sizeof(*scp->drq) ; i++) {
581			if (scp->drq[i] != NULL) {
582				bus_release_resource(scp->dev, SYS_RES_DRQ, scp->drq_rid[i], scp->drq[i]);
583				scp->drq[i] = NULL;
584			}
585		}
586		break;
587#if notyet
588	case LOGICALID_OPL:
589		if (scp->io[0] != NULL) {
590			bus_release_resource(scp->dev, SYS_RES_IOPORT, scp->io_rid[0], scp->io[0]);
591			scp->io[0] = NULL;
592		}
593		break;
594	case LOGICALID_MIDI:
595		if (scp->io[0] != NULL) {
596			bus_release_resource(scp->dev, SYS_RES_IOPORT, scp->io_rid[0], scp->io[0]);
597			scp->io[0] = NULL;
598		}
599		if (scp->irq != NULL) {
600			/* The irq is shared with pcm audio. */
601			dev = find_masterdev(scp);
602			if (dev == NULL)
603				return (1);
604			BUS_RELEASE_RESOURCE(dev, NULL, SYS_RES_IOPORT, scp->irq_rid, scp->irq);
605			scp->irq = NULL;
606		}
607		break;
608#endif /* notyet */
609	}
610	return (0);
611}
612
613#if NISA > 0
614static device_method_t gusc_methods[] = {
615	/* Device interface */
616	DEVMETHOD(device_probe,		gusc_probe),
617	DEVMETHOD(device_attach,	gusc_attach),
618	DEVMETHOD(device_detach,	bus_generic_detach),
619	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
620	DEVMETHOD(device_suspend,	bus_generic_suspend),
621	DEVMETHOD(device_resume,	bus_generic_resume),
622
623	/* Bus interface */
624	DEVMETHOD(bus_print_child,	bus_generic_print_child),
625	DEVMETHOD(bus_alloc_resource,	gusc_alloc_resource),
626	DEVMETHOD(bus_release_resource,	gusc_release_resource),
627	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
628	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
629	DEVMETHOD(bus_setup_intr,	gusc_setup_intr),
630	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
631
632	{ 0, 0 }
633};
634
635static driver_t gusc_driver = {
636	"gusc",
637	gusc_methods,
638	sizeof(struct gusc_softc),
639};
640
641/*
642 * gusc can be attached to an isa bus.
643 */
644DRIVER_MODULE(gusc, isa, gusc_driver, gusc_devclass, 0, 0);
645#endif /* NISA > 0 */
646
647#endif /* NGUSC > 0 */
648