3 = operational card */
int io_base; /* base io address of the socket */
- unsigned int pending_events; /* Pending events on this interface */
-
struct pcmcia_socket socket;
struct pci_dev *dev; /* The PCI device for the socket */
};
/* Interrupt handler functionality */
-static void i82092aa_bh(void *dummy)
-{
- unsigned int events;
- int i;
-
- for (i=0; i < socket_count; i++) {
- events = xchg(&(sockets[i].pending_events),0);
- printk("events = %x \n",events);
- if (events)
- pcmcia_parse_events(&sockets[i].socket, events);
- }
-}
-
-
-static DECLARE_WORK(i82092aa_task, i82092aa_bh, NULL);
-
-
static irqreturn_t i82092aa_interrupt(int irq, void *dev, struct pt_regs *regs)
{
int i;
}
if (events) {
- sockets[i].pending_events |= events;
- schedule_work(&i82092aa_task);
+ pcmcia_parse_events(&sockets[i].socket, events);
}
active |= events;
}
/*====================================================================*/
-static u_int pending_events[8];
-static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED;
-
-static void pcic_bh(void *dummy)
-{
- u_int events;
- int i;
-
- for (i=0; i < sockets; i++) {
- spin_lock_irq(&pending_event_lock);
- events = pending_events[i];
- pending_events[i] = 0;
- spin_unlock_irq(&pending_event_lock);
- /*
- SS_DETECT events need a small delay here. The reason for this is that
- the "is there a card" electronics need time to see the card after the
- "we have a card coming in" electronics have seen it.
- */
- if (events & SS_DETECT)
- mdelay(4);
- if (events)
- pcmcia_parse_events(&socket[i].socket, events);
- }
-}
-
-static DECLARE_WORK(pcic_task, pcic_bh, NULL);
-
-static unsigned long last_detect_jiffies;
-
static irqreturn_t pcic_interrupt(int irq, void *dev,
struct pt_regs *regs)
{
continue;
}
events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
-
-
- /* Several sockets will send multiple "new card detected"
- events in rapid succession. However, the rest of the pcmcia expects
- only one such event. We just ignore these events by having a
- timeout */
-
- if (events) {
- if ((jiffies - last_detect_jiffies)<(HZ/20))
- events = 0;
- last_detect_jiffies = jiffies;
-
- }
-
+
if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
else {
ISA_UNLOCK(i, flags);
DEBUG(2, "i82365: socket %d event 0x%02x\n", i, events);
- if (events) {
- spin_lock(&pending_event_lock);
- pending_events[i] |= events;
- spin_unlock(&pending_event_lock);
- schedule_work(&pcic_task);
- }
+ if (events)
+ pcmcia_parse_events(&socket[i].socket, events);
+
active |= events;
}
if (!active) break;
#include <linux/init.h>
#include <linux/config.h>
#include <linux/cpufreq.h>
-#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
-#include <linux/workqueue.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/notifier.h>
-#include <linux/version.h>
#include <linux/interrupt.h>
+#include <linux/spinlock.h>
#include <asm/hardware.h>
#include <asm/io.h>
return ret;
}
+static spinlock_t status_lock = SPIN_LOCK_UNLOCKED;
-/* sa1100_pcmcia_task_handler()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Processes serviceable socket events using the "eventd" thread context.
- *
- * Event processing (specifically, the invocation of the Card Services event
- * callback) occurs in this thread rather than in the actual interrupt
- * handler due to the use of scheduling operations in the PCMCIA core.
+/* sa1100_check_status()
+ * ^^^^^^^^^^^^^^^^^^^^^
*/
-static void sa1100_pcmcia_task_handler(void *data)
+static void sa1100_check_status(struct sa1100_pcmcia_socket *skt)
{
- struct sa1100_pcmcia_socket *skt = data;
unsigned int events;
DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
do {
unsigned int status;
+ unsigned long flags;
status = sa1100_pcmcia_skt_state(skt);
+ spin_lock_irqsave(&status_lock, flags);
events = (status ^ skt->status) & skt->cs_state.csc_mask;
skt->status = status;
+ spin_unlock_irqrestore(&status_lock, flags);
DEBUG(2, "events: %s%s%s%s%s%s\n",
events == 0 ? "<NONE>" : "",
mod_timer(&skt->poll_timer, jiffies + SA1100_PCMCIA_POLL_PERIOD);
- schedule_work(&skt->work);
+ sa1100_check_status(skt);
}
DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq);
- schedule_work(&skt->work);
+ sa1100_check_status(skt);
return IRQ_HANDLED;
}
skt->socket.owner = ops->owner;
skt->socket.dev.dev = dev;
- INIT_WORK(&skt->work, sa1100_pcmcia_task_handler, skt);
-
init_timer(&skt->poll_timer);
skt->poll_timer.function = sa1100_pcmcia_poll_event;
skt->poll_timer.data = (unsigned long)skt;
unsigned int irq_state;
struct timer_list poll_timer;
- struct work_struct work;
};
struct pcmcia_low_level {
/*====================================================================*/
-static u_int pending_events[2];
-static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED;
-
-static void tcic_bh(void *dummy)
-{
- u_int events;
- int i;
-
- for (i=0; i < sockets; i++) {
- spin_lock_irq(&pending_event_lock);
- events = pending_events[i];
- pending_events[i] = 0;
- spin_unlock_irq(&pending_event_lock);
- if (events)
- pcmcia_parse_events(&socket_table[i].socket, events);
- }
-}
-
-static DECLARE_WORK(tcic_task, tcic_bh, NULL);
-
static irqreturn_t tcic_interrupt(int irq, void *dev, struct pt_regs *regs)
{
int i, quick = 0;
events |= (latch & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
}
if (events) {
- spin_lock(&pending_event_lock);
- pending_events[i] |= events;
- spin_unlock(&pending_event_lock);
- schedule_work(&tcic_task);
+ pcmcia_parse_events(&socket_table[i].socket, events);
}
}
if (state->flags & SS_DEBOUNCED) {
/* The insertion debounce period has ended. Clear any pending insertion events */
- socket->events &= ~SS_DETECT;
state->flags &= ~SS_DEBOUNCED; /* SS_DEBOUNCED is oneshot */
}
yenta_set_power(socket, state);
}
-static void yenta_bh(void *data)
-{
- struct yenta_socket *socket = data;
- unsigned int events;
-
- spin_lock_irq(&socket->event_lock);
- events = socket->events;
- socket->events = 0;
- spin_unlock_irq(&socket->event_lock);
- if (events)
- pcmcia_parse_events(&socket->socket, events);
-}
-
static irqreturn_t yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned int events;
events = yenta_events(socket);
if (events) {
- spin_lock(&socket->event_lock);
- socket->events |= events;
- spin_unlock(&socket->event_lock);
- schedule_work(&socket->tq_task);
+ pcmcia_parse_events(&socket->socket, events);
return IRQ_HANDLED;
}
return IRQ_NONE;
/* prepare struct yenta_socket */
socket->dev = dev;
pci_set_drvdata(dev, socket);
- spin_lock_init(&socket->event_lock);
/*
* Do some basic sanity checking..
/* We must finish initialization here */
- INIT_WORK(&socket->tq_task, yenta_bh, socket);
-
if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->dev.name, socket)) {
/* No IRQ or request_irq failed. Poll */
socket->cb_irq = 0; /* But zero is a valid IRQ number. */
struct pci_dev *dev;
int cb_irq, io_irq;
void *base;
- spinlock_t event_lock;
- unsigned int events;
- struct work_struct tq_task;
struct timer_list poll_timer;
struct pcmcia_socket socket;