Rewrite the interrupt handler to use a state machine similar to
that found in the various kernels for the Advent Vega. This also
changes the code to use the new functions introduced in the
previous commits.

Signed-off-by: Julian Andres Klode <[email protected]>
---
 drivers/staging/nvec/nvec.c     |  391 +++++++++++++++++++++++++++------------
 drivers/staging/nvec/nvec.h     |   55 +++---
 drivers/staging/nvec/nvec_kbd.c |    2 +-
 3 files changed, 305 insertions(+), 143 deletions(-)

diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index 005d389..0df3270 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -153,27 +153,71 @@ static void nvec_gpio_set_value(struct nvec_chip *nvec, 
int value)
 void nvec_write_async(struct nvec_chip *nvec, const unsigned char *data,
                        short size)
 {
-       struct nvec_msg *msg = kzalloc(sizeof(struct nvec_msg), GFP_NOWAIT);
+       struct nvec_msg *msg;
+       unsigned long flags;
 
-       msg->data = kzalloc(size, GFP_NOWAIT);
+       msg = nvec_msg_alloc(nvec);
        msg->data[0] = size;
        memcpy(msg->data + 1, data, size);
        msg->size = size + 1;
-       msg->pos = 0;
-       INIT_LIST_HEAD(&msg->node);
 
+       spin_lock_irqsave(&nvec->tx_lock, flags);
        list_add_tail(&msg->node, &nvec->tx_data);
+       spin_unlock_irqrestore(&nvec->tx_lock, flags);
 
-       gpio_set_value(nvec->gpio, 0);
+       queue_work(nvec->wq, &nvec->tx_work);
 }
 EXPORT_SYMBOL(nvec_write_async);
 
