Implement a kernel thread per PCMCIA socket to handle card insertion and

removal events.
This commit is contained in:
thorpej 1998-11-16 22:41:01 +00:00
parent fade033791
commit fc44652721
2 changed files with 140 additions and 11 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: i82365.c,v 1.13 1998/11/09 07:01:47 msaitoh Exp $ */
/* $NetBSD: i82365.c,v 1.14 1998/11/16 22:41:01 thorpej Exp $ */
#define PCICDEBUG
@ -37,6 +37,7 @@
#include <sys/device.h>
#include <sys/extent.h>
#include <sys/malloc.h>
#include <sys/kthread.h>
#include <vm/vm.h>
@ -84,6 +85,11 @@ void pcic_detach_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));
void pcic_create_event_thread __P((void *));
void pcic_event_thread __P((void *));
void pcic_queue_event __P((struct pcic_handle *, int));
static void pcic_wait_ready __P((struct pcic_handle *));
int
@ -228,6 +234,7 @@ pcic_attach(sc)
/* XXX block interrupts? */
for (i = 0; i < PCIC_NSLOTS; i++) {
SIMPLEQ_INIT(&sc->handle[i].events);
#if 0
/*
* this should work, but w/o it, setting tty flags hangs at
@ -302,6 +309,7 @@ pcic_attach_socket(h)
/* initialize the rest of the handle */
h->shutdown = 0;
h->memalloc = 0;
h->ioalloc = 0;
h->ih_irq = 0;
@ -322,12 +330,97 @@ pcic_attach_socket(h)
pcic_init_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;
}
SIMPLEQ_REMOVE_HEAD(&h->events, pe, pe_q);
splx(s);
switch (pe->pe_type) {
case PCIC_EVENT_INSERTION:
DPRINTF(("%s: insertion event\n", h->sc->dev.dv_xname));
pcic_attach_card(h);
break;
case PCIC_EVENT_REMOVAL:
DPRINTF(("%s: removal event\n", h->sc->dev.dv_xname));
pcic_detach_card(h);
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) |
@ -487,18 +580,20 @@ 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->flags & PCIC_FLAG_CARDP)) {
DPRINTF(("%s: enqueing INSERTION event\n",
h->sc->dev.dv_xname));
pcic_queue_event(h, PCIC_EVENT_INSERTION);
}
} else {
if (h->flags & PCIC_FLAG_CARDP)
pcic_detach_card(h);
if (h->flags & PCIC_FLAG_CARDP) {
/* XXX Should deactivate children NOW. */
DPRINTF(("%s: enqueing REMOVAL event\n",
h->sc->dev.dv_xname));
pcic_queue_event(h, PCIC_EVENT_REMOVAL);
}
}
}
if (cscreg & PCIC_CSC_READY) {
@ -514,6 +609,25 @@ pcic_intr_socket(h)
return (cscreg ? 1 : 0);
}
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;

View File

@ -1,4 +1,4 @@
/* $NetBSD: i82365var.h,v 1.4 1998/05/23 18:32:29 matt Exp $ */
/* $NetBSD: i82365var.h,v 1.5 1998/11/16 22:41:01 thorpej Exp $ */
/*
* Copyright (c) 1997 Marc Horowitz. All rights reserved.
@ -36,6 +36,17 @@
#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;
@ -56,6 +67,10 @@ 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