]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/puc/puc.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 static 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_detach(port->p_dev) == 0) {
416                         device_delete_child(dev, port->p_dev);
417                         if (port->p_rres != NULL)
418                                 rman_release_resource(port->p_rres);
419                         if (port->p_ires != NULL)
420                                 rman_release_resource(port->p_ires);
421                 } else
422                         error = ENXIO;
423         }
424         if (error)
425                 return (error);
426
427         if (sc->sc_serdevs != 0UL)
428                 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
429         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires);
430
431         for (idx = 0; idx < PUC_PCI_BARS; idx++) {
432                 bar = &sc->sc_bar[idx];
433                 if (bar->b_res != NULL)
434                         bus_release_resource(sc->sc_dev, bar->b_type,
435                             bar->b_rid, bar->b_res);
436         }
437
438         rman_fini(&sc->sc_irq);
439         free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
440         rman_fini(&sc->sc_iomem);
441         free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
442         rman_fini(&sc->sc_ioport);
443         free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
444         free(sc->sc_port, M_PUC);
445         return (0);
446 }
447
448 int
449 puc_bfe_probe(device_t dev, const struct puc_cfg *cfg)
450 {
451         struct puc_softc *sc;
452         intptr_t res;
453         int error;
454
455         sc = device_get_softc(dev);
456         sc->sc_dev = dev;
457         sc->sc_cfg = cfg;
458
459         /* We don't attach to single-port serial cards. */
460         if (cfg->ports == PUC_PORT_1S || cfg->ports == PUC_PORT_1P)
461                 return (EDOOFUS);
462         error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
463         if (error)
464                 return (error);
465         error = puc_config(sc, PUC_CFG_GET_DESC, 0, &res);
466         if (error)
467                 return (error);
468         if (res != 0)
469                 device_set_desc(dev, (const char *)res);
470         return (BUS_PROBE_DEFAULT);
471 }
472
473 struct resource *
474 puc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
475     u_long start, u_long end, u_long count, u_int flags)
476 {
477         struct puc_port *port;
478         struct resource *res;
479         device_t assigned, originator;
480         int error;
481
482         /* Get our immediate child. */
483         originator = child;
484         while (child != NULL && device_get_parent(child) != dev)
485                 child = device_get_parent(child);
486         if (child == NULL)
487                 return (NULL);
488
489         port = device_get_ivars(child);
490         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
491
492         if (rid == NULL || *rid != 0)
493                 return (NULL);
494
495         /* We only support default allocations. */
496         if (start != 0UL || end != ~0UL)
497                 return (NULL);
498
499         if (type == port->p_bar->b_type)
500                 res = port->p_rres;
501         else if (type == SYS_RES_IRQ)
502                 res = port->p_ires;
503         else
504                 return (NULL);
505
506         if (res == NULL)
507                 return (NULL);
508
509         assigned = rman_get_device(res);
510         if (assigned == NULL)   /* Not allocated */
511                 rman_set_device(res, originator);
512         else if (assigned != originator)
513                 return (NULL);
514
515         if (flags & RF_ACTIVE) {
516                 error = rman_activate_resource(res);
517                 if (error) {
518                         if (assigned == NULL)
519                                 rman_set_device(res, NULL);
520                         return (NULL);
521                 }
522         }
523
524         return (res);
525 }
526
527 int
528 puc_bus_release_resource(device_t dev, device_t child, int type, int rid,
529     struct resource *res)
530 {
531         struct puc_port *port;
532         device_t originator;
533
534         /* Get our immediate child. */
535         originator = child;
536         while (child != NULL && device_get_parent(child) != dev)
537                 child = device_get_parent(child);
538         if (child == NULL)
539                 return (EINVAL);
540
541         port = device_get_ivars(child);
542         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
543
544         if (rid != 0 || res == NULL)
545                 return (EINVAL);
546
547         if (type == port->p_bar->b_type) {
548                 if (res != port->p_rres)
549                         return (EINVAL);
550         } else if (type == SYS_RES_IRQ) {
551                 if (res != port->p_ires)
552                         return (EINVAL);
553                 if (port->p_hasintr)
554                         return (EBUSY);
555         } else
556                 return (EINVAL);
557
558         if (rman_get_device(res) != originator)
559                 return (ENXIO);
560         if (rman_get_flags(res) & RF_ACTIVE)
561                 rman_deactivate_resource(res);
562         rman_set_device(res, NULL);
563         return (0);
564 }
565
566 int
567 puc_bus_get_resource(device_t dev, device_t child, int type, int rid,
568     u_long *startp, u_long *countp)
569 {
570         struct puc_port *port;
571         struct resource *res;
572         u_long start;
573
574         /* Get our immediate child. */
575         while (child != NULL && device_get_parent(child) != dev)
576                 child = device_get_parent(child);
577         if (child == NULL)
578                 return (EINVAL);
579
580         port = device_get_ivars(child);
581         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
582
583         if (type == port->p_bar->b_type)
584                 res = port->p_rres;
585         else if (type == SYS_RES_IRQ)
586                 res = port->p_ires;
587         else
588                 return (ENXIO);
589
590         if (rid != 0 || res == NULL)
591                 return (ENXIO);
592
593         start = rman_get_start(res);
594         if (startp != NULL)
595                 *startp = start;
596         if (countp != NULL)
597                 *countp = rman_get_end(res) - start + 1;
598         return (0);
599 }
600
601 int
602 puc_bus_setup_intr(device_t dev, device_t child, struct resource *res,
603     int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep)
604 {
605         struct puc_port *port;
606         struct puc_softc *sc;
607         device_t originator;
608         int i, isrc, serdev;
609
610         sc = device_get_softc(dev);
611
612         /* Get our immediate child. */
613         originator = child;
614         while (child != NULL && device_get_parent(child) != dev)
615                 child = device_get_parent(child);
616         if (child == NULL)
617                 return (EINVAL);
618
619         port = device_get_ivars(child);
620         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
621
622         if (cookiep == NULL || res != port->p_ires)
623                 return (EINVAL);
624         /* We demand that serdev devices use filter_only interrupts. */
625         if (port->p_type == PUC_TYPE_SERIAL && ihand != NULL)
626                 return (ENXIO);
627         if (rman_get_device(port->p_ires) != originator)
628                 return (ENXIO);
629
630         /*
631          * Have non-serdev ports handled by the bus implementation. It
632          * supports multiple handlers for a single interrupt as it is,
633          * so we wouldn't add value if we did it ourselves.
634          */
635         serdev = 0;
636         if (port->p_type == PUC_TYPE_SERIAL) {
637                 i = 0, isrc = SER_INT_OVERRUN;
638                 while (i < PUC_ISRCCNT) {
639                         port->p_ihsrc[i] = SERDEV_IHAND(originator, isrc);
640                         if (port->p_ihsrc[i] != NULL)
641                                 serdev = 1;
642                         i++, isrc <<= 1;
643                 }
644         }
645         if (!serdev)
646                 return (BUS_SETUP_INTR(device_get_parent(dev), originator,
647                     sc->sc_ires, flags, filt, ihand, arg, cookiep));
648
649         sc->sc_serdevs |= 1UL << (port->p_nr - 1);
650
651         port->p_hasintr = 1;
652         port->p_iharg = arg;
653
654         *cookiep = port;
655         return (0);
656 }
657
658 int
659 puc_bus_teardown_intr(device_t dev, device_t child, struct resource *res,
660     void *cookie)
661 {
662         struct puc_port *port;
663         struct puc_softc *sc;
664         device_t originator;
665         int i;
666
667         sc = device_get_softc(dev);
668
669         /* Get our immediate child. */
670         originator = child;
671         while (child != NULL && device_get_parent(child) != dev)
672                 child = device_get_parent(child);
673         if (child == NULL)
674                 return (EINVAL);
675
676         port = device_get_ivars(child);
677         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
678
679         if (res != port->p_ires)
680                 return (EINVAL);
681         if (rman_get_device(port->p_ires) != originator)
682                 return (ENXIO);
683
684         if (!port->p_hasintr)
685                 return (BUS_TEARDOWN_INTR(device_get_parent(dev), originator,
686                     sc->sc_ires, cookie));
687
688         if (cookie != port)
689                 return (EINVAL);
690
691         port->p_hasintr = 0;
692         port->p_iharg = NULL;
693
694         for (i = 0; i < PUC_ISRCCNT; i++)
695                 port->p_ihsrc[i] = NULL;
696
697         return (0);
698 }
699
700 int
701 puc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
702 {
703         struct puc_port *port;
704
705         /* Get our immediate child. */
706         while (child != NULL && device_get_parent(child) != dev)
707                 child = device_get_parent(child);
708         if (child == NULL)
709                 return (EINVAL);
710
711         port = device_get_ivars(child);
712         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
713
714         if (result == NULL)
715                 return (EINVAL);
716
717         switch(index) {
718         case PUC_IVAR_CLOCK:
719                 *result = port->p_rclk;
720                 break;
721         case PUC_IVAR_TYPE:
722                 *result = port->p_type;
723                 break;
724         default:
725                 return (ENOENT);
726         }
727         return (0);
728 }
729
730 int
731 puc_bus_print_child(device_t dev, device_t child)
732 {
733         struct puc_port *port;
734         int retval;
735
736         port = device_get_ivars(child);
737         retval = 0;
738
739         retval += bus_print_child_header(dev, child);
740         retval += printf(" at port %d", port->p_nr);
741         retval += bus_print_child_footer(dev, child);
742
743         return (retval);
744 }
745
746 int
747 puc_bus_child_location_str(device_t dev, device_t child, char *buf,
748     size_t buflen)
749 {
750         struct puc_port *port;
751
752         port = device_get_ivars(child);
753         snprintf(buf, buflen, "port=%d", port->p_nr);
754         return (0);
755 }
756
757 int
758 puc_bus_child_pnpinfo_str(device_t dev, device_t child, char *buf,
759     size_t buflen)
760 {
761         struct puc_port *port;
762
763         port = device_get_ivars(child);
764         snprintf(buf, buflen, "type=%d", port->p_type);
765         return (0);
766 }