+struct nvec_msg *nvec_write_sync(struct nvec_chip *nvec,
+               const unsigned char *data, short size)
+{
+       mutex_lock(&nvec->sync_write_mutex);
+
+       nvec->sync_write_pending = (data[1] << 8) + data[0];
+       nvec_write_async(nvec, data, size);
+
+       dev_dbg(nvec->dev, "nvec_sync_write: 0x%04x\n",
+                                       nvec->sync_write_pending);
+       if (!(wait_for_completion_timeout(&nvec->sync_write,
+                               msecs_to_jiffies(2000)))) {
+               dev_warn(nvec->dev, "timeout waiting for sync write to 
complete\n");
+               mutex_unlock(&nvec->sync_write_mutex);
+               return NULL;
+       }
+
+       dev_dbg(nvec->dev, "nvec_sync_write: pong!\n");
+
+       mutex_unlock(&nvec->sync_write_mutex);
+
+       return nvec->last_sync_msg;
+}
+EXPORT_SYMBOL(nvec_write_sync);
+
+/* TX worker */
 static void nvec_request_master(struct work_struct *work)
 {
        struct nvec_chip *nvec = container_of(work, struct nvec_chip, tx_work);
+       unsigned long flags;
+       struct nvec_msg *msg;
 
-       if (!list_empty(&nvec->tx_data))
-               gpio_set_value(nvec->gpio, 0);
+       spin_lock_irqsave(&nvec->tx_lock, flags);
+       while (!list_empty(&nvec->tx_data)) {
+               msg = list_first_entry(&nvec->tx_data, struct nvec_msg, node);
+               spin_unlock_irqrestore(&nvec->tx_lock, flags);
+               nvec_gpio_set_value(nvec, 0);
+               if (!(wait_for_completion_interruptible_timeout(
+                     &nvec->ec_transfer, msecs_to_jiffies(5000)))) {
+                       dev_warn(nvec->dev, "timeout waiting for ec 
transfer\n");
+                       nvec_gpio_set_value(nvec, 1);
+                       msg->pos = 0;
+               } else {
+                       list_del_init(&msg->node);
+                       nvec_msg_free(nvec, msg);
+               }
+               spin_lock_irqsave(&nvec->tx_lock, flags);
+       }
+       spin_unlock_irqrestore(&nvec->tx_lock, flags);
 }
 
 static int parse_msg(struct nvec_chip *nvec, struct nvec_msg *msg)
@@ -195,143 +239,253 @@ static int parse_msg(struct nvec_chip *nvec, struct 
nvec_msg *msg)
        return 0;
 }
 
-static struct nvec_msg *nvec_write_sync(struct nvec_chip *nvec,
-                                       const unsigned char *data, short size)
-{
-       down(&nvec->sync_write_mutex);
-
-       nvec->sync_write_pending = (data[1] << 8) + data[0];
-       nvec_write_async(nvec, data, size);
-
-       dev_dbg(nvec->dev, "nvec_sync_write: 0x%04x\n",
-               nvec->sync_write_pending);
-       wait_for_completion(&nvec->sync_write);
-       dev_dbg(nvec->dev, "nvec_sync_write: pong!\n");
-
-       up(&nvec->sync_write_mutex);
-
-       return nvec->last_sync_msg;
-}
-
 /* RX worker */
 static void nvec_dispatch(struct work_struct *work)
 {
        struct nvec_chip *nvec = container_of(work, struct nvec_chip, rx_work);
+       unsigned long flags;
        struct nvec_msg *msg;
 
+       spin_lock_irqsave(&nvec->rx_lock, flags);
        while (!list_empty(&nvec->rx_data)) {
                msg = list_first_entry(&nvec->rx_data, struct nvec_msg, node);
                list_del_init(&msg->node);
+               spin_unlock_irqrestore(&nvec->rx_lock, flags);
 
                if (nvec->sync_write_pending ==
-                   (msg->data[2] << 8) + msg->data[0]) {
+                     (msg->data[2] << 8) + msg->data[0]) {
                        dev_dbg(nvec->dev, "sync write completed!\n");
                        nvec->sync_write_pending = 0;
                        nvec->last_sync_msg = msg;
                        complete(&nvec->sync_write);
                } else {
                        parse_msg(nvec, msg);
-                       if ((!msg) || (!msg->data))
-                               dev_warn(nvec->dev,
-                                       "attempt access zero pointer\n");
-                       else {
-                               kfree(msg->data);
-                               kfree(msg);
-                       }
+                       nvec_msg_free(nvec, msg);
                }
+               spin_lock_irqsave(&nvec->rx_lock, flags);
        }
+       spin_unlock_irqrestore(&nvec->rx_lock, flags);
 }
 
-static irqreturn_t nvec_interrupt(int irq, void *dev)
+static void nvec_tx_completed(struct nvec_chip *nvec)
 {
-       unsigned long status;
-       unsigned long received;
-       unsigned char to_send;
-       struct nvec_msg *msg;
-       struct nvec_chip *nvec = (struct nvec_chip *)dev;
-       void __iomem *base = nvec->base;
+       /* We got an END_TRANS, let's skip this, maybe there's an event */
+       if (nvec->tx->pos != nvec->tx->size) {
+               dev_err(nvec->dev, "premature END_TRANS, resending\n");
+               nvec->tx->pos = 0;
+               nvec_gpio_set_value(nvec, 0);
+       } else {
+               nvec->state = 0;
+       }
+}
 
-       status = readl(base + I2C_SL_STATUS);
+static void nvec_rx_completed(struct nvec_chip *nvec)
+{
+       unsigned long flags;
 
-       if (!(status & I2C_SL_IRQ)) {
-               dev_warn(nvec->dev, "nvec Spurious IRQ\n");
-               goto handled;
-       }
-       if (status & END_TRANS && !(status & RCVD)) {
-               nvec->state = NVEC_WAIT;
-               if (nvec->rx->size > 1) {
-                       list_add_tail(&nvec->rx->node, &nvec->rx_data);
-                       schedule_work(&nvec->rx_work);
-               } else {
-                       kfree(nvec->rx->data);
-                       kfree(nvec->rx);
-               }
-               return IRQ_HANDLED;
-       } else if (status & RNW) {
-               if (status & RCVD)
-                       udelay(3);
+       if (nvec->rx->pos != nvec_msg_size(nvec->rx))
+               dev_err(nvec->dev, "RX incomplete: Expected %u bytes, got %u\n",
+                          (uint) nvec_msg_size(nvec->rx),
+                          (uint) nvec->rx->pos);
 
-               if (status & RCVD)
-                       nvec->state = NVEC_WRITE;
+       spin_lock_irqsave(&nvec->rx_lock, flags);
 
-               if (list_empty(&nvec->tx_data)) {
-                       dev_err(nvec->dev, "nvec empty tx - sending no-op\n");
-                       to_send = 0x8a;
-                       nvec_write_async(nvec, "\x07\x02", 2);
-               } else {
-                       msg =
-                           list_first_entry(&nvec->tx_data, struct nvec_msg,
-                                            node);
-                       if (msg->pos < msg->size) {
-                               to_send = msg->data[msg->pos];
-                               msg->pos++;
-                       } else {
-                               dev_err(nvec->dev, "nvec crap! %d\n",
-                                       msg->size);
-                               to_send = 0x01;
-                       }
+       /* add the received data to the work list
+          and move the ring buffer pointer to the next entry */
+       list_add_tail(&nvec->rx->node, &nvec->rx_data);
 
-                       if (msg->pos >= msg->size) {
-                               list_del_init(&msg->node);
-                               kfree(msg->data);
-                               kfree(msg);
-                               schedule_work(&nvec->tx_work);
-                               nvec->state = NVEC_WAIT;
-                       }
-               }
-               writel(to_send, base + I2C_SL_RCVD);
+       spin_unlock_irqrestore(&nvec->rx_lock, flags);
 
-               gpio_set_value(nvec->gpio, 1);
+       nvec->state = 0;
 
-               dev_dbg(nvec->dev, "nvec sent %x\n", to_send);
+       if (!nvec_msg_is_event(nvec->rx))
+               complete(&nvec->ec_transfer);
 
-               goto handled;
+       queue_work(nvec->wq, &nvec->rx_work);
+}
+
+/**
+ * nvec_invalid_flags - Send an error message about invalid flags and jump
+ * @nvec: The nvec device
+ * @status: The status flags
+ * @reset: Whether we shall jump to state 0.
+ */
+static void nvec_invalid_flags(struct nvec_chip *nvec, unsigned int status,
+                              bool reset)
+{
+       dev_err(nvec->dev, "unexpected status flags 0x%02x during state %i\n",
+               status, nvec->state);
+       if (reset)
+               nvec->state = 0;
+}
+
+/**
+ * nvec_tx_set - Set the message to transfer (nvec->tx)
+ */
+static void nvec_tx_set(struct nvec_chip *nvec)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&nvec->tx_lock, flags);
+       if (list_empty(&nvec->tx_data)) {
+               dev_err(nvec->dev, "empty tx - sending no-op\n");
+               memcpy(nvec->tx_scratch.data, "\x02\x07\x02", 3);
+               nvec->tx_scratch.size = 3;
+               nvec->tx_scratch.pos = 0;
+               nvec->tx = &nvec->tx_scratch;
+               list_add_tail(&nvec->tx->node, &nvec->tx_data);
        } else {
-               received = readl(base + I2C_SL_RCVD);
+               nvec->tx = list_first_entry(&nvec->tx_data, struct nvec_msg,
+                                           node);
+               nvec->tx->pos = 0;
+       }
+       spin_unlock_irqrestore(&nvec->tx_lock, flags);
+
+       dev_dbg(nvec->dev, "Sending message of length %u, command 0x%x\n",
+               (uint)nvec->tx->size, nvec->tx->data[1]);
+}
+
+/**
+ * nvec_interrupt - Interrupt handler
+ * @irq: The IRQ
+ * @dev: The nvec device
+ */
+static irqreturn_t nvec_interrupt(int irq, void *dev)
+{
+       unsigned long flags;
+       unsigned long status;
+       unsigned int received = 0;
+       unsigned char to_send = 0xff;
+       const unsigned long irq_mask = I2C_SL_IRQ | END_TRANS | RCVD | RNW;
+       struct nvec_chip *nvec = dev;
+       unsigned int state = nvec->state;
 
+       status = readl(nvec->base + I2C_SL_STATUS);
+
+       /* Filter out some errors */
+       if ((status & irq_mask) == 0 && (status & ~irq_mask) != 0) {
+               dev_err(nvec->dev, "unexpected irq mask %lx\n", status);
+               return IRQ_HANDLED;
+       }
+       if ((status & I2C_SL_IRQ) == 0) {
+               dev_err(nvec->dev, "Spurious IRQ\n");
+               return IRQ_HANDLED;
+       }
+
+       /* The EC did not request a read, so it send us something, read it */
+       if ((status & RNW) == 0) {
                if (status & RCVD) {
-                       writel(0, base + I2C_SL_RCVD);
-                       goto handled;
+                       local_irq_save(flags);
+                       received = readl(nvec->base + I2C_SL_RCVD);
+                       writel(0, nvec->base + I2C_SL_RCVD);
+                       local_irq_restore(flags);
+               } else {
+                       received = readl(nvec->base + I2C_SL_RCVD);
+               }
+       }
+
+       if (status == (I2C_SL_IRQ | RCVD))
+               nvec->state = 0;
+
+       switch (nvec->state) {
+       case 0:         /* Verify that its a transfer start, the rest later */
+               if (status != (I2C_SL_IRQ | RCVD))
+                       nvec_invalid_flags(nvec, status, false);
+               break;
+       case 1:         /* command byte */
+               if (status != I2C_SL_IRQ) {
+                       nvec_invalid_flags(nvec, status, true);
+               } else {
+                       nvec->rx = nvec_msg_alloc(nvec);
+                       nvec->rx->data[0] = received;
+                       nvec->rx->pos = 1;
+                       nvec->state = 2;
                }
+               break;
+       case 2:         /* first byte after command */
+               if (status == (I2C_SL_IRQ | RNW | RCVD)) {
+                       udelay(33);
+                       if (nvec->rx->data[0] != 0x01) {
+                               dev_err(nvec->dev,
+                                       "Read without prior read command\n");
+                               nvec->state = 0;
+                               break;
+                       }
+                       nvec_msg_free(nvec, nvec->rx);
+                       nvec->state = 3;
+                       nvec_tx_set(nvec);
+                       BUG_ON(nvec->tx->size < 1);
+                       to_send = nvec->tx->data[0];
+                       nvec->tx->pos = 1;
+               } else if (status == (I2C_SL_IRQ)) {
+                       BUG_ON(nvec->rx == NULL);
+                       nvec->rx->data[1] = received;
+                       nvec->rx->pos = 2;
+                       nvec->state = 4;
+               } else {
+                       nvec_invalid_flags(nvec, status, true);
+               }
+               break;
+       case 3:         /* EC does a block read, we transmit data */
+               if (status & END_TRANS) {
+                       nvec_tx_completed(nvec);
+               } else if ((status & RNW) == 0 || (status & RCVD)) {
+                       nvec_invalid_flags(nvec, status, true);
+               } else if (nvec->tx && nvec->tx->pos < nvec->tx->size) {
+                       to_send = nvec->tx->data[nvec->tx->pos++];
+               } else {
+                       dev_err(nvec->dev, "tx buffer underflow on %p (%u > 
%u)\n",
+                               nvec->tx,
+                               (uint) (nvec->tx ? nvec->tx->pos : 0),
+                               (uint) (nvec->tx ? nvec->tx->size : 0));
+                       nvec->state = 0;
+               }
+               break;
+       case 4:         /* EC does some write, we read the data */
+               if ((status & (END_TRANS | RNW)) == END_TRANS)
+                       nvec_rx_completed(nvec);
+               else if (status & (RNW | RCVD))
+                       nvec_invalid_flags(nvec, status, true);
+               else if (nvec->rx && nvec->rx->pos < NVEC_MSG_SIZE)
+                       nvec->rx->data[nvec->rx->pos++] = received;
+               else
+                       dev_err(nvec->dev,
+                               "RX buffer overflow on %p: "
+                               "Trying to write byte %u of %u\n",
+                               nvec->rx, nvec->rx->pos, NVEC_MSG_SIZE);
+               break;
+       default:
+               nvec->state = 0;
+       }
 
