summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1999-08-08 01:07:03 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1999-08-08 01:07:03 +0000
commitc26ed33114e5e90c2293512caaea133a8f8b66af (patch)
tree0827f9f93966f925efc7d039e961656bd9269f85 /sys/dev/ic
parenta6833536653e21a3adece6249320e89dea0647f3 (diff)
Fill in detach support in the i82365 driver; mostly netbsd, as was the
former pcmcia commit.
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/i82365.c227
-rw-r--r--sys/dev/ic/i82365var.h22
2 files changed, 224 insertions, 25 deletions
diff --git a/sys/dev/ic/i82365.c b/sys/dev/ic/i82365.c
index 159614cbd63..be36072bc36 100644
--- a/sys/dev/ic/i82365.c
+++ b/sys/dev/ic/i82365.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: i82365.c,v 1.8 1999/07/26 05:43:15 deraadt Exp $ */
+/* $OpenBSD: i82365.c,v 1.9 1999/08/08 01:07:02 niklas Exp $ */
/* $NetBSD: i82365.c,v 1.10 1998/06/09 07:36:55 thorpej Exp $ */
/*
@@ -35,7 +35,9 @@
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/extent.h>
+#include <sys/kernel.h>
#include <sys/malloc.h>
+#include <sys/kthread.h>
#include <vm/vm.h>
@@ -89,12 +91,18 @@ int pcic_print __P((void *arg, const char *pnp));
int pcic_intr_socket __P((struct pcic_handle *));
void pcic_attach_card __P((struct pcic_handle *));
-void pcic_detach_card __P((struct pcic_handle *));
+void pcic_detach_card __P((struct pcic_handle *, int));
+void pcic_deactivate_card __P((struct pcic_handle *));
void pcic_chip_do_mem_map __P((struct pcic_handle *, int));
void pcic_chip_do_io_map __P((struct pcic_handle *, int));
-static void pcic_wait_ready __P((struct pcic_handle *));
+void pcic_create_event_thread __P((void *));
+void pcic_event_thread __P((void *));
+
+void pcic_queue_event __P((struct pcic_handle *, int));
+
+void pcic_wait_ready __P((struct pcic_handle *));
struct cfdriver pcic_cd = {
NULL, "pcic", DV_DULL
@@ -209,6 +217,7 @@ pcic_attach(sc)
} else {
sc->handle[0].flags = 0;
}
+ sc->handle[0].laststate = PCIC_LASTSTATE_EMPTY;
DPRINTF((" 0x%02x", reg));
@@ -220,6 +229,7 @@ pcic_attach(sc)
} else {
sc->handle[1].flags = 0;
}
+ sc->handle[1].laststate = PCIC_LASTSTATE_EMPTY;
DPRINTF((" 0x%02x", reg));
@@ -239,6 +249,7 @@ pcic_attach(sc)
} else {
sc->handle[2].flags = 0;
}
+ sc->handle[2].laststate = PCIC_LASTSTATE_EMPTY;
DPRINTF((" 0x%02x", reg));
@@ -251,6 +262,7 @@ pcic_attach(sc)
} else {
sc->handle[3].flags = 0;
}
+ sc->handle[3].laststate = PCIC_LASTSTATE_EMPTY;
DPRINTF((" 0x%02x\n", reg));
} else {
@@ -271,6 +283,7 @@ pcic_attach(sc)
* boot time.
*/
if (sc->handle[i].flags & PCIC_FLAG_SOCKETP) {
+ SIMPLEQ_INIT(&sc->handle[i].events);
pcic_write(&sc->handle[i], PCIC_CSC_INTR, 0);
pcic_read(&sc->handle[i], PCIC_CSC);
}
@@ -341,11 +354,139 @@ pcic_attach_socket(h)
}
void
+pcic_create_event_thread(arg)
+ void *arg;
+{
+ struct pcic_handle *h = arg;
+ const char *cs;
+
+ switch (h->sock) {
+ case C0SA:
+ cs = "0,0";
+ break;
+ case C0SB:
+ cs = "0,1";
+ break;
+ case C1SA:
+ cs = "1,0";
+ break;
+ case C1SB:
+ cs = "1,1";
+ break;
+ default:
+ panic("pcic_create_event_thread: unknown pcic socket");
+ }
+
+ if (kthread_create(pcic_event_thread, h, &h->event_thread,
+ "%s,%s", h->sc->dev.dv_xname, cs)) {
+ printf("%s: unable to create event thread for sock 0x%02x\n",
+ h->sc->dev.dv_xname, h->sock);
+ panic("pcic_create_event_thread");
+ }
+}
+
+void
+pcic_event_thread(arg)
+ void *arg;
+{
+ struct pcic_handle *h = arg;
+ struct pcic_event *pe;
+ int s;
+
+ while (h->shutdown == 0) {
+ s = splhigh();
+ if ((pe = SIMPLEQ_FIRST(&h->events)) == NULL) {
+ splx(s);
+ (void) tsleep(&h->events, PWAIT, "pcicev", 0);
+ continue;
+ } else {
+ splx(s);
+ /* sleep .25s to be enqueued chatterling interrupts */
+ (void) tsleep((caddr_t)pcic_event_thread, PWAIT, "pcicss", hz/4);
+ }
+ s = splhigh();
+ SIMPLEQ_REMOVE_HEAD(&h->events, pe, pe_q);
+ splx(s);
+
+ switch (pe->pe_type) {
+ case PCIC_EVENT_INSERTION:
+ s = splhigh();
+ while (1) {
+ struct pcic_event *pe1, *pe2;
+
+ if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL)
+ break;
+ if (pe1->pe_type != PCIC_EVENT_REMOVAL)
+ break;
+ if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL)
+ break;
+ if (pe2->pe_type == PCIC_EVENT_INSERTION) {
+ SIMPLEQ_REMOVE_HEAD(&h->events, pe1, pe_q);
+ free(pe1, M_TEMP);
+ SIMPLEQ_REMOVE_HEAD(&h->events, pe2, pe_q);
+ free(pe2, M_TEMP);
+ }
+ }
+ splx(s);
+
+ DPRINTF(("%s: insertion event\n", h->sc->dev.dv_xname));
+ pcic_attach_card(h);
+ break;
+
+ case PCIC_EVENT_REMOVAL:
+ s = splhigh();
+ while (1) {
+ struct pcic_event *pe1, *pe2;
+
+ if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL)
+ break;
+ if (pe1->pe_type != PCIC_EVENT_INSERTION)
+ break;
+ if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL)
+ break;
+ if (pe2->pe_type == PCIC_EVENT_REMOVAL) {
+ SIMPLEQ_REMOVE_HEAD(&h->events, pe1, pe_q);
+ free(pe1, M_TEMP);
+ SIMPLEQ_REMOVE_HEAD(&h->events, pe2, pe_q);
+ free(pe2, M_TEMP);
+ }
+ }
+ splx(s);
+
+ DPRINTF(("%s: removal event\n", h->sc->dev.dv_xname));
+ pcic_detach_card(h, DETACH_FORCE);
+ break;
+
+ default:
+ panic("pcic_event_thread: unknown event %d",
+ pe->pe_type);
+ }
+ free(pe, M_TEMP);
+ }
+
+ h->event_thread = NULL;
+
+ /* In case parent is waiting for us to exit. */
+ wakeup(h->sc);
+
+ kthread_exit(0);
+}
+
+void
pcic_init_socket(h)
struct pcic_handle *h;
{
int reg;
+ /*
+ * queue creation of a kernel thread to handle insert/removal events.
+ */
+#ifdef DIAGNOSTIC
+ if (h->event_thread != NULL)
+ panic("pcic_attach_socket: event thread");
+#endif
+ kthread_create_deferred(pcic_create_event_thread, h);
+
/* set up the card to interrupt on card detect */
pcic_write(h, PCIC_CSC_INTR, (h->sc->irq << PCIC_CSC_INTR_IRQ_SHIFT) |
@@ -370,8 +511,11 @@ pcic_init_socket(h)
reg = pcic_read(h, PCIC_IF_STATUS);
if ((reg & PCIC_IF_STATUS_CARDDETECT_MASK) ==
- PCIC_IF_STATUS_CARDDETECT_PRESENT)
+ PCIC_IF_STATUS_CARDDETECT_PRESENT) {
pcic_attach_card(h);
+ h->laststate = PCIC_LASTSTATE_PRESENT;
+ } else
+ h->laststate = PCIC_LASTSTATE_EMPTY;
}
int
@@ -508,18 +652,27 @@ pcic_intr_socket(h)
DPRINTF(("%s: %02x CD %x\n", h->sc->dev.dv_xname, h->sock,
statreg));
- /*
- * XXX This should probably schedule something to happen
- * after the interrupt handler completes
- */
-
if ((statreg & PCIC_IF_STATUS_CARDDETECT_MASK) ==
PCIC_IF_STATUS_CARDDETECT_PRESENT) {
- if (!(h->flags & PCIC_FLAG_CARDP))
- pcic_attach_card(h);
+ if (h->laststate != PCIC_LASTSTATE_PRESENT) {
+ DPRINTF(("%s: enqueing INSERTION event\n",
+ h->sc->dev.dv_xname));
+ pcic_queue_event(h, PCIC_EVENT_INSERTION);
+ }
+ h->laststate = PCIC_LASTSTATE_PRESENT;
} else {
- if (h->flags & PCIC_FLAG_CARDP)
- pcic_detach_card(h);
+ if (h->laststate == PCIC_LASTSTATE_PRESENT) {
+ /* Deactivate the card now. */
+ DPRINTF(("%s: deactivating card\n",
+ h->sc->dev.dv_xname));
+ pcic_deactivate_card(h);
+
+ DPRINTF(("%s: enqueing REMOVAL event\n",
+ h->sc->dev.dv_xname));
+ pcic_queue_event(h, PCIC_EVENT_REMOVAL);
+ }
+ h->laststate = ((statreg & PCIC_IF_STATUS_CARDDETECT_MASK) == 0)
+ ? PCIC_LASTSTATE_EMPTY : PCIC_LASTSTATE_HALF;
}
}
if (cscreg & PCIC_CSC_READY) {
@@ -536,6 +689,25 @@ pcic_intr_socket(h)
}
void
+pcic_queue_event(h, event)
+ struct pcic_handle *h;
+ int event;
+{
+ struct pcic_event *pe;
+ int s;
+
+ pe = malloc(sizeof(*pe), M_TEMP, M_NOWAIT);
+ if (pe == NULL)
+ panic("pcic_queue_event: can't allocate event");
+
+ pe->pe_type = event;
+ s = splhigh();
+ SIMPLEQ_INSERT_TAIL(&h->events, pe, pe_q);
+ splx(s);
+ wakeup(&h->events);
+}
+
+void
pcic_attach_card(h)
struct pcic_handle *h;
{
@@ -550,26 +722,33 @@ pcic_attach_card(h)
}
void
-pcic_detach_card(h)
+pcic_detach_card(h, flags)
struct pcic_handle *h;
+ int flags; /* DETACH_* */
{
- if (!(h->flags & PCIC_FLAG_CARDP))
- panic("pcic_attach_card: already detached");
- h->flags &= ~PCIC_FLAG_CARDP;
+ if (h->flags & PCIC_FLAG_CARDP) {
+ h->flags &= ~PCIC_FLAG_CARDP;
- /* call the MI attach function */
+ /* call the MI detach function */
+ pcmcia_card_detach(h->pcmcia, flags);
+ } else {
+ DPRINTF(("pcic_detach_card: already detached"));
+ }
+}
- pcmcia_card_detach(h->pcmcia);
+void
+pcic_deactivate_card(h)
+ struct pcic_handle *h;
+{
- /* disable card detect resume and configuration reset */
+ /* call the MI deactivate function */
+ pcmcia_card_deactivate(h->pcmcia);
/* power down the socket */
-
pcic_write(h, PCIC_PWRCTL, 0);
- /* reset the card */
-
+ /* reset the socket */
pcic_write(h, PCIC_INTR, 0);
}
@@ -1077,7 +1256,7 @@ pcic_chip_io_unmap(pch, window)
h->ioalloc &= ~(1 << window);
}
-static void
+void
pcic_wait_ready(h)
struct pcic_handle *h;
{
diff --git a/sys/dev/ic/i82365var.h b/sys/dev/ic/i82365var.h
index 952b8ca50e1..81af7b771f2 100644
--- a/sys/dev/ic/i82365var.h
+++ b/sys/dev/ic/i82365var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: i82365var.h,v 1.4 1999/07/26 05:43:15 deraadt Exp $ */
+/* $OpenBSD: i82365var.h,v 1.5 1999/08/08 01:07:02 niklas Exp $ */
/* $NetBSD: i82365var.h,v 1.4 1998/05/23 18:32:29 matt Exp $ */
/*
@@ -37,11 +37,23 @@
#include <dev/ic/i82365reg.h>
+struct proc;
+
+struct pcic_event {
+ SIMPLEQ_ENTRY(pcic_event) pe_q;
+ int pe_type;
+};
+
+/* pe_type */
+#define PCIC_EVENT_INSERTION 0
+#define PCIC_EVENT_REMOVAL 1
+
struct pcic_handle {
struct pcic_softc *sc;
int vendor;
int sock;
int flags;
+ int laststate;
int memalloc;
struct {
bus_addr_t addr;
@@ -57,11 +69,19 @@ struct pcic_handle {
} io[PCIC_IO_WINS];
int ih_irq;
struct device *pcmcia;
+
+ int shutdown;
+ struct proc *event_thread;
+ SIMPLEQ_HEAD(, pcic_event) events;
};
#define PCIC_FLAG_SOCKETP 0x0001
#define PCIC_FLAG_CARDP 0x0002
+#define PCIC_LASTSTATE_PRESENT 0x0002
+#define PCIC_LASTSTATE_HALF 0x0001
+#define PCIC_LASTSTATE_EMPTY 0x0000
+
#define C0SA PCIC_CHIP0_BASE+PCIC_SOCKETA_INDEX
#define C0SB PCIC_CHIP0_BASE+PCIC_SOCKETB_INDEX
#define C1SA PCIC_CHIP1_BASE+PCIC_SOCKETA_INDEX