]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/dev/puc/puc.c
MFC r307518:
[FreeBSD/stable/8.git] / sys / dev / puc / puc.c
1 /*-
2  * Copyright (c) 2006 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
34 #include <sys/conf.h>
35 #include <sys/malloc.h>
36 #include <sys/mutex.h>
37
38 #include <machine/bus.h>
39 #include <machine/resource.h>
40 #include <sys/rman.h>
41
42 #include <dev/pci/pcireg.h>
43 #include <dev/pci/pcivar.h>
44
45 #include <dev/puc/puc_bus.h>
46 #include <dev/puc/puc_cfg.h>
47 #include <dev/puc/puc_bfe.h>
48
49 #define PUC_ISRCCNT     5
50
51 struct puc_port {
52         struct puc_bar  *p_bar;
53         struct resource *p_rres;
54         struct resource *p_ires;
55         device_t        p_dev;
56         int             p_nr;
57         int             p_type;
58         int             p_rclk;
59
60         int             p_hasintr:1;
61
62         serdev_intr_t   *p_ihsrc[PUC_ISRCCNT];
63         void            *p_iharg;
64
65         int             p_ipend;
66 };
67
68 devclass_t puc_devclass;
69 const char puc_driver_name[] = "puc";
70
71 MALLOC_DEFINE(M_PUC, "PUC", "PUC driver");
72
73 struct puc_bar *
74 puc_get_bar(struct puc_softc *sc, int rid)
75 {
76         struct puc_bar *bar;
77         struct rman *rm;
78         u_long end, start;
79         int error, i;
80
81         /* Find the BAR entry with the given RID. */
82         i = 0;
83         while (i < PUC_PCI_BARS && sc->sc_bar[i].b_rid != rid)
84                 i++;
85         if (i < PUC_PCI_BARS)
86                 return (&sc->sc_bar[i]);
87
88         /* Not found. If we're looking for an unused entry, return NULL. */
89         if (rid == -1)
90                 return (NULL);
91
92         /* Get an unused entry for us to fill.  */
93         bar = puc_get_bar(sc, -1);
94         if (bar == NULL)
95                 return (NULL);
96         bar->b_rid = rid;
97         bar->b_type = SYS_RES_IOPORT;
98         bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
99             &bar->b_rid, RF_ACTIVE);
100         if (bar->b_res == NULL) {
101                 bar->b_rid = rid;
102                 bar->b_type = SYS_RES_MEMORY;
103                 bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
104                     &bar->b_rid, RF_ACTIVE);
105                 if (bar->b_res == NULL) {
106                         bar->b_rid = -1;
107                         return (NULL);
108                 }
109         }
110
111         /* Update our managed space. */
112         rm = (bar->b_type == SYS_RES_IOPORT) ? &sc->sc_ioport : &sc->sc_iomem;
113         start = rman_get_start(bar->b_res);
114         end = rman_get_end(bar->b_res);
115         error = rman_manage_region(rm, start, end);
116         if (error) {
117                 bus_release_resource(sc->sc_dev, bar->b_type, bar->b_rid,
118                     bar->b_res);
119                 bar->b_res = NULL;
120                 bar->b_rid = -1;
121                 bar = NULL;
122         }
123
124         return (bar);
125 }
126
127 static int
128 puc_intr(void *arg)
129 {
130         struct puc_port *port;
131         struct puc_softc *sc = arg;
132         u_long ds, dev, devs;
133         int i, idx, ipend, isrc, nints;
134         uint8_t ilr;
135
136         nints = 0;
137         while (1) {
138                 /*
139                  * Obtain the set of devices with pending interrupts.
140                  */
141                 devs = sc->sc_serdevs;
142                 if (sc->sc_ilr == PUC_ILR_DIGI) {
143                         idx = 0;
144                         while (devs & (0xfful << idx)) {
145                                 ilr = ~bus_read_1(sc->sc_port[idx].p_rres, 7);
146                                 devs &= ~0ul ^ ((u_long)ilr << idx);
147                                 idx += 8;
148                         }
149                 } else if (sc->sc_ilr == PUC_ILR_QUATECH) {
150                         /*
151                          * Don't trust the value if it's the same as the option
152                          * register. It may mean that the ILR is not active and
153                          * we're reading the option register instead. This may
154                          * lead to false positives on 8-port boards.
155                          */
156                         ilr = bus_read_1(sc->sc_port[0].p_rres, 7);
157                         if (ilr != (sc->sc_cfg_data & 0xff))
158                                 devs &= (u_long)ilr;
159                 }
160                 if (devs == 0UL)
161                         break;
162
163                 /*
164                  * Obtain the set of interrupt sources from those devices
165                  * that have pending interrupts.
166                  */
167                 ipend = 0;
168                 idx = 0, dev = 1UL;
169                 ds = devs;
170                 while (ds != 0UL) {
171                         while ((ds & dev) == 0UL)
172                                 idx++, dev <<= 1;
173                         ds &= ~dev;
174                         port = &sc->sc_port[idx];
175                         port->p_ipend = SERDEV_IPEND(port->p_dev);
176                         ipend |= port->p_ipend;
177                 }
178                 if (ipend == 0)
179                         break;
180
181                 i = 0, isrc = SER_INT_OVERRUN;
182                 while (ipend) {
183                         while (i < PUC_ISRCCNT && !(ipend & isrc))
184                                 i++, isrc <<= 1;
185                         KASSERT(i < PUC_ISRCCNT, ("%s", __func__));
186                         ipend &= ~isrc;
187                         idx = 0, dev = 1UL;
188                         ds = devs;
189                         while (ds != 0UL) {
190                                 while ((ds & dev) == 0UL)
191                                         idx++, dev <<= 1;
192                                 ds &= ~dev;
193                                 port = &sc->sc_port[idx];
194                                 if (!(port->p_ipend & isrc))
195                                         continue;
196                                 if (port->p_ihsrc[i] != NULL)
197                                         (*port->p_ihsrc[i])(port->p_iharg);
198                                 nints++;
199                         }
200                 }
201         }
202
203         return ((nints > 0) ? FILTER_HANDLED : FILTER_STRAY);
204 }
205
206 int
207 puc_bfe_attach(device_t dev)
208 {
209         char buffer[64];
210         struct puc_bar *bar;
211         struct puc_port *port;
212         struct puc_softc *sc;
213         struct rman *rm;
214         intptr_t res;
215         bus_addr_t ofs, start;
216         bus_size_t size;
217         bus_space_handle_t bsh;
218         bus_space_tag_t bst;
219         int error, idx;
220
221         sc = device_get_softc(dev);
222
223         for (idx = 0; idx < PUC_PCI_BARS; idx++)
224                 sc->sc_bar[idx].b_rid = -1;
225
226         do {
227                 sc->sc_ioport.rm_type = RMAN_ARRAY;
228                 error = rman_init(&sc->sc_ioport);
229                 if (!error) {
230                         sc->sc_iomem.rm_type = RMAN_ARRAY;
231                         error = rman_init(&sc->sc_iomem);
232                         if (!error) {
233                                 sc->sc_irq.rm_type = RMAN_ARRAY;
234                                 error = rman_init(&sc->sc_irq);
235                                 if (!error)
236                                         break;
237                                 rman_fini(&sc->sc_iomem);
238                         }
239                         rman_fini(&sc->sc_ioport);
240                 }
241                 return (error);
242         } while (0);
243
244         snprintf(buffer, sizeof(buffer), "%s I/O port mapping",
245             device_get_nameunit(dev));
246         sc->sc_ioport.rm_descr = strdup(buffer, M_PUC);
247         snprintf(buffer, sizeof(buffer), "%s I/O memory mapping",
248             device_get_nameunit(dev));
249         sc->sc_iomem.rm_descr = strdup(buffer, M_PUC);
250         snprintf(buffer, sizeof(buffer), "%s port numbers",
251             device_get_nameunit(dev));
252         sc->sc_irq.rm_descr = strdup(buffer, M_PUC);
253
254         error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
255         KASSERT(error == 0, ("%s %d", __func__, __LINE__));
256         sc->sc_nports = (int)res;
257         sc->sc_port = malloc(sc->sc_nports * sizeof(struct puc_port),
258             M_PUC, M_WAITOK|M_ZERO);
259
260         error = rman_manage_region(&sc->sc_irq, 1, sc->sc_nports);
261         if (error)
262                 goto fail;
263
264         error = puc_config(sc, PUC_CFG_SETUP, 0, &res);
265         if (error)
266                 goto fail;
267
268         for (idx = 0; idx < sc->sc_nports; idx++) {
269                 port = &sc->sc_port[idx];
270                 port->p_nr = idx + 1;
271                 error = puc_config(sc, PUC_CFG_GET_TYPE, idx, &res);
272                 if (error)
273                         goto fail;
274                 port->p_type = res;
275                 error = puc_config(sc, PUC_CFG_GET_RID, idx, &res);
276                 if (error)
277                         goto fail;
278                 bar = puc_get_bar(sc, res);
279                 if (bar == NULL) {
280                         error = ENXIO;
281                         goto fail;
282                 }
283                 port->p_bar = bar;
284                 start = rman_get_start(bar->b_res);
285                 error = puc_config(sc, PUC_CFG_GET_OFS, idx, &res);
286                 if (error)
287                         goto fail;
288                 ofs = res;
289                 error = puc_config(sc, PUC_CFG_GET_LEN, idx, &res);
290                 if (error)
291                         goto fail;
292                 size = res;
293                 rm = (bar->b_type == SYS_RES_IOPORT)
294                     ? &sc->sc_ioport: &sc->sc_iomem;
295                 port->p_rres = rman_reserve_resource(rm, start + ofs,
296                     start + ofs + size - 1, size, 0, NULL);
297                 if (port->p_rres != NULL) {
298                         bsh = rman_get_bushandle(bar->b_res);
299                         bst = rman_get_bustag(bar->b_res);
300                         bus_space_subregion(bst, bsh, ofs, size, &bsh);
301                         rman_set_bushandle(port->p_rres, bsh);
302                         rman_set_bustag(port->p_rres, bst);
303                 }
304                 port->p_ires = rman_reserve_resource(&sc->sc_irq, port->p_nr,
305                     port->p_nr, 1, 0, NULL);
306                 if (port->p_ires == NULL) {
307                         error = ENXIO;
308                         goto fail;
309                 }
310                 error = puc_config(sc, PUC_CFG_GET_CLOCK, idx, &res);
311                 if (error)
312                         goto fail;
313                 port->p_rclk = res;
314
315                 port->p_dev = device_add_child(dev, NULL, -1);
316                 if (port->p_dev != NULL)
317                         device_set_ivars(port->p_dev, (void *)port);
318         }
319
320         error = puc_config(sc, PUC_CFG_GET_ILR, 0, &res);
321         if (error)
322                 goto fail;
323         sc->sc_ilr = res;
324         if (bootverbose && sc->sc_ilr != 0)
325                 device_printf(dev, "using interrupt latch register\n");
326
327         sc->sc_irid = 0;
328         sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
329             RF_ACTIVE|RF_SHAREABLE);
330         if (sc->sc_ires != NULL) {
331                 error = bus_setup_intr(dev, sc->sc_ires,
332                     INTR_TYPE_TTY, puc_intr, NULL, sc, &sc->sc_icookie);
333                 if (error)
334                         error = bus_setup_intr(dev, sc->sc_ires,
335                             INTR_TYPE_TTY | INTR_MPSAFE, NULL,
336                             (driver_intr_t *)puc_intr, sc, &sc->sc_icookie);
337                 else
338                         sc->sc_fastintr = 1;
339
340                 if (error) {
341                         device_printf(dev, "could not activate interrupt\n");
342                         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
343                             sc->sc_ires);
344                         sc->sc_ires = NULL;
345                 }
346         }
347         if (sc->sc_ires == NULL) {
348                 /* XXX no interrupt resource. Force polled mode. */
349                 sc->sc_polled = 1;
350         }
351
352         /* Probe and attach our children. */
353         for (idx = 0; idx < sc->sc_nports; idx++) {
354                 port = &sc->sc_port[idx];
355                 if (port->p_dev == NULL)
356                         continue;
357                 error = device_probe_and_attach(port->p_dev);
358                 if (error) {
359                         device_delete_child(dev, port->p_dev);
360                         port->p_dev = NULL;
361                 }
362         }
363
364         /*
365          * If there are no serdev devices, then our interrupt handler
366          * will do nothing. Tear it down.
367          */
368         if (sc->sc_serdevs == 0UL)
369                 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
370
371         return (0);
372
373 fail:
374         for (idx = 0; idx < sc->sc_nports; idx++) {
375                 port = &sc->sc_port[idx];
376                 if (port->p_dev != NULL)
377                         device_delete_child(dev, port->p_dev);
378                 if (port->p_rres != NULL)
379                         rman_release_resource(port->p_rres);
380                 if (port->p_ires != NULL)
381                         rman_release_resource(port->p_ires);
382         }
383         for (idx = 0; idx < PUC_PCI_BARS; idx++) {
384                 bar = &sc->sc_bar[idx];
385                 if (bar->b_res != NULL)
386                         bus_release_resource(sc->sc_dev, bar->b_type,
387                             bar->b_rid, bar->b_res);
388         }
389         rman_fini(&sc->sc_irq);
390         free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
391         rman_fini(&sc->sc_iomem);
392         free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
393         rman_fini(&sc->sc_ioport);
394         free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
395         free(sc->sc_port, M_PUC);
396         return (error);
397 }
398
399 int
400 puc_bfe_detach(device_t dev)
401 {
402         struct puc_bar *bar;
403         struct puc_port *port;
404         struct puc_softc *sc;
405         int error, idx;
406
407         sc = device_get_softc(dev);
408
409         /* Detach our children. */
410         error = 0;
411         for (idx = 0; idx < sc->sc_nports; idx++) {
412                 port = &sc->sc_port[idx];
413                 if (port->p_dev == NULL)
414                         continue;
415                 if (device_delete_child(dev, port->p_dev) == 0) {
416                         if (port->p_rres != NULL)
417                                 rman_release_resource(port->p_rres);
418                         if (port->p_ires != NULL)
419                                 rman_release_resource(port->p_ires);
420                 } else
421                         error = ENXIO;
422         }
423         if (error)
424                 return (error);
425
426         if (sc->sc_serdevs != 0UL)
427                 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
428         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires);
429
430         for (idx = 0; idx < PUC_PCI_BARS; idx++) {
431                 bar = &sc->sc_bar[idx];
432                 if (bar->b_res != NULL)
433                         bus_release_resource(sc->sc_dev, bar->b_type,
434                             bar->b_rid, bar->b_res);
435         }
436
437         rman_fini(&sc->sc_irq);
438         free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
439         rman_fini(&sc->sc_iomem);
440         free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
441         rman_fini(&sc->sc_ioport);
442         free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
443         free(sc->sc_port, M_PUC);
444         return (0);
445 }
446
447 int
448 puc_bfe_probe(device_t dev, const struct puc_cfg *cfg)
449 {
450         struct puc_softc *sc;
451         intptr_t res;
452         int error;
453
454         sc = device_get_softc(dev);
455         sc->sc_dev = dev;
456         sc->sc_cfg = cfg;
457
458         /* We don't attach to single-port serial cards. */
459         if (cfg->ports == PUC_PORT_1S || cfg->ports == PUC_PORT_1P)
460                 return (EDOOFUS);
461         error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
462         if (error)
463                 return (error);
464         error = puc_config(sc, PUC_CFG_GET_DESC, 0, &res);
465         if (error)
466                 return (error);
467         if (res != 0)
468                 device_set_desc(dev, (const char *)res);
469         return (BUS_PROBE_DEFAULT);
470 }
471
472 struct resource *
473 puc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
474     u_long start, u_long end, u_long count, u_int flags)
475 {
476         struct puc_port *port;
477         struct resource *res;
478         device_t assigned, originator;
479         int error;
480
481         /* Get our immediate child. */
482         originator = child;
483         while (child != NULL && device_get_parent(child) != dev)
484                 child = device_get_parent(child);
485         if (child == NULL)
486                 return (NULL);
487
488         port = device_get_ivars(child);
489         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
490
491         if (rid == NULL || *rid != 0)
492                 return (NULL);
493
494         /* We only support default allocations. */
495         if (start != 0UL || end != ~0UL)
496                 return (NULL);
497
498         if (type == port->p_bar->b_type)
499                 res = port->p_rres;
500         else if (type == SYS_RES_IRQ)
501                 res = port->p_ires;
502         else
503                 return (NULL);
504
505         if (res == NULL)
506                 return (NULL);
507
508         assigned = rman_get_device(res);
509         if (assigned == NULL)   /* Not allocated */
510                 rman_set_device(res, originator);
511         else if (assigned != originator)
512                 return (NULL);
513
514         if (flags & RF_ACTIVE) {
515                 error = rman_activate_resource(res);
516                 if (error) {
517                         if (assigned == NULL)
518                                 rman_set_device(res, NULL);
519                         return (NULL);
520                 }
521         }
522
523         return (res);
524 }
525
526 int
527 puc_bus_release_resource(device_t dev, device_t child, int type, int rid,
528     struct resource *res)
529 {
530         struct puc_port *port;
531         device_t originator;
532
533         /* Get our immediate child. */
534         originator = child;
535         while (child != NULL && device_get_parent(child) != dev)
536                 child = device_get_parent(child);
537         if (child == NULL)
538                 return (EINVAL);
539
540         port = device_get_ivars(child);
541         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
542
543         if (rid != 0 || res == NULL)
544                 return (EINVAL);
545
546         if (type == port->p_bar->b_type) {
547                 if (res != port->p_rres)
548                         return (EINVAL);
549         } else if (type == SYS_RES_IRQ) {
550                 if (res != port->p_ires)
551                         return (EINVAL);
552                 if (port->p_hasintr)
553                         return (EBUSY);
554         } else
555                 return (EINVAL);
556
557         if (rman_get_device(res) != originator)
558                 return (ENXIO);
559         if (rman_get_flags(res) & RF_ACTIVE)
560                 rman_deactivate_resource(res);
561         rman_set_device(res, NULL);
562         return (0);
563 }
564
565 int
566 puc_bus_get_resource(device_t dev, device_t child, int type, int rid,
567     u_long *startp, u_long *countp)
568 {
569         struct puc_port *port;
570         struct resource *res;
571         u_long start;
572
573         /* Get our immediate child. */
574         while (child != NULL && device_get_parent(child) != dev)
575                 child = device_get_parent(child);
576         if (child == NULL)
577                 return (EINVAL);
578
579         port = device_get_ivars(child);
580         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
581
582         if (type == port->p_bar->b_type)
583                 res = port->p_rres;
584         else if (type == SYS_RES_IRQ)
585                 res = port->p_ires;
586         else
587                 return (ENXIO);
588
589         if (rid != 0 || res == NULL)
590                 return (ENXIO);
591
592         start = rman_get_start(res);
593         if (startp != NULL)
594                 *startp = start;
595         if (countp != NULL)
596                 *countp = rman_get_end(res) - start + 1;
597         return (0);
598 }
599
600 int
601 puc_bus_setup_intr(device_t dev, device_t child, struct resource *res,
602     int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep)
603 {
604         struct puc_port *port;
605         struct puc_softc *sc;
606         device_t originator;
607         int i, isrc, serdev;
608
609         sc = device_get_softc(dev);
610
611         /* Get our immediate child. */
612         originator = child;
613         while (child != NULL && device_get_parent(child) != dev)
614                 child = device_get_parent(child);
615         if (child == NULL)
616                 return (EINVAL);
617
618         port = device_get_ivars(child);
619         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
620
621         if (cookiep == NULL || res != port->p_ires)
622                 return (EINVAL);
623         /* We demand that serdev devices use filter_only interrupts. */
624         if (port->p_type == PUC_TYPE_SERIAL && ihand != NULL)
625                 return (ENXIO);
626         if (rman_get_device(port->p_ires) != originator)
627                 return (ENXIO);
628
629         /*
630          * Have non-serdev ports handled by the bus implementation. It
631          * supports multiple handlers for a single interrupt as it is,
632          * so we wouldn't add value if we did it ourselves.
633          */
634         serdev = 0;
635         if (port->p_type == PUC_TYPE_SERIAL) {
636                 i = 0, isrc = SER_INT_OVERRUN;
637                 while (i < PUC_ISRCCNT) {
638                         port->p_ihsrc[i] = SERDEV_IHAND(originator, isrc);
639                         if (port->p_ihsrc[i] != NULL)
640                                 serdev = 1;
641                         i++, isrc <<= 1;
642                 }
643         }
644         if (!serdev)
645                 return (BUS_SETUP_INTR(device_get_parent(dev), originator,
646                     sc->sc_ires, flags, filt, ihand, arg, cookiep));
647
648         sc->sc_serdevs |= 1UL << (port->p_nr - 1);
649
650         port->p_hasintr = 1;
651         port->p_iharg = arg;
652
653         *cookiep = port;
654         return (0);
655 }
656
657 int
658 puc_bus_teardown_intr(device_t dev, device_t child, struct resource *res,
659     void *cookie)
660 {
661         struct puc_port *port;
662         struct puc_softc *sc;
663         device_t originator;
664         int i;
665
666         sc = device_get_softc(dev);
667
668         /* Get our immediate child. */
669         originator = child;
670         while (child != NULL && device_get_parent(child) != dev)
671                 child = device_get_parent(child);
672         if (child == NULL)
673                 return (EINVAL);
674
675         port = device_get_ivars(child);
676         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
677
678         if (res != port->p_ires)
679                 return (EINVAL);
680         if (rman_get_device(port->p_ires) != originator)
681                 return (ENXIO);
682
683         if (!port->p_hasintr)
684                 return (BUS_TEARDOWN_INTR(device_get_parent(dev), originator,
685                     sc->sc_ires, cookie));
686
687         if (cookie != port)
688                 return (EINVAL);
689
690         port->p_hasintr = 0;
691         port->p_iharg = NULL;
692
693         for (i = 0; i < PUC_ISRCCNT; i++)
694                 port->p_ihsrc[i] = NULL;
695
696         return (0);
697 }
698
699 int
700 puc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
701 {
702         struct puc_port *port;
703
704         /* Get our immediate child. */
705         while (child != NULL && device_get_parent(child) != dev)
706                 child = device_get_parent(child);
707         if (child == NULL)
708                 return (EINVAL);
709
710         port = device_get_ivars(child);
711         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
712
713         if (result == NULL)
714                 return (EINVAL);
715
716         switch(index) {
717         case PUC_IVAR_CLOCK:
718                 *result = port->p_rclk;
719                 break;
720         case PUC_IVAR_TYPE:
721                 *result = port->p_type;
722                 break;
723         default:
724                 return (ENOENT);
725         }
726         return (0);
727 }
728
729 int
730 puc_bus_print_child(device_t dev, device_t child)
731 {
732         struct puc_port *port;
733         int retval;
734
735         port = device_get_ivars(child);
736         retval = 0;
737
738         retval += bus_print_child_header(dev, child);
739         retval += printf(" at port %d", port->p_nr);
740         retval += bus_print_child_footer(dev, child);
741
742         return (retval);
743 }
744
745 int
746 puc_bus_child_location_str(device_t dev, device_t child, char *buf,
747     size_t buflen)
748 {
749         struct puc_port *port;
750
751         port = device_get_ivars(child);
752         snprintf(buf, buflen, "port=%d", port->p_nr);
753         return (0);
754 }
755
756 int
757 puc_bus_child_pnpinfo_str(device_t dev, device_t child, char *buf,
758     size_t buflen)
759 {
760         struct puc_port *port;
761
762         port = device_get_ivars(child);
763         snprintf(buf, buflen, "type=%d", port->p_type);
764         return (0);
765 }