-               if (nvec->state == NVEC_WAIT) {
-                       nvec->state = NVEC_READ;
-                       msg = kzalloc(sizeof(struct nvec_msg), GFP_NOWAIT);
-                       msg->data = kzalloc(32, GFP_NOWAIT);
-                       INIT_LIST_HEAD(&msg->node);
-                       nvec->rx = msg;
-               } else
-                       msg = nvec->rx;
-
-               BUG_ON(msg->pos > 32);
-
-               msg->data[msg->pos] = received;
-               msg->pos++;
-               msg->size = msg->pos;
-               dev_dbg(nvec->dev, "Got %02lx from Master (pos: %d)!\n",
-                       received, msg->pos);
+       /* If we are told that a new transfer starts, verify it */
+       if ((status & (RCVD | RNW)) == RCVD) {
+               if (received != nvec->i2c_addr)
+                       dev_err(nvec->dev,
+                       "received address 0x%02x, expected 0x%02x\n",
+                       received, nvec->i2c_addr);
+               nvec->state = 1;
        }
-handled:
+
+       /* Send data if requested, but not on end of transmission */
+       if ((status & (RNW | END_TRANS)) == RNW)
+               writel(to_send, nvec->base + I2C_SL_RCVD);
+
+       /* If we have send the first byte */
+       if (status == (I2C_SL_IRQ | RNW | RCVD))
+               nvec_gpio_set_value(nvec, 1);
+
+       dev_dbg(nvec->dev,
+               "Handled: %s 0x%02x, %s 0x%02x in state %u [%s%s%s]\n",
+               (status & RNW) == 0 ? "received" : "R=",
+               received,
+               (status & (RNW | END_TRANS)) ? "sent" : "S=",
+               to_send,
+               state,
+               status & END_TRANS ? " END_TRANS" : "",
+               status & RCVD ? " RCVD" : "",
+               status & RNW ? " RNW" : "");
+
        return IRQ_HANDLED;
 }
 
