summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pccard
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2001-08-19 19:16:26 +0000
committerimp <imp@FreeBSD.org>2001-08-19 19:16:26 +0000
commit9860c27835b2daddc07ba4685b62fc3ce53e05fe (patch)
tree7d63c8d39d4561abb802dc7f10bfae6feded7fdf /usr.sbin/pccard
parent12119c5784eeb68c2d9621676dffa23babec9c95 (diff)
downloadFreeBSD-src-9860c27835b2daddc07ba4685b62fc3ce53e05fe.zip
FreeBSD-src-9860c27835b2daddc07ba4685b62fc3ce53e05fe.tar.gz
Fix ISA machines. Also, make it possible for the new pccardd to run
on older kernels correctly. Terminate the loop when we find a suitable irq. Also, only try to select from the pool. Cleaned up the two cases (IRQ picked by the user and ?) into one. MFC upon re approval.
Diffstat (limited to 'usr.sbin/pccard')
-rw-r--r--usr.sbin/pccard/pccardd/cardd.c101
1 files changed, 61 insertions, 40 deletions
diff --git a/usr.sbin/pccard/pccardd/cardd.c b/usr.sbin/pccard/pccardd/cardd.c
index 6b81154..a5b04fd 100644
--- a/usr.sbin/pccard/pccardd/cardd.c
+++ b/usr.sbin/pccard/pccardd/cardd.c
@@ -481,6 +481,7 @@ assign_driver(struct slot *sp, struct card *cp)
struct card_config *conf;
struct pccard_resource res;
int i;
+ int irqmin, irqmax;
for (conf = cp->config; conf; conf = conf->next)
if (conf->inuse == 0 && conf->driver->card == cp &&
@@ -517,52 +518,72 @@ assign_driver(struct slot *sp, struct card *cp)
logmsg("Driver already being used for %s", cp->manuf);
return (NULL);
}
- /* Allocate a free IRQ if none has been specified */
+
+ /*
+ * Allocate a free IRQ if none has been specified. When we're
+ * sharing interrupts (cardbus bridge case), then we'll use what
+ * the kernel tells us to use, reguardless of what the user
+ * configured. Asking the kernel for IRQ 0 is our way of asking
+ * if we should use a shared interrupt.
+ */
res.type = SYS_RES_IRQ;
res.size = 1;
if (conf->irq == 0) {
- res.min = 0;
- res.max = 0;
- if (ioctl(sp->fd, PIOCSRESOURCE, &res) < 0)
- err(1, "ioctl (PIOCSRESOURCE)");
- if (res.resource_addr != ~0ul) {
- conf->irq = res.resource_addr;
- pool_irq[conf->irq] = 0;
- } else {
- for (i = 1; i < 16; i++) {
- if (!use_kern_irq && pool_irq[i]) {
- conf->irq = i;
- pool_irq[i] = 0;
- break;
- }
- res.min = i;
- res.max = i;
- if (ioctl(sp->fd, PIOCSRESOURCE, &res) < 0)
- err(1, "ioctl (PIOCSRESOURCE)");
- if (res.resource_addr == ~0ul)
- continue;
- conf->irq = res.resource_addr;
- pool_irq[conf->irq] = 0;
- }
- }
- if (conf->irq == 0) {
- logmsg("Failed to allocate IRQ for %s\n", cp->manuf);
- return (NULL);
- }
+ irqmin = 1;
+ irqmax = 15;
} else {
- res.min = res.max = conf->irq;
- if (ioctl(sp->fd, PIOCSRESOURCE, &res) < 0)
- err(1, "ioctl (PIOCSRESOURCE)");
- if (res.resource_addr == ~0ul) {
- logmsg("Failed to verify IRQ for %s\n", cp->manuf);
- return (NULL);
- }
- if (res.resource_addr != conf->irq) {
- logmsg("Kernel changed irq from %d to %d for %s\n",
- conf->irq, res.resource_addr, cp->manuf);
+ irqmin = irqmax = conf->irq;
+ conf->irq = 0; /* Make sure we get it. */
+ }
+ res.min = 0;
+ res.max = 0;
+ if (ioctl(sp->fd, PIOCSRESOURCE, &res) < 0)
+ err(1, "ioctl (PIOCSRESOURCE)");
+ if (res.resource_addr != ~0ul) {
+ conf->irq = res.resource_addr;
+ pool_irq[conf->irq] = 0;
+ } else {
+ for (i = irqmin; i <= irqmax; i++) {
+ /*
+ * Skip irqs not in the pool.
+ */
+ if (pool_irq[i] == 0)
+ continue;
+ /*
+ * -I forces us to use the interrupt, so use it.
+ */
+ if (!use_kern_irq) {
+ conf->irq = i;
+ pool_irq[i] = 0;
+ break;
+ }
+ /*
+ * Ask the kernel if we have an free irq.
+ */
+ res.min = i;
+ res.max = i;
+ if (ioctl(sp->fd, PIOCSRESOURCE, &res) < 0)
+ err(1, "ioctl (PIOCSRESOURCE)");
+ if (res.resource_addr == ~0ul)
+ continue;
+ /*
+ * res.resource_addr might be the kernel's
+ * better idea than i, so we have to check to
+ * see if that's in use too. If not, mark it
+ * in use and break out of the loop. I'm not
+ * sure this can happen when IRQ 0 above fails,
+ * but the test is cheap enough.
+ */
+ if (pool_irq[res.resource_addr] == 0)
+ continue;
conf->irq = res.resource_addr;
+ pool_irq[conf->irq] = 0;
+ break;
}
-
+ }
+ if (conf->irq == 0) {
+ logmsg("Failed to allocate IRQ for %s\n", cp->manuf);
+ return (NULL);
}
drvp->card = cp;
drvp->config = conf;
OpenPOWER on IntegriCloud