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.12 2008/01/06 16:55:50 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
,
324 rle
->res
->r_start
= rman_get_start(res
) +
325 sc
->sc_desc
->ports
[i
].offset
;
326 rle
->res
->r_end
= rle
->res
->r_start
+ 8 - 1;
327 rle
->res
->r_bustag
= rman_get_bustag(res
);
328 bus_space_subregion(rle
->res
->r_bustag
,
329 rman_get_bushandle(res
),
330 sc
->sc_desc
->ports
[i
].offset
, 8,
331 &rle
->res
->r_bushandle
);
334 pdev
->serialfreq
= sc
->sc_desc
->ports
[i
].serialfreq
;
336 childunit
= puc_find_free_unit(typestr
);
337 sc
->sc_ports
[i
].dev
= device_add_child(dev
, typestr
, childunit
);
338 if (sc
->sc_ports
[i
].dev
== NULL
) {
340 bus_space_unmap(rman_get_bustag(rle
->res
),
341 rman_get_bushandle(rle
->res
),
343 kfree(rle
->res
, M_DEVBUF
);
344 kfree(pdev
, M_DEVBUF
);
348 device_set_ivars(sc
->sc_ports
[i
].dev
, pdev
);
349 device_set_desc(sc
->sc_ports
[i
].dev
, sc
->sc_desc
->name
);
351 device_quiet(sc
->sc_ports
[i
].dev
);
353 kprintf("puc: type %d, bar %x, offset %x\n",
354 sc
->sc_desc
->ports
[i
].type
,
355 sc
->sc_desc
->ports
[i
].bar
,
356 sc
->sc_desc
->ports
[i
].offset
);
357 print_resource_list(&pdev
->resources
);
359 device_set_flags(sc
->sc_ports
[i
].dev
,
360 sc
->sc_desc
->ports
[i
].flags
);
361 if (device_probe_and_attach(sc
->sc_ports
[i
].dev
) != 0) {
363 bus_space_unmap(rman_get_bustag(rle
->res
),
364 rman_get_bushandle(rle
->res
),
366 kfree(rle
->res
, M_DEVBUF
);
367 kfree(pdev
, M_DEVBUF
);
379 puc_ilr_read(struct puc_softc
*sc
)
385 switch (sc
->sc_desc
->ilr_type
) {
386 case PUC_ILR_TYPE_DIGI
:
387 for (i
= 1; i
>= 0; i
--) {
388 mask
= (mask
<< 8) | (bus_space_read_1(sc
->ilr_st
,
389 sc
->ilr_sh
, sc
->sc_desc
->ilr_offset
[i
]) & 0xff);
401 * This is an interrupt handler. For boards that can't tell us which
402 * device generated the interrupt it just calls all the registered
403 * handlers sequencially, but for boards that can tell us which
404 * device(s) generated the interrupt it calls only handlers for devices
405 * that actually generated the interrupt.
412 struct puc_softc
*sc
;
414 sc
= (struct puc_softc
*)arg
;
415 ilr_mask
= sc
->ilr_enabled
? puc_ilr_read(sc
) : 0xffffffff;
416 for (i
= 0; i
< PUC_MAX_PORTS
; i
++)
417 if (sc
->sc_ports
[i
].ihand
!= NULL
&&
418 ((ilr_mask
>> i
) & 0x00000001))
419 (sc
->sc_ports
[i
].ihand
)(sc
->sc_ports
[i
].ihandarg
);
422 static const struct puc_device_description
*
423 puc_find_description(uint32_t vend
, uint32_t prod
, uint32_t svend
,
428 #define checkreg(val, index) \
429 (((val) & puc_devices[i].rmask[(index)]) == puc_devices[i].rval[(index)])
431 for (i
= 0; puc_devices
[i
].name
!= NULL
; i
++) {
432 if (checkreg(vend
, PUC_REG_VEND
) &&
433 checkreg(prod
, PUC_REG_PROD
) &&
434 checkreg(svend
, PUC_REG_SVEND
) &&
435 checkreg(sprod
, PUC_REG_SPROD
))
436 return (&puc_devices
[i
]);
445 * It might be possible to make these more generic if we can detect patterns.
446 * For instance maybe if the size of a bar is 0x400 (the old isa space) it
447 * might contain one or more superio chips.
450 puc_config_superio(device_t dev
)
452 struct puc_softc
*sc
= (struct puc_softc
*)device_get_softc(dev
);
454 if (sc
->sc_desc
->rval
[PUC_REG_VEND
] == 0x1592 &&
455 sc
->sc_desc
->rval
[PUC_REG_PROD
] == 0x0781)
456 puc_config_win877(sc
->sc_bar_mappings
[0].res
);
459 #define rdspio(indx) (bus_space_write_1(bst, bsh, efir, indx), \
460 bus_space_read_1(bst, bsh, efdr))
461 #define wrspio(indx,data) (bus_space_write_1(bst, bsh, efir, indx), \
462 bus_space_write_1(bst, bsh, efdr, data))
466 puc_print_win877(bus_space_tag_t bst
, bus_space_handle_t bsh
, u_int efir
,
469 u_char cr00
, cr01
, cr04
, cr09
, cr0d
, cr14
, cr15
, cr16
, cr17
;
470 u_char cr18
, cr19
, cr24
, cr25
, cr28
, cr2c
, cr31
, cr32
;
489 kprintf("877T: cr00 %x, cr01 %x, cr04 %x, cr09 %x, cr0d %x, cr14 %x, "
490 "cr15 %x, cr16 %x, cr17 %x, cr18 %x, cr19 %x, cr24 %x, cr25 %x, "
491 "cr28 %x, cr2c %x, cr31 %x, cr32 %x\n", cr00
, cr01
, cr04
, cr09
,
492 cr0d
, cr14
, cr15
, cr16
, cr17
,
493 cr18
, cr19
, cr24
, cr25
, cr28
, cr2c
, cr31
, cr32
);
498 puc_config_win877(struct resource
*res
)
503 bus_space_handle_t bsh
;
505 bst
= rman_get_bustag(res
);
506 bsh
= rman_get_bushandle(res
);
508 /* configure the first W83877TF */
509 bus_space_write_1(bst
, bsh
, 0x250, 0x89);
512 val
= rdspio(0x09) & 0x0f;
514 kprintf("conf_win877: Oops not a W83877TF\n");
520 puc_print_win877(bst
, bsh
, efir
, efdr
);
529 wrspio(0x24, 0x2e8 >> 2);
530 wrspio(0x25, 0x2f8 >> 2);
536 puc_print_win877(bst
, bsh
, efir
, efdr
);
539 bus_space_write_1(bst
, bsh
, 0x250, 0xaa);
541 /* configure the second W83877TF */
542 bus_space_write_1(bst
, bsh
, 0x3f0, 0x87);
543 bus_space_write_1(bst
, bsh
, 0x3f0, 0x87);
546 val
= rdspio(0x09) & 0x0f;
548 kprintf("conf_win877: Oops not a W83877TF\n");
554 puc_print_win877(bst
, bsh
, efir
, efdr
);
563 wrspio(0x24, 0x3e8 >> 2);
564 wrspio(0x25, 0x3f8 >> 2);
570 puc_print_win877(bst
, bsh
, efir
, efdr
);
573 bus_space_write_1(bst
, bsh
, 0x3f0, 0xaa);
579 static int puc_find_free_unit(char *name
)
587 while (resource_int_value(name
, unit
, "port", &start
) == 0 &&
590 dc
= devclass_find(name
);
593 while (devclass_get_device(dc
, unit
))
596 kprintf("puc: Using %s%d\n", name
, unit
);
603 puc_print_resource_list(struct resource_list
*rl
)
605 struct resource_list_entry
*rle
;
607 kprintf("print_resource_list: rl %p\n", rl
);
608 SLIST_FOREACH(rle
, rl
, link
)
609 kprintf("type %x, rid %x\n", rle
->type
, rle
->rid
);
610 kprintf("print_resource_list: end.\n");
614 static struct resource
*
615 puc_alloc_resource(device_t dev
, device_t child
, int type
, int *rid
,
616 u_long start
, u_long end
, u_long count
, u_int flags
)
618 struct puc_device
*pdev
;
619 struct resource
*retval
;
620 struct resource_list
*rl
;
621 struct resource_list_entry
*rle
;
623 pdev
= device_get_ivars(child
);
624 rl
= &pdev
->resources
;
627 kprintf("puc_alloc_resource: pdev %p, looking for t %x, r %x\n",
629 puc_print_resource_list(rl
);
632 rle
= resource_list_find(rl
, type
, *rid
);
638 kprintf("found rle, %lx, %lx, %lx\n", start
, end
, count
);
642 kprintf("oops rle is gone\n");
648 puc_release_resource(device_t dev
, device_t child
, int type
, int rid
,
649 struct resource
*res
)
655 puc_get_resource(device_t dev
, device_t child
, int type
, int rid
,
656 u_long
*startp
, u_long
*countp
)
658 struct puc_device
*pdev
;
659 struct resource_list
*rl
;
660 struct resource_list_entry
*rle
;
662 pdev
= device_get_ivars(child
);
663 rl
= &pdev
->resources
;
666 kprintf("puc_get_resource: pdev %p, looking for t %x, r %x\n", pdev
,
668 puc_print_resource_list(rl
);
670 rle
= resource_list_find(rl
, type
, rid
);
673 kprintf("found rle %p,", rle
);
676 *startp
= rle
->start
;
678 *countp
= rle
->count
;
680 kprintf(" %lx, %lx\n", rle
->start
, rle
->count
);
684 kprintf("oops rle is gone\n");
689 puc_setup_intr(device_t dev
, device_t child
, struct resource
*r
, int flags
,
690 void (*ihand
)(void *), void *arg
,
691 void **cookiep
, lwkt_serialize_t serializer
)
694 struct puc_softc
*sc
;
696 sc
= (struct puc_softc
*)device_get_softc(dev
);
697 for (i
= 0; PUC_PORT_VALID(sc
->sc_desc
, i
); i
++) {
698 if (sc
->sc_ports
[i
].dev
== child
) {
699 if (sc
->sc_ports
[i
].ihand
!= 0)
701 sc
->sc_ports
[i
].ihand
= ihand
;
702 sc
->sc_ports
[i
].ihandarg
= arg
;
703 KKASSERT(serializer
== NULL
); /* not handled yet XXX */
712 puc_teardown_intr(device_t dev
, device_t child
, struct resource
*r
,
716 struct puc_softc
*sc
;
718 sc
= (struct puc_softc
*)device_get_softc(dev
);
719 for (i
= 0; PUC_PORT_VALID(sc
->sc_desc
, i
); i
++) {
720 if (sc
->sc_ports
[i
].dev
== child
) {
721 sc
->sc_ports
[i
].ihand
= NULL
;
722 sc
->sc_ports
[i
].ihandarg
= NULL
;
730 puc_read_ivar(device_t dev
, device_t child
, int index
, uintptr_t *result
)
732 struct puc_device
*pdev
;
734 pdev
= device_get_ivars(child
);
740 *result
= pdev
->serialfreq
;
748 static device_method_t puc_pci_methods
[] = {
749 /* Device interface */
750 DEVMETHOD(device_probe
, puc_pci_probe
),
751 DEVMETHOD(device_attach
, puc_pci_attach
),
753 DEVMETHOD(bus_alloc_resource
, puc_alloc_resource
),
754 DEVMETHOD(bus_release_resource
, puc_release_resource
),
755 DEVMETHOD(bus_get_resource
, puc_get_resource
),
756 DEVMETHOD(bus_read_ivar
, puc_read_ivar
),
757 DEVMETHOD(bus_setup_intr
, puc_setup_intr
),
758 DEVMETHOD(bus_teardown_intr
, puc_teardown_intr
),
759 DEVMETHOD(bus_print_child
, bus_generic_print_child
),
760 DEVMETHOD(bus_driver_added
, bus_generic_driver_added
),
764 static driver_t puc_pci_driver
= {
767 sizeof(struct puc_softc
),
770 static devclass_t puc_devclass
;
772 DRIVER_MODULE(puc
, pci
, puc_pci_driver
, puc_devclass
, 0, 0);