@@ -430,6 +584,7 @@ static int __devinit tegra_nvec_probe(struct 
platform_device *pdev)
        nvec->base = base;
        nvec->irq = res->start;
        nvec->i2c_clk = i2c_clk;
+       nvec->rx = &nvec->msg_pool[0];
 
        /* Set the gpio to low when we've got something to say */
        err = gpio_request(nvec->gpio, "nvec gpio");
@@ -439,11 +594,15 @@ static int __devinit tegra_nvec_probe(struct 
platform_device *pdev)
        ATOMIC_INIT_NOTIFIER_HEAD(&nvec->notifier_list);
 
        init_completion(&nvec->sync_write);
-       sema_init(&nvec->sync_write_mutex, 1);
-       INIT_LIST_HEAD(&nvec->tx_data);
+       init_completion(&nvec->ec_transfer);
+       mutex_init(&nvec->sync_write_mutex);
+       spin_lock_init(&nvec->tx_lock);
+       spin_lock_init(&nvec->rx_lock);
        INIT_LIST_HEAD(&nvec->rx_data);
+       INIT_LIST_HEAD(&nvec->tx_data);
        INIT_WORK(&nvec->rx_work, nvec_dispatch);
        INIT_WORK(&nvec->tx_work, nvec_request_master);
+       nvec->wq = alloc_workqueue("nvec", WQ_NON_REENTRANT, 2);
 
        err = request_irq(nvec->irq, nvec_interrupt, 0, "nvec", nvec);
        if (err) {
@@ -471,13 +630,14 @@ static int __devinit tegra_nvec_probe(struct 
platform_device *pdev)
 
        /* Get Firmware Version */
        msg = nvec_write_sync(nvec, EC_GET_FIRMWARE_VERSION,
-                             sizeof(EC_GET_FIRMWARE_VERSION));
+               sizeof(EC_GET_FIRMWARE_VERSION));
 
