]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/puc/puc.c
This commit was generated by cvs2svn to compensate for changes in r170349,
[FreeBSD/FreeBSD.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         driver_filter_t *p_ih;
63         serdev_intr_t   *p_ihsrc[PUC_ISRCCNT];
64         void            *p_iharg;
65
66         int             p_ipend;
67 };
68
69 devclass_t puc_devclass;
70 const char puc_driver_name[] = "puc";
71
72 MALLOC_DEFINE(M_PUC, "PUC", "PUC driver");
73
74 struct puc_bar *
75 puc_get_bar(struct puc_softc *sc, int rid)
76 {
77         struct puc_bar *bar;
78         struct rman *rm;
79         u_long end, start;
80         int error, i;
81
82         /* Find the BAR entry with the given RID. */
83         i = 0;
84         while (i < PUC_PCI_BARS && sc->sc_bar[i].b_rid != rid)
85                 i++;
86         if (i < PUC_PCI_BARS)
87                 return (&sc->sc_bar[i]);
88
89         /* Not found. If we're looking for an unused entry, return NULL. */
90         if (rid == -1)
91                 return (NULL);
92
93         /* Get an unused entry for us to fill.  */
94         bar = puc_get_bar(sc, -1);
95         if (bar == NULL)
96                 return (NULL);
97         bar->b_rid = rid;
98         bar->b_type = SYS_RES_IOPORT;
99         bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
100             &bar->b_rid, RF_ACTIVE);
101         if (bar->b_res == NULL) {
102                 bar->b_rid = rid;
103                 bar->b_type = SYS_RES_MEMORY;
104                 bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
105                     &bar->b_rid, RF_ACTIVE);
106                 if (bar->b_res == NULL) {
107                         bar->b_rid = -1;
108                         return (NULL);
109                 }
110         }
111
112         /* Update our managed space. */
113         rm = (bar->b_type == SYS_RES_IOPORT) ? &sc->sc_ioport : &sc->sc_iomem;
114         start = rman_get_start(bar->b_res);
115         end = rman_get_end(bar->b_res);
116         error = rman_manage_region(rm, start, end);
117         if (error) {
118                 bus_release_resource(sc->sc_dev, bar->b_type, bar->b_rid,
119                     bar->b_res);
120                 bar->b_res = NULL;
121                 bar->b_rid = -1;
122                 bar = NULL;
123         }
124
125         return (bar);
126 }
127
128 static int
129 puc_intr(void *arg)
130 {
131         struct puc_port *port;
132         struct puc_softc *sc = arg;
133         u_long dev, devs;
134         int i, idx, ipend, isrc;
135         uint8_t ilr;
136
137         devs = sc->sc_serdevs;
138         if (sc->sc_ilr == PUC_ILR_DIGI) {
139                 idx = 0;
140                 while (devs & (0xfful << idx)) {
141                         ilr = ~bus_read_1(sc->sc_port[idx].p_rres, 7);
142                         devs &= ~0ul ^ ((u_long)ilr << idx);
143                         idx += 8;
144                 }
145         } else if (sc->sc_ilr == PUC_ILR_QUATECH) {
146                 /*
147                  * Don't trust the value if it's the same as the option
148                  * register. It may mean that the ILR is not active and
149                  * we're reading the option register instead. This may
150                  * lead to false positives on 8-port boards.
151                  */
152                 ilr = bus_read_1(sc->sc_port[0].p_rres, 7);
153                 if (ilr != (sc->sc_cfg_data & 0xff))
154                         devs &= (u_long)ilr;
155         }
156
157         ipend = 0;
158         idx = 0, dev = 1UL;
159         while (devs != 0UL) {
160                 while ((devs & dev) == 0UL)
161                         idx++, dev <<= 1;
162                 devs &= ~dev;
163                 port = &sc->sc_port[idx];
164                 port->p_ipend = SERDEV_IPEND(port->p_dev);
165                 ipend |= port->p_ipend;
166         }
167
168         i = 0, isrc = SER_INT_OVERRUN;
169         while (ipend) {
170                 while (i < PUC_ISRCCNT && !(ipend & isrc))
171                         i++, isrc <<= 1;
172                 KASSERT(i < PUC_ISRCCNT, ("%s", __func__));
173                 ipend &= ~isrc;
174                 idx = 0, dev = 1UL;
175                 devs = sc->sc_serdevs;
176                 while (devs != 0UL) {
177                         while ((devs & dev) == 0UL)
178                                 idx++, dev <<= 1;
179                         devs &= ~dev;
180                         port = &sc->sc_port[idx];
181                         if (!(port->p_ipend & isrc))
182                                 continue;
183                         if (port->p_ihsrc[i] != NULL)
184                                 (*port->p_ihsrc[i])(port->p_iharg);
185                 }
186                 return (FILTER_HANDLED);
187         }
188         return (FILTER_STRAY);
189 }
190
191 int
192 puc_bfe_attach(device_t dev)
193 {
194         char buffer[64];
195         struct puc_bar *bar;
196         struct puc_port *port;
197         struct puc_softc *sc;
198         struct rman *rm;
199         intptr_t res;
200         bus_addr_t ofs, start;
201         bus_size_t size;
202         bus_space_handle_t bsh;
203         bus_space_tag_t bst;
204         int error, idx;
205
206         sc = device_get_softc(dev);
207
208         for (idx = 0; idx < PUC_PCI_BARS; idx++)
209                 sc->sc_bar[idx].b_rid = -1;
210
211         do {
212                 sc->sc_ioport.rm_type = RMAN_ARRAY;
213                 error = rman_init(&sc->sc_ioport);
214                 if (!error) {
215                         sc->sc_iomem.rm_type = RMAN_ARRAY;
216                         error = rman_init(&sc->sc_iomem);
217                         if (!error) {
218                                 sc->sc_irq.rm_type = RMAN_ARRAY;
219                                 error = rman_init(&sc->sc_irq);
220                                 if (!error)
221                                         break;
222                                 rman_fini(&sc->sc_iomem);
223                         }
224                         rman_fini(&sc->sc_ioport);
225                 }
226                 return (error);
227         } while (0);
228
229         snprintf(buffer, sizeof(buffer), "%s I/O port mapping",
230             device_get_nameunit(dev));
231         sc->sc_ioport.rm_descr = strdup(buffer, M_PUC);
232         snprintf(buffer, sizeof(buffer), "%s I/O memory mapping",
233             device_get_nameunit(dev));
234         sc->sc_iomem.rm_descr = strdup(buffer, M_PUC);
235         snprintf(buffer, sizeof(buffer), "%s port numbers",
236             device_get_nameunit(dev));
237         sc->sc_irq.rm_descr = strdup(buffer, M_PUC);
238
239         error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
240         KASSERT(error == 0, ("%s %d", __func__, __LINE__));
241         sc->sc_nports = (int)res;
242         sc->sc_port = malloc(sc->sc_nports * sizeof(struct puc_port),
243             M_PUC, M_WAITOK|M_ZERO);
244
245         error = rman_manage_region(&sc->sc_irq, 1, sc->sc_nports);
246         if (error)
247                 goto fail;
248
249         error = puc_config(sc, PUC_CFG_SETUP, 0, &res);
250         if (error)
251                 goto fail;
252
253         for (idx = 0; idx < sc->sc_nports; idx++) {
254                 port = &sc->sc_port[idx];
255                 port->p_nr = idx + 1;
256                 error = puc_config(sc, PUC_CFG_GET_TYPE, idx, &res);
257                 if (error)
258                         goto fail;
259                 port->p_type = res;
260                 error = puc_config(sc, PUC_CFG_GET_RID, idx, &res);
261                 if (error)
262                         goto fail;
263                 bar = puc_get_bar(sc, res);
264                 if (bar == NULL) {
265                         error = ENXIO;
266                         goto fail;
267                 }
268                 port->p_bar = bar;
269                 start = rman_get_start(bar->b_res);
270                 error = puc_config(sc, PUC_CFG_GET_OFS, idx, &res);
271                 if (error)
272                         goto fail;
273                 ofs = res;
274                 error = puc_config(sc, PUC_CFG_GET_LEN, idx, &res);
275                 if (error)
276                         goto fail;
277                 size = res;
278                 rm = (bar->b_type == SYS_RES_IOPORT)
279                     ? &sc->sc_ioport: &sc->sc_iomem;
280                 port->p_rres = rman_reserve_resource(rm, start + ofs,
281                     start + ofs + size - 1, size, 0, NULL);
282                 if (port->p_rres != NULL) {
283                         bsh = rman_get_bushandle(bar->b_res);
284                         bst = rman_get_bustag(bar->b_res);
285                         bus_space_subregion(bst, bsh, ofs, size, &bsh);
286                         rman_set_bushandle(port->p_rres, bsh);
287                         rman_set_bustag(port->p_rres, bst);
288                 }
289                 port->p_ires = rman_reserve_resource(&sc->sc_irq, port->p_nr,
290                     port->p_nr, 1, 0, NULL);
291                 if (port->p_ires == NULL) {
292                         error = ENXIO;
293                         goto fail;
294                 }
295                 error = puc_config(sc, PUC_CFG_GET_CLOCK, idx, &res);
296                 if (error)
297                         goto fail;
298                 port->p_rclk = res;
299
300                 port->p_dev = device_add_child(dev, NULL, -1);
301                 if (port->p_dev != NULL)
302                         device_set_ivars(port->p_dev, (void *)port);
303         }
304
305         error = puc_config(sc, PUC_CFG_GET_ILR, 0, &res);
306         if (error)
307                 goto fail;
308         sc->sc_ilr = res;
309         if (bootverbose && sc->sc_ilr != 0)
310                 device_printf(dev, "using interrupt latch register\n");
311
312         sc->sc_irid = 0;
313         sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
314             RF_ACTIVE|RF_SHAREABLE);
315         if (sc->sc_ires != NULL) {
316                 error = bus_setup_intr(dev, sc->sc_ires,
317                     INTR_TYPE_TTY, puc_intr, NULL, sc, &sc->sc_icookie);
318                 if (error)
319                         error = bus_setup_intr(dev, sc->sc_ires,
320                             INTR_TYPE_TTY | INTR_MPSAFE, NULL,
321                             (driver_intr_t *)puc_intr, sc, &sc->sc_icookie);
322                 else
323                         sc->sc_fastintr = 1;
324
325                 if (error) {
326                         device_printf(dev, "could not activate interrupt\n");
327                         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
328                             sc->sc_ires);
329                         sc->sc_ires = NULL;
330                 }
331         }
332         if (sc->sc_ires == NULL) {
333                 /* XXX no interrupt resource. Force polled mode. */
334                 sc->sc_polled = 1;
335         }
336
337         /* Probe and attach our children. */
338         for (idx = 0; idx < sc->sc_nports; idx++) {
339                 port = &sc->sc_port[idx];
340                 if (port->p_dev == NULL)
341                         continue;
342                 error = device_probe_and_attach(port->p_dev);
343                 if (error) {
344                         device_delete_child(dev, port->p_dev);
345                         port->p_dev = NULL;
346                 }
347         }
348
349         /*
350          * If there are no serdev devices, then our interrupt handler
351          * will do nothing. Tear it down.
352          */
353         if (sc->sc_serdevs == 0UL)
354                 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
355
356         return (0);
357
358 fail:
359         for (idx = 0; idx < sc->sc_nports; idx++) {
360                 port = &sc->sc_port[idx];
361                 if (port->p_dev != NULL)
362                         device_delete_child(dev, port->p_dev);
363                 if (port->p_rres != NULL)
364                         rman_release_resource(port->p_rres);
365                 if (port->p_ires != NULL)
366                         rman_release_resource(port->p_ires);
367         }
368         for (idx = 0; idx < PUC_PCI_BARS; idx++) {
369                 bar = &sc->sc_bar[idx];
370                 if (bar->b_res != NULL)
371                         bus_release_resource(sc->sc_dev, bar->b_type,
372                             bar->b_rid, bar->b_res);
373         }
374         rman_fini(&sc->sc_irq);
375         free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
376         rman_fini(&sc->sc_iomem);
377         free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
378         rman_fini(&sc->sc_ioport);
379         free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
380         free(sc->sc_port, M_PUC);
381         return (error);
382 }
383
384 int
385 puc_bfe_detach(device_t dev)
386 {
387         struct puc_bar *bar;
388         struct puc_port *port;
389         struct puc_softc *sc;
390         int error, idx;
391
392         sc = device_get_softc(dev);
393
394         /* Detach our children. */
395         error = 0;
396         for (idx = 0; idx < sc->sc_nports; idx++) {
397                 port = &sc->sc_port[idx];
398                 if (port->p_dev == NULL)
399                         continue;
400                 if (device_detach(port->p_dev) == 0) {
401                         device_delete_child(dev, port->p_dev);
402                         if (port->p_rres != NULL)
403                                 rman_release_resource(port->p_rres);
404                         if (port->p_ires != NULL)
405                                 rman_release_resource(port->p_ires);
406                 } else
407                         error = ENXIO;
408         }
409         if (error)
410                 return (error);
411
412         if (sc->sc_serdevs != 0UL)
413                 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
414         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires);
415
416         for (idx = 0; idx < PUC_PCI_BARS; idx++) {
417                 bar = &sc->sc_bar[idx];
418                 if (bar->b_res != NULL)
419                         bus_release_resource(sc->sc_dev, bar->b_type,
420                             bar->b_rid, bar->b_res);
421         }
422
423         rman_fini(&sc->sc_irq);
424         free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
425         rman_fini(&sc->sc_iomem);
426         free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
427         rman_fini(&sc->sc_ioport);
428         free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
429         free(sc->sc_port, M_PUC);
430         return (0);
431 }
432
433 int
434 puc_bfe_probe(device_t dev, const struct puc_cfg *cfg)
435 {
436         struct puc_softc *sc;
437         intptr_t res;
438         int error;
439
440         sc = device_get_softc(dev);
441         sc->sc_dev = dev;
442         sc->sc_cfg = cfg;
443
444         /* We don't attach to single-port serial cards. */
445         if (cfg->ports == PUC_PORT_1S || cfg->ports == PUC_PORT_1P)
446                 return (EDOOFUS);
447         error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
448         if (error)
449                 return (error);
450         error = puc_config(sc, PUC_CFG_GET_DESC, 0, &res);
451         if (error)
452                 return (error);
453         if (res != 0)
454                 device_set_desc(dev, (const char *)res);
455         return (BUS_PROBE_DEFAULT);
456 }
457
458 struct resource *
459 puc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
460     u_long start, u_long end, u_long count, u_int flags)
461 {
462         struct puc_port *port;
463         struct resource *res;
464         device_t assigned, originator;
465         int error;
466
467         /* Get our immediate child. */
468         originator = child;
469         while (child != NULL && device_get_parent(child) != dev)
470                 child = device_get_parent(child);
471         if (child == NULL)
472                 return (NULL);
473
474         port = device_get_ivars(child);
475         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
476
477         if (rid == NULL || *rid != 0)
478                 return (NULL);
479
480         /* We only support default allocations. */
481         if (start != 0UL || end != ~0UL)
482                 return (NULL);
483
484         if (type == port->p_bar->b_type)
485                 res = port->p_rres;
486         else if (type == SYS_RES_IRQ)
487                 res = port->p_ires;
488         else
489                 return (NULL);
490
491         if (res == NULL)
492                 return (NULL);
493
494         assigned = rman_get_device(res);
495         if (assigned == NULL)   /* Not allocated */
496                 rman_set_device(res, originator);
497         else if (assigned != originator)
498                 return (NULL);
499
500         if (flags & RF_ACTIVE) {
501                 error = rman_activate_resource(res);
502                 if (error) {
503                         if (assigned == NULL)
504                                 rman_set_device(res, NULL);
505                         return (NULL);
506                 }
507         }
508
509         return (res);
510 }
511
512 int
513 puc_bus_release_resource(device_t dev, device_t child, int type, int rid,
514     struct resource *res)
515 {
516         struct puc_port *port;
517         device_t originator;
518
519         /* Get our immediate child. */
520         originator = child;
521         while (child != NULL && device_get_parent(child) != dev)
522                 child = device_get_parent(child);
523         if (child == NULL)
524                 return (EINVAL);
525
526         port = device_get_ivars(child);
527         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
528
529         if (rid != 0 || res == NULL)
530                 return (EINVAL);
531
532         if (type == port->p_bar->b_type) {
533                 if (res != port->p_rres)
534                         return (EINVAL);
535         } else if (type == SYS_RES_IRQ) {
536                 if (res != port->p_ires)
537                         return (EINVAL);
538                 if (port->p_hasintr)
539                         return (EBUSY);
540         } else
541                 return (EINVAL);
542
543         if (rman_get_device(res) != originator)
544                 return (ENXIO);
545         if (rman_get_flags(res) & RF_ACTIVE)
546                 rman_deactivate_resource(res);
547         rman_set_device(res, NULL);
548         return (0);
549 }
550
551 int
552 puc_bus_get_resource(device_t dev, device_t child, int type, int rid,
553     u_long *startp, u_long *countp)
554 {
555         struct puc_port *port;
556         struct resource *res;
557         u_long start;
558
559         /* Get our immediate child. */
560         while (child != NULL && device_get_parent(child) != dev)
561                 child = device_get_parent(child);
562         if (child == NULL)
563                 return (EINVAL);
564
565         port = device_get_ivars(child);
566         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
567
568         if (type == port->p_bar->b_type)
569                 res = port->p_rres;
570         else if (type == SYS_RES_IRQ)
571                 res = port->p_ires;
572         else
573                 return (ENXIO);
574
575         if (rid != 0 || res == NULL)
576                 return (ENXIO);
577
578         start = rman_get_start(res);
579         if (startp != NULL)
580                 *startp = start;
581         if (countp != NULL)
582                 *countp = rman_get_end(res) - start + 1;
583         return (0);
584 }
585
586 int
587 puc_bus_setup_intr(device_t dev, device_t child, struct resource *res,
588     int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep)
589 {
590         struct puc_port *port;
591         struct puc_softc *sc;
592         device_t originator;
593         int i, isrc, serdev;
594
595         sc = device_get_softc(dev);
596
597         /* Get our immediate child. */
598         originator = child;
599         while (child != NULL && device_get_parent(child) != dev)
600                 child = device_get_parent(child);
601         if (child == NULL)
602                 return (EINVAL);
603
604         port = device_get_ivars(child);
605         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
606
607         if (filt == NULL || cookiep == NULL || res != port->p_ires)
608                 return (EINVAL);
609         if (rman_get_device(port->p_ires) != originator)
610                 return (ENXIO);
611
612         /*
613          * Have non-serdev ports handled by the bus implementation. It
614          * supports multiple handlers for a single interrupt as it is,
615          * so we wouldn't add value if we did it ourselves.
616          */
617         serdev = 0;
618         if (port->p_type == PUC_TYPE_SERIAL) {
619                 i = 0, isrc = SER_INT_OVERRUN;
620                 while (i < PUC_ISRCCNT) {
621                         port->p_ihsrc[i] = SERDEV_IHAND(originator, isrc);
622                         if (port->p_ihsrc[i] != NULL)
623                                 serdev = 1;
624                         i++, isrc <<= 1;
625                 }
626         }
627         if (!serdev)
628                 return (BUS_SETUP_INTR(device_get_parent(dev), originator,
629                     sc->sc_ires, flags, filt, ihand, arg, cookiep));
630
631         /* We demand that serdev devices use fast interrupts. */
632         if (filt == NULL)
633                 return (ENXIO);
634
635         sc->sc_serdevs |= 1UL << (port->p_nr - 1);
636
637         port->p_hasintr = 1;
638         port->p_ih = filt;
639         port->p_iharg = arg;
640
641         *cookiep = port;
642         return (0);
643 }
644
645 int
646 puc_bus_teardown_intr(device_t dev, device_t child, struct resource *res,
647     void *cookie)
648 {
649         struct puc_port *port;
650         struct puc_softc *sc;
651         device_t originator;
652         int i;
653
654         sc = device_get_softc(dev);
655
656         /* Get our immediate child. */
657         originator = child;
658         while (child != NULL && device_get_parent(child) != dev)
659                 child = device_get_parent(child);
660         if (child == NULL)
661                 return (EINVAL);
662
663         port = device_get_ivars(child);
664         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
665
666         if (res != port->p_ires)
667                 return (EINVAL);
668         if (rman_get_device(port->p_ires) != originator)
669                 return (ENXIO);
670
671         if (!port->p_hasintr)
672                 return (BUS_TEARDOWN_INTR(device_get_parent(dev), originator,
673                     sc->sc_ires, cookie));
674
675         if (cookie != port)
676                 return (EINVAL);
677
678         port->p_hasintr = 0;
679         port->p_ih = NULL;
680         port->p_iharg = NULL;
681
682         for (i = 0; i < PUC_ISRCCNT; i++)
683                 port->p_ihsrc[i] = NULL;
684
685         return (0);
686 }
687
688 int
689 puc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
690 {
691         struct puc_port *port;
692
693         /* Get our immediate child. */
694         while (child != NULL && device_get_parent(child) != dev)
695                 child = device_get_parent(child);
696         if (child == NULL)
697                 return (EINVAL);
698
699         port = device_get_ivars(child);
700         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
701
702         if (result == NULL)
703                 return (EINVAL);
704
705         switch(index) {
706         case PUC_IVAR_CLOCK:
707                 *result = port->p_rclk;
708                 break;
709         case PUC_IVAR_TYPE:
710                 *result = port->p_type;
711                 break;
712         default:
713                 return (ENOENT);
714         }
715         return (0);
716 }