#include <linux/types.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
+#include <linux/completion.h>
#include <linux/reboot.h>
#include <linux/mm.h>
#include <linux/slab.h>
#define HAVE_EXPMASK
#endif
-enum req {
- req_readbytes,
- req_reset
-};
-
struct ecard_request {
- enum req req;
+ void (*fn)(struct ecard_request *);
ecard_t *ec;
unsigned int address;
unsigned int length;
unsigned int use_loader;
void *buffer;
+ struct completion *complete;
};
struct expcard_blacklist {
#define POD_INT_ADDR(x) ((volatile unsigned char *)\
((BUS_ADDR((x)) - IO_BASE) + IO_START))
-static inline void ecard_task_reset(struct ecard_request *req)
+static void ecard_task_reset(struct ecard_request *req)
{
struct expansion_card *ec = req->ec;
if (ec->loader)
ecard_loader_reset(POD_INT_ADDR(ec->podaddr), ec->loader);
}
-static void
-ecard_task_readbytes(struct ecard_request *req)
+static void ecard_task_readbytes(struct ecard_request *req)
{
unsigned char *buf = (unsigned char *)req->buffer;
volatile unsigned char *base_addr =
}
-static void ecard_do_request(struct ecard_request *req)
-{
- switch (req->req) {
- case req_readbytes:
- ecard_task_readbytes(req);
- break;
-
- case req_reset:
- ecard_task_reset(req);
- break;
- }
-}
-
-#include <linux/completion.h>
-
-static pid_t ecard_pid;
-static wait_queue_head_t ecard_wait;
+static DECLARE_WAIT_QUEUE_HEAD(ecard_wait);
static struct ecard_request *ecard_req;
-
-static DECLARE_COMPLETION(ecard_completion);
+static DECLARE_MUTEX(ecard_sem);
/*
* Set up the expansion card daemon's page tables.
static int
ecard_task(void * unused)
{
- struct task_struct *tsk = current;
-
daemonize("kecardd");
/*
while (1) {
struct ecard_request *req;
- do {
- req = xchg(&ecard_req, NULL);
-
- if (req == NULL) {
- sigemptyset(&tsk->pending.signal);
- interruptible_sleep_on(&ecard_wait);
- }
- } while (req == NULL);
+ wait_event_interruptible(ecard_wait, ecard_req != NULL);
- ecard_do_request(req);
- complete(&ecard_completion);
+ req = xchg(&ecard_req, NULL);
+ if (req != NULL) {
+ req->fn(req);
+ complete(req->complete);
+ }
}
}
* FIXME: The test here is not sufficient to detect if the
* kcardd is running.
*/
-static void
-ecard_call(struct ecard_request *req)
+static void ecard_call(struct ecard_request *req)
{
- /*
- * Make sure we have a context that is able to sleep.
- */
- if (current == &init_task || in_interrupt())
- BUG();
+ DECLARE_COMPLETION(completion);
- if (ecard_pid <= 0)
- ecard_pid = kernel_thread(ecard_task, NULL, CLONE_KERNEL);
+ req->complete = &completion;
+ down(&ecard_sem);
ecard_req = req;
wake_up(&ecard_wait);
/*
* Now wait for kecardd to run.
*/
- wait_for_completion(&ecard_completion);
+ wait_for_completion(&completion);
+ up(&ecard_sem);
}
/* ======================= Mid-level card control ===================== */
{
struct ecard_request req;
- req.req = req_readbytes;
+ req.fn = ecard_task_readbytes;
req.ec = ec;
req.address = off;
req.length = len;
*/
static int __init ecard_init(void)
{
- int slot, irqhw;
+ int slot, irqhw, ret;
- init_waitqueue_head(&ecard_wait);
+ ret = kernel_thread(ecard_task, NULL, CLONE_KERNEL);
+ if (ret < 0) {
+ printk(KERN_ERR "Ecard: unable to create kernel thread: %d\n",
+ ret);
+ return ret;
+ }
printk("Probing expansion cards\n");
if (drv->shutdown)
drv->shutdown(ec);
ecard_release(ec);
- req.req = req_reset;
+ req.fn = ecard_task_reset;
req.ec = ec;
ecard_call(&req);
}