-       dev_warn(nvec->dev, "ec firmware version %02x.%02x.%02x / %02x\n",
-                msg->data[4], msg->data[5], msg->data[6], msg->data[7]);
+       if (msg) {
+               dev_warn(nvec->dev, "ec firmware version %02x.%02x.%02x / 
%02x\n",
+                       msg->data[4], msg->data[5], msg->data[6], msg->data[7]);
 
-       kfree(msg->data);
-       kfree(msg);
+               nvec_msg_free(nvec, msg);
+       }
 
        ret = mfd_add_devices(nvec->dev, -1, nvec_devices,
                              ARRAY_SIZE(nvec_devices), base, 0);
@@ -511,6 +671,7 @@ static int __devexit tegra_nvec_remove(struct 
platform_device *pdev)
        free_irq(nvec->irq, &nvec_interrupt);
        iounmap(nvec->base);
        gpio_free(nvec->gpio);
+       destroy_workqueue(nvec->wq);
        kfree(nvec);
 
        return 0;
diff --git a/drivers/staging/nvec/nvec.h b/drivers/staging/nvec/nvec.h
index 5440802..0a98b92 100644
--- a/drivers/staging/nvec/nvec.h
+++ b/drivers/staging/nvec/nvec.h
@@ -23,39 +23,36 @@
 /* NVEC_POOL_SIZE - Size of the pool in &struct nvec_msg */
 #define NVEC_POOL_SIZE 64
 
