2 * $NetBSD: puc.c,v 1.7 2000/07/29 17:43:38 jlam Exp $
3 * $FreeBSD: src/sys/dev/puc/puc.c,v 1.3.2.5 2003/04/04 08:42:17 sobomax Exp $
4 * $DragonFly: src/sys/dev/misc/puc/puc.c,v 1.11 2006/12/23 00:26:18 swildner Exp $
8 * Copyright (c) 2002 JF Hay. All rights reserved.
9 * Copyright (c) 2000 M. Warner Losh. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice unmodified, this list of conditions, and the following
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.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Copyright (c) 1996, 1998, 1999
35 * Christopher G. Demetriou. All rights reserved.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by Christopher G. Demetriou
48 * for the NetBSD Project.
49 * 4. The name of the author may not be used to endorse or promote products
50 * derived from this software without specific prior written permission
52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65 * PCI "universal" communication card device driver, glues com, lpt,
66 * and similar ports to PCI via bridge chip often much larger than
67 * the devices being glued.
69 * Author: Christopher G. Demetriou, May 14, 1998 (derived from NetBSD
70 * sys/dev/pci/pciide.c, revision 1.6).
72 * These devices could be (and some times are) described as
73 * communications/{serial,parallel}, etc. devices with known
74 * programming interfaces, but those programming interfaces (in
75 * particular the BAR assignments for devices, etc.) in fact are not
76 * particularly well defined.
78 * After I/we have seen more of these devices, it may be possible
79 * to generalize some of these bits. In particular, devices which
80 * describe themselves as communications/serial/16[45]50, and
81 * communications/parallel/??? might be attached via direct
82 * 'com' and 'lpt' attachments to pci.
85 #include <sys/param.h>
86 #include <sys/systm.h>
87 #include <sys/kernel.h>
90 #include <sys/malloc.h>
93 #include <bus/pci/pcireg.h>
94 #include <bus/pci/pcivar.h>
100 const struct puc_device_description
*sc_desc
;
102 /* card-global dynamic data */
105 struct resource
*irqres
;
108 bus_space_tag_t ilr_st
;
109 bus_space_handle_t ilr_sh
;
112 struct resource
*res
;
113 } sc_bar_mappings
[PUC_MAX_BAR
];
115 /* per-port dynamic data */
118 /* filled in by bus_setup_intr() */
119 void (*ihand
) (void *);
121 } sc_ports
[PUC_MAX_PORTS
];
125 struct resource_list resources
;
129 static int puc_pci_probe(device_t dev
);
130 static int puc_pci_attach(device_t dev
);
131 static void puc_intr(void *arg
);
133 static struct resource
*puc_alloc_resource(device_t
, device_t
, int, int *,
134 u_long
, u_long
, u_long
, u_int
);
135 static int puc_release_resource(device_t
, device_t
, int, int,
137 static int puc_get_resource(device_t
, device_t
, int, int, u_long
*, u_long
*);
138 static int puc_setup_intr(device_t
, device_t
, struct resource
*, int,
139 void (*)(void *), void *, void **, lwkt_serialize_t
);
140 static int puc_teardown_intr(device_t
, device_t
, struct resource
*,
142 static int puc_read_ivar(device_t
, device_t
, int, uintptr_t *);
144 static const struct puc_device_description
*puc_find_description(uint32_t,
145 uint32_t, uint32_t, uint32_t);
146 static void puc_config_superio(device_t
);
147 static void puc_config_win877(struct resource
*);
148 static int puc_find_free_unit(char *);
150 static void puc_print_win877(bus_space_tag_t
, bus_space_handle_t
, u_int
,
152 static void puc_print_resource_list(struct resource_list
*);
156 puc_pci_probe(device_t dev
)
158 uint32_t v1
, v2
, d1
, d2
;
159 const struct puc_device_description
*desc
;
161 if ((pci_read_config(dev
, PCIR_HDRTYPE
, 1) & PCIM_HDRTYPE
) != 0)
164 v1
= pci_read_config(dev
, PCIR_VENDOR
, 2);
165 d1
= pci_read_config(dev
, PCIR_DEVICE
, 2);
166 v2
= pci_read_config(dev
, PCIR_SUBVEND_0
, 2);
167 d2
= pci_read_config(dev
, PCIR_SUBDEV_0
, 2);
169 desc
= puc_find_description(v1
, d1
, v2
, d2
);
172 device_set_desc(dev
, desc
->name
);
177 puc_probe_ilr(struct puc_softc
*sc
, struct resource
*res
)
182 switch (sc
->sc_desc
->ilr_type
) {
183 case PUC_ILR_TYPE_DIGI
:
184 sc
->ilr_st
= rman_get_bustag(res
);
185 sc
->ilr_sh
= rman_get_bushandle(res
);
186 for (i
= 0; i
< 2; i
++) {
187 t1
= bus_space_read_1(sc
->ilr_st
, sc
->ilr_sh
,
188 sc
->sc_desc
->ilr_offset
[i
]);
190 bus_space_write_1(sc
->ilr_st
, sc
->ilr_sh
,
191 sc
->sc_desc
->ilr_offset
[i
], t1
);
192 t2
= bus_space_read_1(sc
->ilr_st
, sc
->ilr_sh
,
193 sc
->sc_desc
->ilr_offset
[i
]);
206 puc_pci_attach(device_t dev
)
209 int bidx
, childunit
, i
, irq_setup
, rid
;
210 uint32_t v1
, v2
, d1
, d2
;
211 struct puc_softc
*sc
;
212 struct puc_device
*pdev
;
213 struct resource
*res
;
214 struct resource_list_entry
*rle
;
216 sc
= (struct puc_softc
*)device_get_softc(dev
);
217 bzero(sc
, sizeof(*sc
));
218 v1
= pci_read_config(dev
, PCIR_VENDOR
, 2);
219 d1
= pci_read_config(dev
, PCIR_DEVICE
, 2);
220 v2
= pci_read_config(dev
, PCIR_SUBVEND_0
, 2);
221 d2
= pci_read_config(dev
, PCIR_SUBDEV_0
, 2);
222 sc
->sc_desc
= puc_find_description(v1
, d1
, v2
, d2
);
223 if (sc
->sc_desc
== NULL
)
229 kprintf("puc: name: %s\n", sc
->sc_desc
->name
);
232 res
= bus_alloc_resource(dev
, SYS_RES_IRQ
, &rid
, 0, ~0, 1,
233 RF_ACTIVE
| RF_SHAREABLE
);
240 irq_setup
= BUS_SETUP_INTR(device_get_parent(dev
), dev
, res
,
241 INTR_FAST
, puc_intr
, sc
,
242 &sc
->intr_cookie
, NULL
);
247 irq_setup
= BUS_SETUP_INTR(device_get_parent(dev
), dev
, res
,
249 &sc
->intr_cookie
, NULL
);
254 for (i
= 0; PUC_PORT_VALID(sc
->sc_desc
, i
); i
++) {
255 if (rid
== sc
->sc_desc
->ports
[i
].bar
)
257 rid
= sc
->sc_desc
->ports
[i
].bar
;
258 bidx
= PUC_PORT_BAR_INDEX(rid
);
260 if (sc
->sc_bar_mappings
[bidx
].res
!= NULL
)
262 res
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &rid
,
263 0ul, ~0ul, 1, RF_ACTIVE
);
265 kprintf("could not get resource\n");
268 sc
->sc_bar_mappings
[bidx
].res
= res
;
270 if (sc
->sc_desc
->ilr_type
!= PUC_ILR_TYPE_NONE
) {
271 sc
->ilr_enabled
= puc_probe_ilr(sc
, res
);
273 device_printf(dev
, "ILR enabled\n");
275 device_printf(dev
, "ILR disabled\n");
278 kprintf("port bst %x, start %x, end %x\n",
279 (u_int
)rman_get_bustag(res
), (u_int
)rman_get_start(res
),
280 (u_int
)rman_get_end(res
));
284 puc_config_superio(dev
);
286 for (i
= 0; PUC_PORT_VALID(sc
->sc_desc
, i
); i
++) {
287 rid
= sc
->sc_desc
->ports
[i
].bar
;
288 bidx
= PUC_PORT_BAR_INDEX(rid
);
289 if (sc
->sc_bar_mappings
[bidx
].res
== NULL
)
292 switch (sc
->sc_desc
->ports
[i
].type
) {
293 case PUC_PORT_TYPE_COM
:
299 pdev
= kmalloc(sizeof(struct puc_device
), M_DEVBUF
,
301 resource_list_init(&pdev
->resources
);
303 /* First fake up an IRQ resource. */
304 resource_list_add(&pdev
->resources
, SYS_RES_IRQ
, 0,
305 rman_get_start(sc
->irqres
), rman_get_end(sc
->irqres
),
306 rman_get_end(sc
->irqres
) - rman_get_start(sc
->irqres
) + 1);
307 rle
= resource_list_find(&pdev
->resources
, SYS_RES_IRQ
, 0);
308 rle
->res
= sc
->irqres
;
310 /* Now fake an IOPORT resource */
311 res
= sc
->sc_bar_mappings
[bidx
].res
;
312 resource_list_add(&pdev
->resources
, SYS_RES_IOPORT
, 0,
313 rman_get_start(res
) + sc
->sc_desc
->ports
[i
].offset
,
314 rman_get_end(res
) + sc
->sc_desc
->ports
[i
].offset
+ 8 - 1,
316 rle
= resource_list_find(&pdev
->resources
, SYS_RES_IOPORT
, 0);
318 if (sc
->barmuxed
== 0) {
319 rle
->res
= sc
->sc_bar_mappings
[bidx
].res
;
321 rle
->res
= kmalloc(sizeof(struct resource
), M_DEVBUF
,
323 if (rle
->res
== NULL
) {
324 kfree(pdev
, M_DEVBUF
);
328 rle
->res
->r_start
= rman_get_start(res
) +
329 sc
->sc_desc
->ports
[i
].offset
;
330 rle
->res
->r_end
= rle
->res
->r_start
+ 8 - 1;
331 rle
->res
->r_bustag
= rman_get_bustag(res
);
332 bus_space_subregion(rle
->res
->r_bustag
,
333 rman_get_bushandle(res
),
334 sc
->sc_desc
->ports
[i
].offset
, 8,
335 &rle
->res
->r_bushandle
);
338 pdev
->serialfreq
= sc
->sc_desc
->ports
[i
].serialfreq
;
340 childunit
= puc_find_free_unit(typestr
);
341 sc
->sc_ports
[i
].dev
= device_add_child(dev
, typestr
, childunit
);
342 if (sc
->sc_ports
[i
].dev
== NULL
) {
344 bus_space_unmap(rman_get_bustag(rle
->res
),
345 rman_get_bushandle(rle
->res
),
347 kfree(rle
->res
, M_DEVBUF
);
348 kfree(pdev
, M_DEVBUF
);
352 device_set_ivars(sc
->sc_ports
[i
].dev
, pdev
);
353 device_set_desc(sc
->sc_ports
[i
].dev
, sc
->sc_desc
->name
);
355 device_quiet(sc
->sc_ports
[i
].dev
);
357 kprintf("puc: type %d, bar %x, offset %x\n",
358 sc
->sc_desc
->ports
[i
].type
,
359 sc
->sc_desc
->ports
[i
].bar
,
360 sc
->sc_desc
->ports
[i
].offset
);
361 print_resource_list(&pdev
->resources
);
363 device_set_flags(sc
->sc_ports
[i
].dev
,
364 sc
->sc_desc
->ports
[i
].flags
);
365 if (device_probe_and_attach(sc
->sc_ports
[i
].dev
) != 0) {
367 bus_space_unmap(rman_get_bustag(rle
->res
),
368 rman_get_bushandle(rle
->res
),
370 kfree(rle
->res
, M_DEVBUF
);
371 kfree(pdev
, M_DEVBUF
);
383 puc_ilr_read(struct puc_softc
*sc
)
389 switch (sc
->sc_desc
->ilr_type
) {
390 case PUC_ILR_TYPE_DIGI
:
391 for (i
= 1; i
>= 0; i
--) {
392 mask
= (mask
<< 8) | (bus_space_read_1(sc
->ilr_st
,
393 sc
->ilr_sh
, sc
->sc_desc
->ilr_offset
[i
]) & 0xff);
405 * This is an interrupt handler. For boards that can't tell us which
406 * device generated the interrupt it just calls all the registered
407 * handlers sequencially, but for boards that can tell us which
408 * device(s) generated the interrupt it calls only handlers for devices
409 * that actually generated the interrupt.
416 struct puc_softc
*sc
;
418 sc
= (struct puc_softc
*)arg
;
419 ilr_mask
= sc
->ilr_enabled
? puc_ilr_read(sc
) : 0xffffffff;
420 for (i
= 0; i
< PUC_MAX_PORTS
; i
++)
421 if (sc
->sc_ports
[i
].ihand
!= NULL
&&
422 ((ilr_mask
>> i
) & 0x00000001))
423 (sc
->sc_ports
[i
].ihand
)(sc
->sc_ports
[i
].ihandarg
);
426 static const struct puc_device_description
*
427 puc_find_description(uint32_t vend
, uint32_t prod
, uint32_t svend
,
432 #define checkreg(val, index) \
433 (((val) & puc_devices[i].rmask[(index)]) == puc_devices[i].rval[(index)])
435 for (i
= 0; puc_devices
[i
].name
!= NULL
; i
++) {
436 if (checkreg(vend
, PUC_REG_VEND
) &&
437 checkreg(prod
, PUC_REG_PROD
) &&
438 checkreg(svend
, PUC_REG_SVEND
) &&
439 checkreg(sprod
, PUC_REG_SPROD
))
440 return (&puc_devices
[i
]);
449 * It might be possible to make these more generic if we can detect patterns.
450 * For instance maybe if the size of a bar is 0x400 (the old isa space) it
451 * might contain one or more superio chips.
454 puc_config_superio(device_t dev
)
456 struct puc_softc
*sc
= (struct puc_softc
*)device_get_softc(dev
);
458 if (sc
->sc_desc
->rval
[PUC_REG_VEND
] == 0x1592 &&
459 sc
->sc_desc
->rval
[PUC_REG_PROD
] == 0x0781)
460 puc_config_win877(sc
->sc_bar_mappings
[0].res
);
463 #define rdspio(indx) (bus_space_write_1(bst, bsh, efir, indx), \
464 bus_space_read_1(bst, bsh, efdr))
465 #define wrspio(indx,data) (bus_space_write_1(bst, bsh, efir, indx), \
466 bus_space_write_1(bst, bsh, efdr, data))
470 puc_print_win877(bus_space_tag_t bst
, bus_space_handle_t bsh
, u_int efir
,
473 u_char cr00
, cr01
, cr04
, cr09
, cr0d
, cr14
, cr15
, cr16
, cr17
;
474 u_char cr18
, cr19
, cr24
, cr25
, cr28
, cr2c
, cr31
, cr32
;
493 kprintf("877T: cr00 %x, cr01 %x, cr04 %x, cr09 %x, cr0d %x, cr14 %x, "
494 "cr15 %x, cr16 %x, cr17 %x, cr18 %x, cr19 %x, cr24 %x, cr25 %x, "
495 "cr28 %x, cr2c %x, cr31 %x, cr32 %x\n", cr00
, cr01
, cr04
, cr09
,
496 cr0d
, cr14
, cr15
, cr16
, cr17
,
497 cr18
, cr19
, cr24
, cr25
, cr28
, cr2c
, cr31
, cr32
);
502 puc_config_win877(struct resource
*res
)
507 bus_space_handle_t bsh
;
509 bst
= rman_get_bustag(res
);
510 bsh
= rman_get_bushandle(res
);
512 /* configure the first W83877TF */
513 bus_space_write_1(bst
, bsh
, 0x250, 0x89);
516 val
= rdspio(0x09) & 0x0f;
518 kprintf("conf_win877: Oops not a W83877TF\n");
524 puc_print_win877(bst
, bsh
, efir
, efdr
);
533 wrspio(0x24, 0x2e8 >> 2);
534 wrspio(0x25, 0x2f8 >> 2);
540 puc_print_win877(bst
, bsh
, efir
, efdr
);
543 bus_space_write_1(bst
, bsh
, 0x250, 0xaa);
545 /* configure the second W83877TF */
546 bus_space_write_1(bst
, bsh
, 0x3f0, 0x87);
547 bus_space_write_1(bst
, bsh
, 0x3f0, 0x87);
550 val
= rdspio(0x09) & 0x0f;
552 kprintf("conf_win877: Oops not a W83877TF\n");
558 puc_print_win877(bst
, bsh
, efir
, efdr
);
567 wrspio(0x24, 0x3e8 >> 2);
568 wrspio(0x25, 0x3f8 >> 2);
574 puc_print_win877(bst
, bsh
, efir
, efdr
);
577 bus_space_write_1(bst
, bsh
, 0x3f0, 0xaa);
583 static int puc_find_free_unit(char *name
)
591 while (resource_int_value(name
, unit
, "port", &start
) == 0 &&
594 dc
= devclass_find(name
);
597 while (devclass_get_device(dc
, unit
))
600 kprintf("puc: Using %s%d\n", name
, unit
);
607 puc_print_resource_list(struct resource_list
*rl
)
609 struct resource_list_entry
*rle
;
611 kprintf("print_resource_list: rl %p\n", rl
);
612 SLIST_FOREACH(rle
, rl
, link
)
613 kprintf("type %x, rid %x\n", rle
->type
, rle
->rid
);
614 kprintf("print_resource_list: end.\n");
618 static struct resource
*
619 puc_alloc_resource(device_t dev
, device_t child
, int type
, int *rid
,
620 u_long start
, u_long end
, u_long count
, u_int flags
)
622 struct puc_device
*pdev
;
623 struct resource
*retval
;
624 struct resource_list
*rl
;
625 struct resource_list_entry
*rle
;
627 pdev
= device_get_ivars(child
);
628 rl
= &pdev
->resources
;
631 kprintf("puc_alloc_resource: pdev %p, looking for t %x, r %x\n",
633 puc_print_resource_list(rl
);
636 rle
= resource_list_find(rl
, type
, *rid
);
642 kprintf("found rle, %lx, %lx, %lx\n", start
, end
, count
);
646 kprintf("oops rle is gone\n");
652 puc_release_resource(device_t dev
, device_t child
, int type
, int rid
,
653 struct resource
*res
)
659 puc_get_resource(device_t dev
, device_t child
, int type
, int rid
,
660 u_long
*startp
, u_long
*countp
)
662 struct puc_device
*pdev
;
663 struct resource_list
*rl
;
664 struct resource_list_entry
*rle
;
666 pdev
= device_get_ivars(child
);
667 rl
= &pdev
->resources
;
670 kprintf("puc_get_resource: pdev %p, looking for t %x, r %x\n", pdev
,
672 puc_print_resource_list(rl
);
674 rle
= resource_list_find(rl
, type
, rid
);
677 kprintf("found rle %p,", rle
);
680 *startp
= rle
->start
;
682 *countp
= rle
->count
;
684 kprintf(" %lx, %lx\n", rle
->start
, rle
->count
);
688 kprintf("oops rle is gone\n");
693 puc_setup_intr(device_t dev
, device_t child
, struct resource
*r
, int flags
,
694 void (*ihand
)(void *), void *arg
,
695 void **cookiep
, lwkt_serialize_t serializer
)
698 struct puc_softc
*sc
;
700 sc
= (struct puc_softc
*)device_get_softc(dev
);
701 for (i
= 0; PUC_PORT_VALID(sc
->sc_desc
, i
); i
++) {
702 if (sc
->sc_ports
[i
].dev
== child
) {
703 if (sc
->sc_ports
[i
].ihand
!= 0)
705 sc
->sc_ports
[i
].ihand
= ihand
;
706 sc
->sc_ports
[i
].ihandarg
= arg
;
707 KKASSERT(serializer
== NULL
); /* not handled yet XXX */
716 puc_teardown_intr(device_t dev
, device_t child
, struct resource
*r
,
720 struct puc_softc
*sc
;
722 sc
= (struct puc_softc
*)device_get_softc(dev
);
723 for (i
= 0; PUC_PORT_VALID(sc
->sc_desc
, i
); i
++) {
724 if (sc
->sc_ports
[i
].dev
== child
) {
725 sc
->sc_ports
[i
].ihand
= NULL
;
726 sc
->sc_ports
[i
].ihandarg
= NULL
;
734 puc_read_ivar(device_t dev
, device_t child
, int index
, uintptr_t *result
)
736 struct puc_device
*pdev
;
738 pdev
= device_get_ivars(child
);
744 *result
= pdev
->serialfreq
;
752 static device_method_t puc_pci_methods
[] = {
753 /* Device interface */
754 DEVMETHOD(device_probe
, puc_pci_probe
),
755 DEVMETHOD(device_attach
, puc_pci_attach
),
757 DEVMETHOD(bus_alloc_resource
, puc_alloc_resource
),
758 DEVMETHOD(bus_release_resource
, puc_release_resource
),
759 DEVMETHOD(bus_get_resource
, puc_get_resource
),
760 DEVMETHOD(bus_read_ivar
, puc_read_ivar
),
761 DEVMETHOD(bus_setup_intr
, puc_setup_intr
),
762 DEVMETHOD(bus_teardown_intr
, puc_teardown_intr
),
763 DEVMETHOD(bus_print_child
, bus_generic_print_child
),
764 DEVMETHOD(bus_driver_added
, bus_generic_driver_added
),
768 static driver_t puc_pci_driver
= {
771 sizeof(struct puc_softc
),
774 static devclass_t puc_devclass
;
776 DRIVER_MODULE(puc
, pci
, puc_pci_driver
, puc_devclass
, 0, 0);