-typedef enum {
+/*
+ * NVEC_MSG_SIZE - Maximum size of the data field of &struct nvec_msg.
+ *
+ * A message must store up to a SMBus block operation which consists of
+ * one command byte, one count byte, and up to 32 payload bytes = 34
+ * byte.
+ */
+#define NVEC_MSG_SIZE  34
+
+enum {
        NVEC_2BYTES,
        NVEC_3BYTES,
-       NVEC_VAR_SIZE
-} nvec_size;
-
-typedef enum {
-       NOT_REALLY,
-       YES,
-       NOT_AT_ALL,
-} how_care;
+       NVEC_VAR_SIZE,
+};
 
-typedef enum {
+enum {
        NVEC_SYS = 1,
        NVEC_BAT,
        NVEC_KBD = 5,
        NVEC_PS2,
        NVEC_CNTL,
        NVEC_KB_EVT = 0x80,
-       NVEC_PS2_EVT
-} nvec_event;
-
-typedef enum {
-       NVEC_WAIT,
-       NVEC_READ,
-       NVEC_WRITE
-} nvec_state;
+       NVEC_PS2_EVT,
+};
 
 struct nvec_msg {
-       unsigned char *data;
+       struct list_head node;
+       unsigned char data[NVEC_MSG_SIZE];
        unsigned short size;
        unsigned short pos;
-       struct list_head node;
        atomic_t used;
 };
 
@@ -77,19 +74,27 @@ struct nvec_chip {
        int i2c_addr;
        void __iomem *base;
        struct clk *i2c_clk;
-       nvec_state state;
        struct atomic_notifier_head notifier_list;
        struct list_head rx_data, tx_data;
        struct notifier_block nvec_status_notifier;
        struct work_struct rx_work, tx_work;
-       struct nvec_msg *rx, *tx;
+       struct workqueue_struct *wq;
        struct nvec_msg msg_pool[NVEC_POOL_SIZE];
+       struct nvec_msg *rx;
+
+       struct nvec_msg *tx;
+       struct nvec_msg tx_scratch;
+       struct completion ec_transfer;
+
+       spinlock_t tx_lock, rx_lock;
 
        /* sync write stuff */
-       struct semaphore sync_write_mutex;
+       struct mutex sync_write_mutex;
        struct completion sync_write;
        u16 sync_write_pending;
        struct nvec_msg *last_sync_msg;
+
+       int state;
 };
 
 extern void nvec_write_async(struct nvec_chip *nvec, const unsigned char *data,
@@ -103,10 +108,6 @@ extern int nvec_unregister_notifier(struct device *dev,
                                    struct notifier_block *nb,
                                    unsigned int events);
 
-const char *nvec_send_msg(unsigned char *src, unsigned char *dst_size,
-                         how_care care_resp,
-                         void (*rt_handler) (unsigned char *data));
-
 #define I2C_CNFG                       0x00
 #define I2C_CNFG_PACKET_MODE_EN                (1<<10)
 #define I2C_CNFG_NEW_MASTER_SFM                (1<<11)
diff --git a/drivers/staging/nvec/nvec_kbd.c b/drivers/staging/nvec/nvec_kbd.c
index eaaafac..167eac0 100644
--- a/drivers/staging/nvec/nvec_kbd.c
+++ b/drivers/staging/nvec/nvec_kbd.c
@@ -41,7 +41,7 @@ static int nvec_keys_notifier(struct notifier_block *nb,
        unsigned char *msg = (unsigned char *)data;
 
        if (event_type == NVEC_KB_EVT) {
-               nvec_size _size = (msg[0] & (3 << 5)) >> 5;
+               int _size = (msg[0] & (3 << 5)) >> 5;
 
 /* power on/off button */
                if (_size == NVEC_VAR_SIZE)
-- 
1.7.5.4

_______________________________________________
devel mailing list
[email protected]
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel

Reply via email to