diff for duplicates of <41FA5556.4000700@acm.org> diff --git a/a/1.txt b/N1/1.txt index 36ada1a..dac8a09 100644 --- a/a/1.txt +++ b/N1/1.txt @@ -25,7 +25,7 @@ I'll post the changes to the i801 driver next. This patch requires the fixes to the completion code that Mike Waychison posted a few days ago -(http://marc.theaimsgroup.com/?l=linux-kernel&m\x110669761400454&w=2). +(http://marc.theaimsgroup.com/?l=linux-kernel&m=110669761400454&w=2). Otherwise the wait_for_completion_interruptible() and wait_for_completion_timeout() are broken. @@ -37,1296 +37,3 @@ current I2C driver requires a task context, but you can't exactly do things at panic time with a task context. -Corey --------------- next part -------------- -Index: linux-2.6.11-rc2/drivers/i2c/i2c-core.c -=================================--- linux-2.6.11-rc2.orig/drivers/i2c/i2c-core.c 2005-01-26 15:59:53.000000000 -0600 -+++ linux-2.6.11-rc2/drivers/i2c/i2c-core.c 2005-01-28 08:54:00.000000000 -0600 -@@ -30,8 +30,14 @@ - #include <linux/init.h> - #include <linux/idr.h> - #include <linux/seq_file.h> -+#include <linux/completion.h> - #include <asm/uaccess.h> - -+static int i2c_stop_timer(struct i2c_adapter * adap); -+static void i2c_start_timer(struct i2c_adapter * adap, -+ struct i2c_op_q_entry * entry); -+ -+#define USEC_PER_JIFFIE (1000000 / HZ) - - static LIST_HEAD(adapters); - static LIST_HEAD(drivers); -@@ -134,11 +140,26 @@ - } - - adap->nr = id & MAX_ID_MASK; -+ spin_lock_init(&adap->q_lock); -+ INIT_LIST_HEAD(&adap->q); - init_MUTEX(&adap->bus_lock); - init_MUTEX(&adap->clist_lock); - list_add_tail(&adap->list,&adapters); - INIT_LIST_HEAD(&adap->clients); - -+ adap->timer = kmalloc(sizeof(*adap->timer), GFP_KERNEL); -+ if (!adap->timer) { -+ res = -ENOMEM; -+ goto out_unlock; -+ } -+ -+ init_timer(&adap->timer->timer); -+ spin_lock_init(&adap->timer->lock); -+ adap->timer->deleted = 0; -+ adap->timer->running = 0; -+ adap->timer->next_call_time = 0; -+ adap->timer->adapter = adap; -+ - /* Add the adapter to the driver core. - * If the parent pointer is not set up, - * we add this adapter to the host bus. -@@ -181,6 +202,7 @@ - struct i2c_driver *driver; - struct i2c_client *client; - int res = 0; -+ unsigned long flags; - - down(&core_lists); - -@@ -233,6 +255,17 @@ - device_unregister(&adap->dev); - list_del(&adap->list); - -+ /* Stop the timer and free its memory */ -+ spin_lock_irqsave(&adap->timer->lock, flags); -+ if (i2c_stop_timer(adap)) { -+ spin_unlock_irqrestore(&adap->timer->lock, flags); -+ kfree(adap->timer); -+ } else { -+ adap->timer->deleted = 1; -+ spin_unlock_irqrestore(&adap->timer->lock, flags); -+ } -+ adap->timer = NULL; -+ - /* wait for sysfs to drop all references */ - wait_for_completion(&adap->dev_released); - wait_for_completion(&adap->class_dev_released); -@@ -583,15 +616,283 @@ - * ---------------------------------------------------- - */ - --int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num) -+/* Must be called with the q_lock held. */ -+static void i2c_start_entry(struct i2c_adapter * adap, -+ struct i2c_op_q_entry * entry) -+{ -+ entry->started = 1; -+ switch (entry->xfer_type) { -+ case I2C_OP_I2C: -+ adap->algo->master_start(adap, entry); -+ break; -+ case I2C_OP_SMBUS: -+ adap->algo->smbus_start(adap, entry); -+ break; -+ default: -+ entry->result = -EINVAL; -+ i2c_op_done(adap, entry); -+ } -+ -+ if (!entry->completed && entry->use_timer) -+ i2c_start_timer(adap, entry); -+} -+ -+/* Must be called with q lock held. */ -+static void i2c_entry_inc(struct i2c_adapter * adapter, -+ struct i2c_op_q_entry * entry) - { -- int ret; -+ atomic_inc(&entry->usecount); -+} -+ -+/* Get the first entry off the head of the queue and lock it there. -+ The entry is guaranteed to remain first in the list and the handler -+ not be called until i2c_entry_put() is called. */ -+static struct i2c_op_q_entry *_i2c_entry_get(struct i2c_adapter * adap) -+{ -+ struct i2c_op_q_entry * entry = NULL; - -- if (adap->algo->master_xfer) { -- dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num); -+ if (!list_empty(&adap->q)) { -+ struct list_head * link = adap->q.next; -+ entry = list_entry(link, struct i2c_op_q_entry, link); -+ if (entry->completed) -+ entry = NULL; -+ else -+ i2c_entry_inc(adap, entry); -+ } -+ pr_debug("_i2c_entry_get %p %p\n", adap, entry); -+ return entry; -+} -+ -+struct i2c_op_q_entry *i2c_entry_get(struct i2c_adapter * adap) -+{ -+ unsigned long flags; -+ struct i2c_op_q_entry * entry; -+ -+ spin_lock_irqsave(&adap->q_lock, flags); -+ entry = _i2c_entry_get(adap); -+ spin_unlock_irqrestore(&adap->q_lock, flags); -+ return entry; -+} -+ -+void i2c_entry_put(struct i2c_adapter * adap, -+ struct i2c_op_q_entry * entry) -+{ -+ unsigned long flags; -+ struct i2c_op_q_entry * new_entry = NULL; -+ -+ restart: -+ pr_debug("i2c_put %p %p\n", adap, entry); -+ if (atomic_dec_and_test(&entry->usecount)) { -+ spin_lock_irqsave(&adap->q_lock, flags); -+ list_del(&entry->link); -+ -+ /* Get the next entry to start. */ -+ new_entry = _i2c_entry_get(adap); -+ spin_unlock_irqrestore(&adap->q_lock, flags); -+ -+ entry->handler(entry); -+ -+ -+ if (new_entry) { -+ i2c_start_entry(adap, new_entry); -+ if (new_entry->start) -+ complete(new_entry->start); -+ /* Do tail recursion ourself. */ -+ entry = new_entry; -+ goto restart; -+ } -+ } -+} -+ -+static void i2c_handle_timer(unsigned long data); -+ -+static void i2c_start_timer(struct i2c_adapter * adap, -+ struct i2c_op_q_entry * entry) -+{ -+ unsigned int wait_jiffies; -+ struct i2c_timer *t = adap->timer; -+ unsigned long flags; -+ -+ wait_jiffies = ((entry->call_again_us + USEC_PER_JIFFIE - 1) -+ / USEC_PER_JIFFIE); -+ if (wait_jiffies = 0) -+ wait_jiffies = 1; -+ /* This won't be polled from the user code, so -+ start a timer to poll it. */ -+ spin_lock_irqsave(&t->lock, flags); -+ if (! t->running) { -+ t->timer.expires = jiffies + wait_jiffies; -+ t->timer.data = (unsigned long) adap; -+ t->timer.function = i2c_handle_timer; -+ t->running = 1; -+ t->next_call_time = wait_jiffies * USEC_PER_JIFFIE; -+ add_timer(&t->timer); -+ t->sequence = adap->timer_sequence; -+ } -+ spin_unlock_irqrestore(&t->lock, flags); -+} -+ -+/* Returns true if the timer is stopped (or was not running), false if -+ not. Must be called with the timer lock held. */ -+static int i2c_stop_timer(struct i2c_adapter * adap) -+{ -+ return (!adap->timer->running || del_timer(&adap->timer->timer)); -+} -+ -+static void i2c_handle_timer(unsigned long data) -+{ -+ struct i2c_timer * t = (void *) data; -+ struct i2c_adapter * adap; -+ unsigned long flags; -+ struct i2c_op_q_entry * entry; -+ unsigned int sequence_match; -+ -+ spin_lock_irqsave(&t->lock, flags); -+ if (t->deleted) { -+ spin_unlock_irqrestore(&t->lock, flags); -+ kfree(t); -+ return; -+ } -+ -+ adap = t->adapter; -+ t->running = 0; -+ sequence_match = adap->timer_sequence = t->sequence; -+ spin_unlock_irqrestore(&t->lock, flags); -+ -+ entry = i2c_entry_get(adap); -+ pr_debug("i2c_handle_timer: %p %p\n", adap, entry); -+ if (!entry) -+ return; -+ -+ if (sequence_match) { -+ /* This is the one we expected, call the poll routine. */ -+ adap->algo->poll(adap, entry, t->next_call_time); -+ -+ if (!entry->completed) -+ i2c_start_timer(adap, entry); -+ } else if (entry->use_timer) -+ /* We raced in timer deletion, just restart the -+ timer if necessary. */ -+ i2c_start_timer(adap, entry); -+ -+ i2c_entry_put(adap, entry); -+} -+ -+void i2c_op_done(struct i2c_adapter *adap, struct i2c_op_q_entry *e) -+{ -+ unsigned long flags; -+ int did_complete = 0; -+ -+ pr_debug("i2c_op_done: %p %p\n", adap, e); -+ spin_lock_irqsave(&adap->q_lock, flags); -+ if (! e->completed) { -+ e->completed = 1; -+ did_complete = 1; -+ } -+ spin_unlock_irqrestore(&adap->q_lock, flags); -+ -+ if (did_complete) { -+ if (e->use_timer) { -+ struct i2c_timer *t = adap->timer; -+ spin_lock_irqsave(&t->lock, flags); -+ if (!i2c_stop_timer(adap)) -+ /* If we are unable to stop the timer, that -+ means the timer has gone off but has not -+ yet run the first part of the handler call. -+ Increment the sequence so the timer handler -+ can detect this. */ -+ adap->timer_sequence++; -+ spin_unlock_irqrestore(&t->lock, flags); -+ } -+ if (e->complete) -+ e->complete(adap, e); -+ } -+ -+ i2c_entry_put(adap, e); -+} -+ -+static void i2c_wait_complete(struct i2c_op_q_entry * entry) -+{ -+ struct completion *done = entry->handler_data; -+ pr_debug("i2c_wait_complete %p\n", entry); -+ complete(done); -+} -+ -+static void i2c_perform_op_wait(struct i2c_adapter * adap, -+ struct i2c_op_q_entry * entry) -+{ -+ struct completion done; -+ unsigned long flags; -+ struct i2c_algorithm *algo = adap->algo; -+ -+ pr_debug("i2c_perform_op_wait %p %p\n", adap, entry); -+ init_completion(&done); -+ entry->start = NULL; -+ entry->handler = i2c_wait_complete; -+ entry->handler_data = &done; -+ entry->started = 0; -+ entry->completed = 0; -+ entry->result = 0; -+ entry->use_timer = 0; /* We poll it directly. */ -+ entry->data = NULL; -+ atomic_set(&entry->usecount, 1); -+ spin_lock_irqsave(&adap->q_lock, flags); -+ list_add_tail(&entry->link, &adap->q); -+ if (adap->q.next = &entry->link) { -+ /* Added to the list head, start it */ -+ spin_unlock_irqrestore(&adap->q_lock, flags); -+ i2c_start_entry(adap, entry); -+ } else { -+ struct completion start; -+ init_completion(&start); -+ entry->start = &start; -+ spin_unlock_irqrestore(&adap->q_lock, flags); -+ -+ wait_for_completion_interruptible(&start); -+ -+ spin_lock_irqsave(&adap->q_lock, flags); -+ if (!entry->started) { -+ /* Operation was interrupted. There -+ is a race, we can't use the -+ wait_for_completion return code. */ -+ entry->result = -ERESTARTSYS; -+ entry->completed = 1; -+ list_del(&entry->link); -+ } -+ spin_unlock_irqrestore(&adap->q_lock, flags); -+ } -+ -+ /* Once the operation is started, we will not -+ interrupt it. */ -+ while (!entry->completed) { -+ unsigned int timeout = entry->call_again_us; -+ timeout += (USEC_PER_JIFFIE - 1); -+ timeout /= USEC_PER_JIFFIE; -+ if (timeout = 0) -+ timeout = 1; -+ wait_for_completion_timeout(&done, timeout); -+ if (entry->completed) -+ break; -+ algo->poll(adap, entry, timeout * USEC_PER_JIFFIE); -+ } -+} -+ -+static int i2c_transfer_entry(struct i2c_adapter * adap, -+ struct i2c_op_q_entry * entry) -+{ -+ entry->xfer_type = I2C_OP_I2C; -+ entry->complete = NULL; -+ if (adap->algo->master_start) { -+ i2c_perform_op_wait(adap, entry); -+ return entry->result; -+ } else if (adap->algo->master_xfer) { -+ int ret; -+ dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", -+ entry->i2c.num); - - down(&adap->bus_lock); -- ret = adap->algo->master_xfer(adap,msgs,num); -+ ret = adap->algo->master_xfer(adap, entry->i2c.msgs, -+ entry->i2c.num); - up(&adap->bus_lock); - - return ret; -@@ -601,33 +902,45 @@ - } - } - -+int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num) -+{ -+ struct i2c_op_q_entry *entry; -+ int rv; -+ -+ entry = kmalloc(sizeof(*entry), GFP_KERNEL); -+ if (!entry) -+ return -ENOMEM; -+ -+ entry->i2c.msgs = msgs; -+ entry->i2c.num = num; -+ -+ rv = i2c_transfer_entry(adap, entry); -+ kfree(entry); -+ return rv; -+} -+ - int i2c_master_send(struct i2c_client *client,const char *buf ,int count) - { - int ret; - struct i2c_adapter *adap=client->adapter; - struct i2c_msg msg; - -- if (client->adapter->algo->master_xfer) { -- msg.addr = client->addr; -- msg.flags = client->flags & I2C_M_TEN; -- msg.len = count; -- msg.buf = (char *)buf; -- -- dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n", -- count); -+ msg.addr = client->addr; -+ msg.flags = client->flags & I2C_M_TEN; -+ msg.len = count; -+ msg.buf = (char *)buf; - -- down(&adap->bus_lock); -- ret = adap->algo->master_xfer(adap,&msg,1); -- up(&adap->bus_lock); -+ dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n", -+ count); - -- /* if everything went ok (i.e. 1 msg transmitted), return #bytes -- * transmitted, else error code. -- */ -- return (ret = 1 )? count : ret; -- } else { -- dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); -- return -ENOSYS; -- } -+ ret = i2c_transfer(adap, &msg, 1); -+ if (ret < 0) -+ return ret; -+ -+ /* if everything went ok (i.e. 1 msg transmitted), return #bytes -+ * transmitted, else error code. -+ */ -+ return (ret = 1 )? count : ret; - } - - int i2c_master_recv(struct i2c_client *client, char *buf ,int count) -@@ -635,31 +948,27 @@ - struct i2c_adapter *adap=client->adapter; - struct i2c_msg msg; - int ret; -- if (client->adapter->algo->master_xfer) { -- msg.addr = client->addr; -- msg.flags = client->flags & I2C_M_TEN; -- msg.flags |= I2C_M_RD; -- msg.len = count; -- msg.buf = buf; - -- dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n", -- count); -- -- down(&adap->bus_lock); -- ret = adap->algo->master_xfer(adap,&msg,1); -- up(&adap->bus_lock); -+ msg.addr = client->addr; -+ msg.flags = client->flags & I2C_M_TEN; -+ msg.flags |= I2C_M_RD; -+ msg.len = count; -+ msg.buf = buf; -+ -+ dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n", -+ count); - -- dev_dbg(&client->adapter->dev, "master_recv: return:%d (count:%d, addr:0x%02x)\n", -- ret, count, client->addr); -+ ret = i2c_transfer(adap, &msg, 1); -+ if (ret < 0) -+ return ret; -+ -+ dev_dbg(&client->adapter->dev, "master_recv: return:%d (count:%d, addr:0x%02x)\n", -+ ret, count, client->addr); - -- /* if everything went ok (i.e. 1 msg transmitted), return #bytes -- * transmitted, else error code. -- */ -- return (ret = 1 )? count : ret; -- } else { -- dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); -- return -ENOSYS; -- } -+ /* if everything went ok (i.e. 1 msg transmitted), return #bytes -+ * transmitted, else error code. -+ */ -+ return (ret = 1 )? count : ret; - } - - -@@ -1037,7 +1346,8 @@ - } - - /* Returns the number of read bytes */ --s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values) -+s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, -+ u8 *values) - { - union i2c_smbus_data data; - int i; -@@ -1052,184 +1362,333 @@ - } - } - --/* Simulate a SMBus command using the i2c protocol -- No checking of parameters is done! */ --static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, -- unsigned short flags, -- char read_write, u8 command, int size, -- union i2c_smbus_data * data) --{ -- /* So we need to generate a series of msgs. In the case of writing, we -- need to use only one message; when reading, we need two. We initialize -- most things with sane defaults, to keep the code below somewhat -- simpler. */ -- unsigned char msgbuf0[34]; -- unsigned char msgbuf1[34]; -- int num = read_write = I2C_SMBUS_READ?2:1; -- struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, -- { addr, flags | I2C_M_RD, 0, msgbuf1 } -- }; -+ -+static void i2c_smbus_complete_entry(struct i2c_adapter * adap, -+ struct i2c_op_q_entry * entry) -+{ -+ if (entry->result < 0) -+ return; -+ -+ if(entry->result >= 0 && entry->swpec && -+ entry->smbus.size != I2C_SMBUS_QUICK && -+ entry->smbus.size != I2C_SMBUS_I2C_BLOCK_DATA && -+ (entry->smbus.read_write = I2C_SMBUS_READ || -+ entry->smbus.size = I2C_SMBUS_PROC_CALL_PEC || -+ entry->smbus.size = I2C_SMBUS_BLOCK_PROC_CALL_PEC)) { -+ if(i2c_smbus_check_pec(entry->smbus.addr, -+ entry->smbus.command, -+ entry->smbus.size, -+ entry->partial, -+ entry->smbus.data)) -+ entry->result = -EINVAL; -+ } -+} -+ -+static void i2c_smbus_format_entry(struct i2c_adapter * adap, -+ struct i2c_op_q_entry * entry) -+{ -+ entry->swpec = 0; -+ entry->partial = 0; -+ entry->smbus.flags &= I2C_M_TEN | I2C_CLIENT_PEC; -+ if((entry->smbus.flags & I2C_CLIENT_PEC) && -+ !(i2c_check_functionality(adap, I2C_FUNC_SMBUS_HWPEC_CALC))) { -+ entry->swpec = 1; -+ if(entry->smbus.read_write = I2C_SMBUS_READ && -+ entry->smbus.size = I2C_SMBUS_BLOCK_DATA) -+ entry->smbus.size = I2C_SMBUS_BLOCK_DATA_PEC; -+ else if(entry->smbus.size = I2C_SMBUS_PROC_CALL) -+ entry->smbus.size = I2C_SMBUS_PROC_CALL_PEC; -+ else if(entry->smbus.size = I2C_SMBUS_BLOCK_PROC_CALL) { -+ unsigned char *data = entry->smbus.data->block; -+ i2c_smbus_add_pec(entry->smbus.addr, -+ entry->smbus.command, -+ I2C_SMBUS_BLOCK_DATA, -+ entry->smbus.data); -+ entry->partial = data[data[0] + 1]; -+ entry->smbus.size = I2C_SMBUS_BLOCK_PROC_CALL_PEC; -+ } else if(entry->smbus.read_write = I2C_SMBUS_WRITE && -+ entry->smbus.size != I2C_SMBUS_QUICK && -+ entry->smbus.size != I2C_SMBUS_I2C_BLOCK_DATA) -+ entry->smbus.size + i2c_smbus_add_pec(entry->smbus.addr, -+ entry->smbus.command, -+ entry->smbus.size, -+ entry->smbus.data); -+ } -+ -+ entry->complete = i2c_smbus_complete_entry; -+} -+ -+static void i2c_smbus_emu_complete(struct i2c_adapter * adap, -+ struct i2c_op_q_entry * entry) -+{ -+ unsigned char *msgbuf0 = entry->i2c.msgs[0].buf; -+ unsigned char *msgbuf1 = entry->i2c.msgs[1].buf; - int i; - -- msgbuf0[0] = command; -- switch(size) { -+ if (entry->smbus.read_write != I2C_SMBUS_READ) -+ return; -+ -+ switch(entry->smbus.size) { -+ case I2C_SMBUS_BYTE: -+ entry->smbus.data->byte = msgbuf0[0]; -+ break; -+ case I2C_SMBUS_BYTE_DATA: -+ entry->smbus.data->byte = msgbuf1[0]; -+ break; -+ case I2C_SMBUS_WORD_DATA: -+ case I2C_SMBUS_PROC_CALL: -+ entry->smbus.data->word = msgbuf1[0]|(msgbuf1[1] << 8); -+ break; -+ case I2C_SMBUS_I2C_BLOCK_DATA: -+ /* fixed at 32 for now */ -+ entry->smbus.data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX; -+ for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++) -+ entry->smbus.data->block[i+1] = msgbuf1[i]; -+ break; -+ } -+ -+ entry->xfer_type = I2C_OP_SMBUS; -+ i2c_smbus_complete_entry(adap, entry); -+} -+ -+static int i2c_smbus_emu_format(struct i2c_adapter *adap, -+ struct i2c_op_q_entry * entry) -+{ -+ /* So we need to generate a series of msgs. In the case of -+ writing, we need to use only one message; when reading, we -+ need two. We initialize most things with sane defaults, to -+ keep the code below somewhat simpler. */ -+ unsigned char *msgbuf0 = entry->msgbuf0; -+ unsigned char *msgbuf1 = entry->msgbuf1; -+ int num = entry->smbus.read_write = I2C_SMBUS_READ?2:1; -+ struct i2c_msg *msg = entry->msg; -+ int i; -+ -+ entry->i2c.msgs = msg; -+ entry->i2c.msgs[0].buf = msgbuf0; -+ entry->i2c.msgs[1].buf = msgbuf1; -+ -+ msg[0].addr = entry->smbus.addr; -+ msg[0].flags = entry->smbus.flags; -+ msg[0].len = 1; -+ msg[1].addr = entry->smbus.addr; -+ msg[1].flags = entry->smbus.flags | I2C_M_RD; -+ msg[1].len = 1; -+ -+ msgbuf0[0] = entry->smbus.command; -+ switch(entry->smbus.size) { - case I2C_SMBUS_QUICK: - msg[0].len = 0; - /* Special case: The read/write field is used as data */ -- msg[0].flags = flags | (read_write=I2C_SMBUS_READ)?I2C_M_RD:0; -+ msg[0].flags = (entry->smbus.flags | -+ ((entry->smbus.read_write=I2C_SMBUS_READ) -+ ? I2C_M_RD : 0)); - num = 1; - break; - case I2C_SMBUS_BYTE: -- if (read_write = I2C_SMBUS_READ) { -+ if (entry->smbus.read_write = I2C_SMBUS_READ) { - /* Special case: only a read! */ -- msg[0].flags = I2C_M_RD | flags; -+ msg[0].flags = I2C_M_RD | entry->smbus.flags; - num = 1; - } - break; - case I2C_SMBUS_BYTE_DATA: -- if (read_write = I2C_SMBUS_READ) -+ if (entry->smbus.read_write = I2C_SMBUS_READ) - msg[1].len = 1; - else { - msg[0].len = 2; -- msgbuf0[1] = data->byte; -+ msgbuf0[1] = entry->smbus.data->byte; - } - break; - case I2C_SMBUS_WORD_DATA: -- if (read_write = I2C_SMBUS_READ) -+ if (entry->smbus.read_write = I2C_SMBUS_READ) - msg[1].len = 2; - else { - msg[0].len=3; -- msgbuf0[1] = data->word & 0xff; -- msgbuf0[2] = (data->word >> 8) & 0xff; -+ msgbuf0[1] = entry->smbus.data->word & 0xff; -+ msgbuf0[2] = (entry->smbus.data->word >> 8) & 0xff; - } - break; - case I2C_SMBUS_PROC_CALL: - num = 2; /* Special case */ -- read_write = I2C_SMBUS_READ; -+ entry->smbus.read_write = I2C_SMBUS_READ; - msg[0].len = 3; - msg[1].len = 2; -- msgbuf0[1] = data->word & 0xff; -- msgbuf0[2] = (data->word >> 8) & 0xff; -+ msgbuf0[1] = entry->smbus.data->word & 0xff; -+ msgbuf0[2] = (entry->smbus.data->word >> 8) & 0xff; - break; - case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_BLOCK_DATA_PEC: -- if (read_write = I2C_SMBUS_READ) { -- dev_err(&adapter->dev, "Block read not supported " -+ if (entry->smbus.read_write = I2C_SMBUS_READ) { -+ dev_err(&adap->dev, "Block read not supported " - "under I2C emulation!\n"); - return -1; - } else { -- msg[0].len = data->block[0] + 2; -+ msg[0].len = entry->smbus.data->block[0] + 2; - if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { -- dev_err(&adapter->dev, "smbus_access called with " -+ dev_err(&adap->dev, -+ "smbus_access called with " - "invalid block write size (%d)\n", -- data->block[0]); -+ entry->smbus.data->block[0]); - return -1; - } -- if(size = I2C_SMBUS_BLOCK_DATA_PEC) -+ if(entry->smbus.size = I2C_SMBUS_BLOCK_DATA_PEC) - (msg[0].len)++; - for (i = 1; i <= msg[0].len; i++) -- msgbuf0[i] = data->block[i-1]; -+ msgbuf0[i] = entry->smbus.data->block[i-1]; - } - break; - case I2C_SMBUS_BLOCK_PROC_CALL: - case I2C_SMBUS_BLOCK_PROC_CALL_PEC: -- dev_dbg(&adapter->dev, "Block process call not supported " -+ dev_dbg(&adap->dev, "Block process call not supported " - "under I2C emulation!\n"); - return -1; - case I2C_SMBUS_I2C_BLOCK_DATA: -- if (read_write = I2C_SMBUS_READ) { -+ if (entry->smbus.read_write = I2C_SMBUS_READ) { - msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX; - } else { -- msg[0].len = data->block[0] + 1; -+ msg[0].len = entry->smbus.data->block[0] + 1; - if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) { -- dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with " -+ dev_err(&adap->dev, -+ "i2c_smbus_xfer_emulated called with " - "invalid block write size (%d)\n", -- data->block[0]); -+ entry->smbus.data->block[0]); - return -1; - } -- for (i = 1; i <= data->block[0]; i++) -- msgbuf0[i] = data->block[i]; -+ for (i = 1; i <= entry->smbus.data->block[0]; i++) -+ msgbuf0[i] = entry->smbus.data->block[i]; - } - break; - default: -- dev_err(&adapter->dev, "smbus_access called with invalid size (%d)\n", -- size); -+ dev_err(&adap->dev, -+ "smbus_access called with invalid size (%d)\n", -+ entry->smbus.size); - return -1; - } - -- if (i2c_transfer(adapter, msg, num) < 0) -- return -1; -- -- if (read_write = I2C_SMBUS_READ) -- switch(size) { -- case I2C_SMBUS_BYTE: -- data->byte = msgbuf0[0]; -- break; -- case I2C_SMBUS_BYTE_DATA: -- data->byte = msgbuf1[0]; -- break; -- case I2C_SMBUS_WORD_DATA: -- case I2C_SMBUS_PROC_CALL: -- data->word = msgbuf1[0] | (msgbuf1[1] << 8); -- break; -- case I2C_SMBUS_I2C_BLOCK_DATA: -- /* fixed at 32 for now */ -- data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX; -- for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++) -- data->block[i+1] = msgbuf1[i]; -- break; -- } -+ entry->xfer_type = I2C_OP_I2C; -+ entry->i2c.msgs = msg; -+ entry->i2c.num = num; -+ entry->complete = i2c_smbus_emu_complete; - return 0; - } - -+/* Simulate a SMBus command using the i2c protocol -+ No checking of parameters is done! */ -+static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adap, -+ struct i2c_op_q_entry * entry) -+ -+{ -+ if (i2c_smbus_emu_format(adap, entry)) -+ return -EINVAL; -+ -+ if (i2c_transfer_entry(adap, entry) < 0) -+ return -EINVAL; - --s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, -+ return entry->result; -+} -+ -+s32 i2c_smbus_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, - char read_write, u8 command, int size, - union i2c_smbus_data * data) - { -- s32 res; -- int swpec = 0; -- u8 partial = 0; -- -- flags &= I2C_M_TEN | I2C_CLIENT_PEC; -- if((flags & I2C_CLIENT_PEC) && -- !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) { -- swpec = 1; -- if(read_write = I2C_SMBUS_READ && -- size = I2C_SMBUS_BLOCK_DATA) -- size = I2C_SMBUS_BLOCK_DATA_PEC; -- else if(size = I2C_SMBUS_PROC_CALL) -- size = I2C_SMBUS_PROC_CALL_PEC; -- else if(size = I2C_SMBUS_BLOCK_PROC_CALL) { -- i2c_smbus_add_pec(addr, command, -- I2C_SMBUS_BLOCK_DATA, data); -- partial = data->block[data->block[0] + 1]; -- size = I2C_SMBUS_BLOCK_PROC_CALL_PEC; -- } else if(read_write = I2C_SMBUS_WRITE && -- size != I2C_SMBUS_QUICK && -- size != I2C_SMBUS_I2C_BLOCK_DATA) -- size = i2c_smbus_add_pec(addr, command, size, data); -- } -- -- if (adapter->algo->smbus_xfer) { -- down(&adapter->bus_lock); -- res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, -- command,size,data); -- up(&adapter->bus_lock); -- } else -- res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, -- command,size,data); -- -- if(res >= 0 && swpec && -- size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA && -- (read_write = I2C_SMBUS_READ || size = I2C_SMBUS_PROC_CALL_PEC || -- size = I2C_SMBUS_BLOCK_PROC_CALL_PEC)) { -- if(i2c_smbus_check_pec(addr, command, size, partial, data)) -- return -1; -+ struct i2c_op_q_entry *entry; -+ struct i2c_algorithm *algo = adap->algo; -+ int result; -+ -+ -+ entry = kmalloc(sizeof(*entry), GFP_KERNEL); -+ if (!entry) -+ return -ENOMEM; -+ -+ entry->xfer_type = I2C_OP_SMBUS; -+ entry->smbus.addr = addr; -+ entry->smbus.flags = flags; -+ entry->smbus.read_write = read_write; -+ entry->smbus.command = command; -+ entry->smbus.size = size; -+ entry->smbus.data = data; -+ -+ i2c_smbus_format_entry(adap, entry); -+ -+ if (algo->smbus_start) { -+ i2c_perform_op_wait(adap, entry); -+ } else if (algo->smbus_xfer) { -+ down(&adap->bus_lock); -+ entry->result = adap->algo->smbus_xfer(adap, -+ entry->smbus.addr, -+ entry->smbus.flags, -+ entry->smbus.read_write, -+ entry->smbus.command, -+ entry->smbus.size, -+ entry->smbus.data); -+ up(&adap->bus_lock); -+ } else { -+ i2c_smbus_xfer_emulated(adap, entry); - } -- return res; -+ -+ result = entry->result; -+ kfree(entry); -+ return result; - } - -+int i2c_non_blocking_capable(struct i2c_adapter *adap) -+{ -+ return adap->algo->poll != NULL; -+} -+ -+void i2c_poll(struct i2c_client *client, -+ unsigned int us_since_last_call) -+{ -+ struct i2c_adapter *adap = client->adapter; -+ struct i2c_op_q_entry *entry; -+ -+ entry = i2c_entry_get(adap); -+ if (!entry) -+ return; -+ adap->algo->poll(adap, entry, us_since_last_call); -+ i2c_entry_put(adap, entry); -+} -+ -+int i2c_non_blocking_op(struct i2c_client *client, -+ struct i2c_op_q_entry *entry) -+{ -+ unsigned long flags; -+ struct i2c_adapter *adap = client->adapter; -+ -+ if (!i2c_non_blocking_capable(adap)) -+ return -ENOSYS; -+ -+ entry->smbus.addr = client->addr; -+ entry->smbus.flags = client->flags; -+ -+ if (entry->xfer_type = I2C_OP_SMBUS) { -+ i2c_smbus_format_entry(adap, entry); -+ if (!adap->algo->smbus_start) { -+ if (i2c_smbus_emu_format(adap, entry)) -+ return -EINVAL; -+ } -+ } -+ -+ entry->start = NULL; -+ entry->started = 0; -+ entry->completed = 0; -+ entry->result = 0; -+ entry->use_timer = 1; /* Let the timer code poll it. */ -+ entry->data = NULL; -+ atomic_set(&entry->usecount, 1); -+ -+ spin_lock_irqsave(&adap->q_lock, flags); -+ list_add_tail(&entry->link, &adap->q); -+ if (adap->q.next = &entry->link) { -+ /* Added to the list head, start it */ -+ spin_unlock_irqrestore(&adap->q_lock, flags); -+ i2c_start_entry(adap, entry); -+ } else -+ spin_unlock_irqrestore(&adap->q_lock, flags); -+ return 0; -+} - - /* You should always define `functionality'; the 'else' is just for - backward compatibility. */ -@@ -1258,6 +1717,7 @@ - EXPORT_SYMBOL(i2c_clients_command); - EXPORT_SYMBOL(i2c_check_addr); - -+EXPORT_SYMBOL(i2c_op_done); - EXPORT_SYMBOL(i2c_master_send); - EXPORT_SYMBOL(i2c_master_recv); - EXPORT_SYMBOL(i2c_control); -@@ -1278,6 +1738,10 @@ - EXPORT_SYMBOL(i2c_smbus_write_block_data); - EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); - -+EXPORT_SYMBOL(i2c_non_blocking_capable); -+EXPORT_SYMBOL(i2c_poll); -+EXPORT_SYMBOL(i2c_non_blocking_op); -+ - EXPORT_SYMBOL(i2c_get_functionality); - EXPORT_SYMBOL(i2c_check_functionality); - -Index: linux-2.6.11-rc2/include/linux/i2c.h -=================================--- linux-2.6.11-rc2.orig/include/linux/i2c.h 2005-01-26 15:59:53.000000000 -0600 -+++ linux-2.6.11-rc2/include/linux/i2c.h 2005-01-28 08:53:31.000000000 -0600 -@@ -32,7 +32,11 @@ - #include <linux/types.h> - #include <linux/i2c-id.h> - #include <linux/device.h> /* for struct device */ -+#include <linux/list.h> -+#include <linux/spinlock.h> -+#include <linux/timer.h> - #include <asm/semaphore.h> -+#include <asm/atomic.h> - - /* --- General options ------------------------------------------------ */ - -@@ -43,6 +47,7 @@ - struct i2c_driver; - struct i2c_client_address_data; - union i2c_smbus_data; -+struct i2c_op_q_entry; - - /* - * The master routines are the ones normally used to transmit data to devices -@@ -55,7 +60,7 @@ - - /* Transfer num messages. - */ --extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],int num); -+extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msg,int num); - - /* - * Some adapter types (i.e. PCF 8584 based ones) may support slave behaviuor. -@@ -95,6 +100,25 @@ - extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, - u8 command, u8 *values); - -+/* Non-blocking interface. The user should fill out the public -+ portions of the entry structure. All data in the entry structure -+ should be guaranteed to be available until the handler callback is -+ called with the entry. */ -+typedef void (*i2c_op_done_cb)(struct i2c_op_q_entry *entry); -+ -+extern int i2c_non_blocking_op(struct i2c_client *client, -+ struct i2c_op_q_entry *entry); -+ -+/* Can the adapter do non-blocking operations? */ -+extern int i2c_non_blocking_capable(struct i2c_adapter *adap); -+ -+/* Poll the i2c interface. This should only be called in a situation -+ where scheduling and interrupts are off. You should put the amount -+ of microseconds between calls in us_since_last_call. */ -+extern void i2c_poll(struct i2c_client *client, -+ unsigned int us_since_last_call); -+ -+ - /* - * A driver is capable of handling one or more physical devices present on - * I2C adapters. This information is used to inform the driver of adapter -@@ -181,6 +205,33 @@ - } - - /* -+ * About locking and the non-blocking interface. -+ * -+ * The poll operations are called single-threaded (along with the -+ * xxx_start operations), so if the driver is only polled then there -+ * is no need to do any locking. If you are using interrupts, then -+ * the timer operations and interrupts can race and you need to lock -+ * appropriately. -+ * -+ * i2c_op_done() can be called multiple times on the same entry (as -+ * long as each one has a get operation). This handles poll and -+ * interrupt races calling i2c_op_done(). It will do the right thing. -+ */ -+ -+/* Called from an non-blocking interface to get the current working -+ entry. Returns NULL if there is none. This is primarily for -+ interrupt handlers to determine what they should be working on. -+ Note that if you call i2c_entry_get() and get a non-null entry, you -+ must call i2c_entry_put() on it. */ -+struct i2c_op_q_entry *i2c_entry_get(struct i2c_adapter * adap); -+void i2c_entry_put(struct i2c_adapter * adap, -+ struct i2c_op_q_entry * entry); -+ -+/* Called from an non-blocking interface to report that an operation -+ has completed. Can be called from interrupt context. */ -+void i2c_op_done(struct i2c_adapter *adap, struct i2c_op_q_entry *entry); -+ -+/* - * The following structs are for those who like to implement new bus drivers: - * i2c_algorithm is the interface to a class of hardware solutions which can - * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584 -@@ -190,15 +241,40 @@ - char name[32]; /* textual description */ - unsigned int id; - -- /* If an adapter algorithm can't to I2C-level access, set master_xfer -+ /* If an adapter algorithm can't do I2C-level access, set master_xfer - to NULL. If an adapter algorithm can do SMBus access, set - smbus_xfer. If set to NULL, the SMBus protocol is simulated - using common I2C messages */ -- int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg msgs[], -- int num); -- int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, -- unsigned short flags, char read_write, -- u8 command, int size, union i2c_smbus_data * data); -+ int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs, -+ int num); -+ int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr, -+ unsigned short flags, char read_write, -+ u8 command, int size, union i2c_smbus_data * data); -+ -+ /* These are like the previous calls, but they will only start -+ the operation. The poll call will be called periodically -+ to drive the operation of the bus. Each of these calls -+ should set the result on an error, and set the timeout as -+ necessary. Note that even interrupt driven drivers need to -+ poll so they can time out operations. When the operation -+ is complete, these should call i2c_op_done(). Note that -+ all the data structures passed in are guaranteed to be kept -+ around until the operation completes. These may be called -+ from interrupt context. If the start operation fails, this -+ should set the result and call i2c_op_done(). */ -+ void (*master_start)(struct i2c_adapter *adap, -+ struct i2c_op_q_entry *entry); -+ void (*smbus_start)(struct i2c_adapter *adap, -+ struct i2c_op_q_entry *entry); -+ /* us_since_last_poll is the amount of time since the last -+ time poll was called. Note that this may be *less* than the -+ time you requested, so always use this number and don't -+ assume it's the one you gave it. This time is approximate -+ and is only guaranteed to be >= the time since the last -+ poll. The value may be zero. */ -+ void (*poll)(struct i2c_adapter *adap, -+ struct i2c_op_q_entry *entry, -+ unsigned int us_since_last_poll); - - /* --- these optional/future use for some adapter types.*/ - int (*slave_send)(struct i2c_adapter *,char*,int); -@@ -212,6 +288,21 @@ - }; - - /* -+ * The timer has it's own separately allocated data structure because -+ * it needs to be able to exist even if the adapter is deleted (due to -+ * timer cancellation races). -+ */ -+struct i2c_timer { -+ spinlock_t lock; -+ int deleted; -+ struct timer_list timer; -+ int running; -+ unsigned int next_call_time; -+ struct i2c_adapter *adapter; -+ unsigned int sequence; -+}; -+ -+/* - * i2c_adapter is the structure used to identify a physical i2c bus along - * with the access algorithms necessary to access it. - */ -@@ -228,8 +319,15 @@ - int (*client_unregister)(struct i2c_client *); - - /* data fields that are valid for all devices */ -+ struct list_head q; -+ spinlock_t q_lock; -+ - struct semaphore bus_lock; -- struct semaphore clist_lock; -+ -+ /* Used to time non-blocking operations. The sequence is used -+ to handle race conditions in the timer handler. */ -+ struct i2c_timer *timer; -+ unsigned int timer_sequence; - - int timeout; - int retries; -@@ -242,9 +340,14 @@ - #endif /* def CONFIG_PROC_FS */ - - int nr; -+ -+ struct semaphore clist_lock; - struct list_head clients; -+ - struct list_head list; -+ - char name[I2C_NAME_SIZE]; -+ - struct completion dev_released; - struct completion class_dev_released; - }; -@@ -395,6 +498,90 @@ - __u8 *buf; /* pointer to msg data */ - }; - -+/* -+ * Hold a queue of I2C operations to perform, and used to pass data -+ * around. -+ */ -+#define I2C_OP_I2C 0 -+#define I2C_OP_SMBUS 1 -+struct i2c_op_q_entry { -+ /* The result will be set to the result of the operation when -+ it completes. */ -+ s32 result; -+ -+ /**************************************************************/ -+ /* Public interface. The user should set these up (and the -+ proper structure below). */ -+ int xfer_type; -+ -+ /* Handler may be called from interrupt context, so be -+ careful. */ -+ i2c_op_done_cb handler; -+ void *handler_data; -+ -+ /* Note that this is not a union because an smbus operation -+ may be converted into an i2c operation (thus both -+ structures will be used). The data in these may be changd -+ by the driver. */ -+ struct { -+ struct i2c_msg *msgs; -+ int num; -+ } i2c; -+ struct { -+ /* Addr and flags are filled in by the non-blocking -+ send routine that takes a client. */ -+ u16 addr; -+ unsigned short flags; -+ -+ char read_write; -+ u8 command; -+ -+ /* Note that the size is *not* the length of the data. -+ It is the transaction type, like I2C_SMBUS_QUICK -+ and the ones after that below. If this is a block -+ transaction, the length of the rest of the data is -+ in the first byte of the data, for both transmit -+ and receive. */ -+ int size; -+ union i2c_smbus_data *data; -+ } smbus; -+ -+ /**************************************************************/ -+ /* For use by the bus interface. The bus interface sets the -+ timeout in microseconds until the next poll operation. -+ This *must* be set in the start operation. The time_left -+ and data can be used for anything the bus interface likes. -+ data will be set to NULL before being started so the bus -+ interface can use that to tell if it has been set up -+ yet. */ -+ unsigned int call_again_us; -+ long time_left; -+ void *data; -+ -+ /**************************************************************/ -+ /* Internals */ -+ struct list_head link; -+ struct completion *start; -+ unsigned int started : 1; -+ unsigned int completed : 1; -+ unsigned int use_timer : 1; -+ u8 swpec; -+ u8 partial; -+ void (*complete)(struct i2c_adapter *adap, -+ struct i2c_op_q_entry *entry); -+ -+ /* It's wierd, but we use a usecount to track if an q entry is -+ in use and when it should be reported back to the user. */ -+ atomic_t usecount; -+ -+ /* These are here for SMBus emulation over I2C. I don't like -+ them taking this much room in the data structure, but they -+ need to be available in this case. */ -+ unsigned char msgbuf0[34]; -+ unsigned char msgbuf1[34]; -+ struct i2c_msg msg[2]; -+}; -+ - /* To determine what functionality is present */ - - #define I2C_FUNC_I2C 0x00000001 -@@ -423,22 +610,22 @@ - #define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC 0x40000000 /* SMBus 2.0 */ - #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */ - --#define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \ -- I2C_FUNC_SMBUS_WRITE_BYTE --#define I2C_FUNC_SMBUS_BYTE_DATA I2C_FUNC_SMBUS_READ_BYTE_DATA | \ -- I2C_FUNC_SMBUS_WRITE_BYTE_DATA --#define I2C_FUNC_SMBUS_WORD_DATA I2C_FUNC_SMBUS_READ_WORD_DATA | \ -- I2C_FUNC_SMBUS_WRITE_WORD_DATA --#define I2C_FUNC_SMBUS_BLOCK_DATA I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ -- I2C_FUNC_SMBUS_WRITE_BLOCK_DATA --#define I2C_FUNC_SMBUS_I2C_BLOCK I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ -- I2C_FUNC_SMBUS_WRITE_I2C_BLOCK --#define I2C_FUNC_SMBUS_I2C_BLOCK_2 I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \ -- I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 --#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \ -- I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC --#define I2C_FUNC_SMBUS_WORD_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \ -- I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC -+#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ -+ I2C_FUNC_SMBUS_WRITE_BYTE) -+#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \ -+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA) -+#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \ -+ I2C_FUNC_SMBUS_WRITE_WORD_DATA) -+#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ -+ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) -+#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ -+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) -+#define I2C_FUNC_SMBUS_I2C_BLOCK_2 (I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \ -+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2) -+#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC (I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \ -+ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC) -+#define I2C_FUNC_SMBUS_WORD_DATA_PEC (I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \ -+ I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC) - - #define I2C_FUNC_SMBUS_READ_BYTE_PEC I2C_FUNC_SMBUS_READ_BYTE_DATA - #define I2C_FUNC_SMBUS_WRITE_BYTE_PEC I2C_FUNC_SMBUS_WRITE_BYTE_DATA -@@ -447,14 +634,14 @@ - #define I2C_FUNC_SMBUS_BYTE_PEC I2C_FUNC_SMBUS_BYTE_DATA - #define I2C_FUNC_SMBUS_BYTE_DATA_PEC I2C_FUNC_SMBUS_WORD_DATA - --#define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \ -- I2C_FUNC_SMBUS_BYTE | \ -- I2C_FUNC_SMBUS_BYTE_DATA | \ -- I2C_FUNC_SMBUS_WORD_DATA | \ -- I2C_FUNC_SMBUS_PROC_CALL | \ -- I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ -- I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \ -- I2C_FUNC_SMBUS_I2C_BLOCK -+#define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | \ -+ I2C_FUNC_SMBUS_BYTE | \ -+ I2C_FUNC_SMBUS_BYTE_DATA | \ -+ I2C_FUNC_SMBUS_WORD_DATA | \ -+ I2C_FUNC_SMBUS_PROC_CALL | \ -+ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ -+ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \ -+ I2C_FUNC_SMBUS_I2C_BLOCK) - - /* - * Data for SMBus Messages diff --git a/N1/2.hdr b/N1/2.hdr new file mode 100644 index 0000000..6fed701 --- /dev/null +++ b/N1/2.hdr @@ -0,0 +1,5 @@ +Content-Type: text/plain; + name="i2c_async.diff" +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; + filename="i2c_async.diff" diff --git a/N1/2.txt b/N1/2.txt new file mode 100644 index 0000000..99db0d8 --- /dev/null +++ b/N1/2.txt @@ -0,0 +1,1295 @@ +Index: linux-2.6.11-rc2/drivers/i2c/i2c-core.c +=================================================================== +--- linux-2.6.11-rc2.orig/drivers/i2c/i2c-core.c 2005-01-26 15:59:53.000000000 -0600 ++++ linux-2.6.11-rc2/drivers/i2c/i2c-core.c 2005-01-28 08:54:00.000000000 -0600 +@@ -30,8 +30,14 @@ + #include <linux/init.h> + #include <linux/idr.h> + #include <linux/seq_file.h> ++#include <linux/completion.h> + #include <asm/uaccess.h> + ++static int i2c_stop_timer(struct i2c_adapter * adap); ++static void i2c_start_timer(struct i2c_adapter * adap, ++ struct i2c_op_q_entry * entry); ++ ++#define USEC_PER_JIFFIE (1000000 / HZ) + + static LIST_HEAD(adapters); + static LIST_HEAD(drivers); +@@ -134,11 +140,26 @@ + } + + adap->nr = id & MAX_ID_MASK; ++ spin_lock_init(&adap->q_lock); ++ INIT_LIST_HEAD(&adap->q); + init_MUTEX(&adap->bus_lock); + init_MUTEX(&adap->clist_lock); + list_add_tail(&adap->list,&adapters); + INIT_LIST_HEAD(&adap->clients); + ++ adap->timer = kmalloc(sizeof(*adap->timer), GFP_KERNEL); ++ if (!adap->timer) { ++ res = -ENOMEM; ++ goto out_unlock; ++ } ++ ++ init_timer(&adap->timer->timer); ++ spin_lock_init(&adap->timer->lock); ++ adap->timer->deleted = 0; ++ adap->timer->running = 0; ++ adap->timer->next_call_time = 0; ++ adap->timer->adapter = adap; ++ + /* Add the adapter to the driver core. + * If the parent pointer is not set up, + * we add this adapter to the host bus. +@@ -181,6 +202,7 @@ + struct i2c_driver *driver; + struct i2c_client *client; + int res = 0; ++ unsigned long flags; + + down(&core_lists); + +@@ -233,6 +255,17 @@ + device_unregister(&adap->dev); + list_del(&adap->list); + ++ /* Stop the timer and free its memory */ ++ spin_lock_irqsave(&adap->timer->lock, flags); ++ if (i2c_stop_timer(adap)) { ++ spin_unlock_irqrestore(&adap->timer->lock, flags); ++ kfree(adap->timer); ++ } else { ++ adap->timer->deleted = 1; ++ spin_unlock_irqrestore(&adap->timer->lock, flags); ++ } ++ adap->timer = NULL; ++ + /* wait for sysfs to drop all references */ + wait_for_completion(&adap->dev_released); + wait_for_completion(&adap->class_dev_released); +@@ -583,15 +616,283 @@ + * ---------------------------------------------------- + */ + +-int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num) ++/* Must be called with the q_lock held. */ ++static void i2c_start_entry(struct i2c_adapter * adap, ++ struct i2c_op_q_entry * entry) ++{ ++ entry->started = 1; ++ switch (entry->xfer_type) { ++ case I2C_OP_I2C: ++ adap->algo->master_start(adap, entry); ++ break; ++ case I2C_OP_SMBUS: ++ adap->algo->smbus_start(adap, entry); ++ break; ++ default: ++ entry->result = -EINVAL; ++ i2c_op_done(adap, entry); ++ } ++ ++ if (!entry->completed && entry->use_timer) ++ i2c_start_timer(adap, entry); ++} ++ ++/* Must be called with q lock held. */ ++static void i2c_entry_inc(struct i2c_adapter * adapter, ++ struct i2c_op_q_entry * entry) + { +- int ret; ++ atomic_inc(&entry->usecount); ++} ++ ++/* Get the first entry off the head of the queue and lock it there. ++ The entry is guaranteed to remain first in the list and the handler ++ not be called until i2c_entry_put() is called. */ ++static struct i2c_op_q_entry *_i2c_entry_get(struct i2c_adapter * adap) ++{ ++ struct i2c_op_q_entry * entry = NULL; + +- if (adap->algo->master_xfer) { +- dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num); ++ if (!list_empty(&adap->q)) { ++ struct list_head * link = adap->q.next; ++ entry = list_entry(link, struct i2c_op_q_entry, link); ++ if (entry->completed) ++ entry = NULL; ++ else ++ i2c_entry_inc(adap, entry); ++ } ++ pr_debug("_i2c_entry_get %p %p\n", adap, entry); ++ return entry; ++} ++ ++struct i2c_op_q_entry *i2c_entry_get(struct i2c_adapter * adap) ++{ ++ unsigned long flags; ++ struct i2c_op_q_entry * entry; ++ ++ spin_lock_irqsave(&adap->q_lock, flags); ++ entry = _i2c_entry_get(adap); ++ spin_unlock_irqrestore(&adap->q_lock, flags); ++ return entry; ++} ++ ++void i2c_entry_put(struct i2c_adapter * adap, ++ struct i2c_op_q_entry * entry) ++{ ++ unsigned long flags; ++ struct i2c_op_q_entry * new_entry = NULL; ++ ++ restart: ++ pr_debug("i2c_put %p %p\n", adap, entry); ++ if (atomic_dec_and_test(&entry->usecount)) { ++ spin_lock_irqsave(&adap->q_lock, flags); ++ list_del(&entry->link); ++ ++ /* Get the next entry to start. */ ++ new_entry = _i2c_entry_get(adap); ++ spin_unlock_irqrestore(&adap->q_lock, flags); ++ ++ entry->handler(entry); ++ ++ ++ if (new_entry) { ++ i2c_start_entry(adap, new_entry); ++ if (new_entry->start) ++ complete(new_entry->start); ++ /* Do tail recursion ourself. */ ++ entry = new_entry; ++ goto restart; ++ } ++ } ++} ++ ++static void i2c_handle_timer(unsigned long data); ++ ++static void i2c_start_timer(struct i2c_adapter * adap, ++ struct i2c_op_q_entry * entry) ++{ ++ unsigned int wait_jiffies; ++ struct i2c_timer *t = adap->timer; ++ unsigned long flags; ++ ++ wait_jiffies = ((entry->call_again_us + USEC_PER_JIFFIE - 1) ++ / USEC_PER_JIFFIE); ++ if (wait_jiffies == 0) ++ wait_jiffies = 1; ++ /* This won't be polled from the user code, so ++ start a timer to poll it. */ ++ spin_lock_irqsave(&t->lock, flags); ++ if (! t->running) { ++ t->timer.expires = jiffies + wait_jiffies; ++ t->timer.data = (unsigned long) adap; ++ t->timer.function = i2c_handle_timer; ++ t->running = 1; ++ t->next_call_time = wait_jiffies * USEC_PER_JIFFIE; ++ add_timer(&t->timer); ++ t->sequence = adap->timer_sequence; ++ } ++ spin_unlock_irqrestore(&t->lock, flags); ++} ++ ++/* Returns true if the timer is stopped (or was not running), false if ++ not. Must be called with the timer lock held. */ ++static int i2c_stop_timer(struct i2c_adapter * adap) ++{ ++ return (!adap->timer->running || del_timer(&adap->timer->timer)); ++} ++ ++static void i2c_handle_timer(unsigned long data) ++{ ++ struct i2c_timer * t = (void *) data; ++ struct i2c_adapter * adap; ++ unsigned long flags; ++ struct i2c_op_q_entry * entry; ++ unsigned int sequence_match; ++ ++ spin_lock_irqsave(&t->lock, flags); ++ if (t->deleted) { ++ spin_unlock_irqrestore(&t->lock, flags); ++ kfree(t); ++ return; ++ } ++ ++ adap = t->adapter; ++ t->running = 0; ++ sequence_match = adap->timer_sequence == t->sequence; ++ spin_unlock_irqrestore(&t->lock, flags); ++ ++ entry = i2c_entry_get(adap); ++ pr_debug("i2c_handle_timer: %p %p\n", adap, entry); ++ if (!entry) ++ return; ++ ++ if (sequence_match) { ++ /* This is the one we expected, call the poll routine. */ ++ adap->algo->poll(adap, entry, t->next_call_time); ++ ++ if (!entry->completed) ++ i2c_start_timer(adap, entry); ++ } else if (entry->use_timer) ++ /* We raced in timer deletion, just restart the ++ timer if necessary. */ ++ i2c_start_timer(adap, entry); ++ ++ i2c_entry_put(adap, entry); ++} ++ ++void i2c_op_done(struct i2c_adapter *adap, struct i2c_op_q_entry *e) ++{ ++ unsigned long flags; ++ int did_complete = 0; ++ ++ pr_debug("i2c_op_done: %p %p\n", adap, e); ++ spin_lock_irqsave(&adap->q_lock, flags); ++ if (! e->completed) { ++ e->completed = 1; ++ did_complete = 1; ++ } ++ spin_unlock_irqrestore(&adap->q_lock, flags); ++ ++ if (did_complete) { ++ if (e->use_timer) { ++ struct i2c_timer *t = adap->timer; ++ spin_lock_irqsave(&t->lock, flags); ++ if (!i2c_stop_timer(adap)) ++ /* If we are unable to stop the timer, that ++ means the timer has gone off but has not ++ yet run the first part of the handler call. ++ Increment the sequence so the timer handler ++ can detect this. */ ++ adap->timer_sequence++; ++ spin_unlock_irqrestore(&t->lock, flags); ++ } ++ if (e->complete) ++ e->complete(adap, e); ++ } ++ ++ i2c_entry_put(adap, e); ++} ++ ++static void i2c_wait_complete(struct i2c_op_q_entry * entry) ++{ ++ struct completion *done = entry->handler_data; ++ pr_debug("i2c_wait_complete %p\n", entry); ++ complete(done); ++} ++ ++static void i2c_perform_op_wait(struct i2c_adapter * adap, ++ struct i2c_op_q_entry * entry) ++{ ++ struct completion done; ++ unsigned long flags; ++ struct i2c_algorithm *algo = adap->algo; ++ ++ pr_debug("i2c_perform_op_wait %p %p\n", adap, entry); ++ init_completion(&done); ++ entry->start = NULL; ++ entry->handler = i2c_wait_complete; ++ entry->handler_data = &done; ++ entry->started = 0; ++ entry->completed = 0; ++ entry->result = 0; ++ entry->use_timer = 0; /* We poll it directly. */ ++ entry->data = NULL; ++ atomic_set(&entry->usecount, 1); ++ spin_lock_irqsave(&adap->q_lock, flags); ++ list_add_tail(&entry->link, &adap->q); ++ if (adap->q.next == &entry->link) { ++ /* Added to the list head, start it */ ++ spin_unlock_irqrestore(&adap->q_lock, flags); ++ i2c_start_entry(adap, entry); ++ } else { ++ struct completion start; ++ init_completion(&start); ++ entry->start = &start; ++ spin_unlock_irqrestore(&adap->q_lock, flags); ++ ++ wait_for_completion_interruptible(&start); ++ ++ spin_lock_irqsave(&adap->q_lock, flags); ++ if (!entry->started) { ++ /* Operation was interrupted. There ++ is a race, we can't use the ++ wait_for_completion return code. */ ++ entry->result = -ERESTARTSYS; ++ entry->completed = 1; ++ list_del(&entry->link); ++ } ++ spin_unlock_irqrestore(&adap->q_lock, flags); ++ } ++ ++ /* Once the operation is started, we will not ++ interrupt it. */ ++ while (!entry->completed) { ++ unsigned int timeout = entry->call_again_us; ++ timeout += (USEC_PER_JIFFIE - 1); ++ timeout /= USEC_PER_JIFFIE; ++ if (timeout == 0) ++ timeout = 1; ++ wait_for_completion_timeout(&done, timeout); ++ if (entry->completed) ++ break; ++ algo->poll(adap, entry, timeout * USEC_PER_JIFFIE); ++ } ++} ++ ++static int i2c_transfer_entry(struct i2c_adapter * adap, ++ struct i2c_op_q_entry * entry) ++{ ++ entry->xfer_type = I2C_OP_I2C; ++ entry->complete = NULL; ++ if (adap->algo->master_start) { ++ i2c_perform_op_wait(adap, entry); ++ return entry->result; ++ } else if (adap->algo->master_xfer) { ++ int ret; ++ dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", ++ entry->i2c.num); + + down(&adap->bus_lock); +- ret = adap->algo->master_xfer(adap,msgs,num); ++ ret = adap->algo->master_xfer(adap, entry->i2c.msgs, ++ entry->i2c.num); + up(&adap->bus_lock); + + return ret; +@@ -601,33 +902,45 @@ + } + } + ++int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num) ++{ ++ struct i2c_op_q_entry *entry; ++ int rv; ++ ++ entry = kmalloc(sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return -ENOMEM; ++ ++ entry->i2c.msgs = msgs; ++ entry->i2c.num = num; ++ ++ rv = i2c_transfer_entry(adap, entry); ++ kfree(entry); ++ return rv; ++} ++ + int i2c_master_send(struct i2c_client *client,const char *buf ,int count) + { + int ret; + struct i2c_adapter *adap=client->adapter; + struct i2c_msg msg; + +- if (client->adapter->algo->master_xfer) { +- msg.addr = client->addr; +- msg.flags = client->flags & I2C_M_TEN; +- msg.len = count; +- msg.buf = (char *)buf; +- +- dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n", +- count); ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.len = count; ++ msg.buf = (char *)buf; + +- down(&adap->bus_lock); +- ret = adap->algo->master_xfer(adap,&msg,1); +- up(&adap->bus_lock); ++ dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n", ++ count); + +- /* if everything went ok (i.e. 1 msg transmitted), return #bytes +- * transmitted, else error code. +- */ +- return (ret == 1 )? count : ret; +- } else { +- dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); +- return -ENOSYS; +- } ++ ret = i2c_transfer(adap, &msg, 1); ++ if (ret < 0) ++ return ret; ++ ++ /* if everything went ok (i.e. 1 msg transmitted), return #bytes ++ * transmitted, else error code. ++ */ ++ return (ret == 1 )? count : ret; + } + + int i2c_master_recv(struct i2c_client *client, char *buf ,int count) +@@ -635,31 +948,27 @@ + struct i2c_adapter *adap=client->adapter; + struct i2c_msg msg; + int ret; +- if (client->adapter->algo->master_xfer) { +- msg.addr = client->addr; +- msg.flags = client->flags & I2C_M_TEN; +- msg.flags |= I2C_M_RD; +- msg.len = count; +- msg.buf = buf; + +- dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n", +- count); +- +- down(&adap->bus_lock); +- ret = adap->algo->master_xfer(adap,&msg,1); +- up(&adap->bus_lock); ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.flags |= I2C_M_RD; ++ msg.len = count; ++ msg.buf = buf; ++ ++ dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n", ++ count); + +- dev_dbg(&client->adapter->dev, "master_recv: return:%d (count:%d, addr:0x%02x)\n", +- ret, count, client->addr); ++ ret = i2c_transfer(adap, &msg, 1); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(&client->adapter->dev, "master_recv: return:%d (count:%d, addr:0x%02x)\n", ++ ret, count, client->addr); + +- /* if everything went ok (i.e. 1 msg transmitted), return #bytes +- * transmitted, else error code. +- */ +- return (ret == 1 )? count : ret; +- } else { +- dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); +- return -ENOSYS; +- } ++ /* if everything went ok (i.e. 1 msg transmitted), return #bytes ++ * transmitted, else error code. ++ */ ++ return (ret == 1 )? count : ret; + } + + +@@ -1037,7 +1346,8 @@ + } + + /* Returns the number of read bytes */ +-s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values) ++s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, ++ u8 *values) + { + union i2c_smbus_data data; + int i; +@@ -1052,184 +1362,333 @@ + } + } + +-/* Simulate a SMBus command using the i2c protocol +- No checking of parameters is done! */ +-static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, +- unsigned short flags, +- char read_write, u8 command, int size, +- union i2c_smbus_data * data) +-{ +- /* So we need to generate a series of msgs. In the case of writing, we +- need to use only one message; when reading, we need two. We initialize +- most things with sane defaults, to keep the code below somewhat +- simpler. */ +- unsigned char msgbuf0[34]; +- unsigned char msgbuf1[34]; +- int num = read_write == I2C_SMBUS_READ?2:1; +- struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, +- { addr, flags | I2C_M_RD, 0, msgbuf1 } +- }; ++ ++static void i2c_smbus_complete_entry(struct i2c_adapter * adap, ++ struct i2c_op_q_entry * entry) ++{ ++ if (entry->result < 0) ++ return; ++ ++ if(entry->result >= 0 && entry->swpec && ++ entry->smbus.size != I2C_SMBUS_QUICK && ++ entry->smbus.size != I2C_SMBUS_I2C_BLOCK_DATA && ++ (entry->smbus.read_write == I2C_SMBUS_READ || ++ entry->smbus.size == I2C_SMBUS_PROC_CALL_PEC || ++ entry->smbus.size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) { ++ if(i2c_smbus_check_pec(entry->smbus.addr, ++ entry->smbus.command, ++ entry->smbus.size, ++ entry->partial, ++ entry->smbus.data)) ++ entry->result = -EINVAL; ++ } ++} ++ ++static void i2c_smbus_format_entry(struct i2c_adapter * adap, ++ struct i2c_op_q_entry * entry) ++{ ++ entry->swpec = 0; ++ entry->partial = 0; ++ entry->smbus.flags &= I2C_M_TEN | I2C_CLIENT_PEC; ++ if((entry->smbus.flags & I2C_CLIENT_PEC) && ++ !(i2c_check_functionality(adap, I2C_FUNC_SMBUS_HWPEC_CALC))) { ++ entry->swpec = 1; ++ if(entry->smbus.read_write == I2C_SMBUS_READ && ++ entry->smbus.size == I2C_SMBUS_BLOCK_DATA) ++ entry->smbus.size = I2C_SMBUS_BLOCK_DATA_PEC; ++ else if(entry->smbus.size == I2C_SMBUS_PROC_CALL) ++ entry->smbus.size = I2C_SMBUS_PROC_CALL_PEC; ++ else if(entry->smbus.size == I2C_SMBUS_BLOCK_PROC_CALL) { ++ unsigned char *data = entry->smbus.data->block; ++ i2c_smbus_add_pec(entry->smbus.addr, ++ entry->smbus.command, ++ I2C_SMBUS_BLOCK_DATA, ++ entry->smbus.data); ++ entry->partial = data[data[0] + 1]; ++ entry->smbus.size = I2C_SMBUS_BLOCK_PROC_CALL_PEC; ++ } else if(entry->smbus.read_write == I2C_SMBUS_WRITE && ++ entry->smbus.size != I2C_SMBUS_QUICK && ++ entry->smbus.size != I2C_SMBUS_I2C_BLOCK_DATA) ++ entry->smbus.size = ++ i2c_smbus_add_pec(entry->smbus.addr, ++ entry->smbus.command, ++ entry->smbus.size, ++ entry->smbus.data); ++ } ++ ++ entry->complete = i2c_smbus_complete_entry; ++} ++ ++static void i2c_smbus_emu_complete(struct i2c_adapter * adap, ++ struct i2c_op_q_entry * entry) ++{ ++ unsigned char *msgbuf0 = entry->i2c.msgs[0].buf; ++ unsigned char *msgbuf1 = entry->i2c.msgs[1].buf; + int i; + +- msgbuf0[0] = command; +- switch(size) { ++ if (entry->smbus.read_write != I2C_SMBUS_READ) ++ return; ++ ++ switch(entry->smbus.size) { ++ case I2C_SMBUS_BYTE: ++ entry->smbus.data->byte = msgbuf0[0]; ++ break; ++ case I2C_SMBUS_BYTE_DATA: ++ entry->smbus.data->byte = msgbuf1[0]; ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ case I2C_SMBUS_PROC_CALL: ++ entry->smbus.data->word = msgbuf1[0]|(msgbuf1[1] << 8); ++ break; ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ /* fixed at 32 for now */ ++ entry->smbus.data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX; ++ for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++) ++ entry->smbus.data->block[i+1] = msgbuf1[i]; ++ break; ++ } ++ ++ entry->xfer_type = I2C_OP_SMBUS; ++ i2c_smbus_complete_entry(adap, entry); ++} ++ ++static int i2c_smbus_emu_format(struct i2c_adapter *adap, ++ struct i2c_op_q_entry * entry) ++{ ++ /* So we need to generate a series of msgs. In the case of ++ writing, we need to use only one message; when reading, we ++ need two. We initialize most things with sane defaults, to ++ keep the code below somewhat simpler. */ ++ unsigned char *msgbuf0 = entry->msgbuf0; ++ unsigned char *msgbuf1 = entry->msgbuf1; ++ int num = entry->smbus.read_write == I2C_SMBUS_READ?2:1; ++ struct i2c_msg *msg = entry->msg; ++ int i; ++ ++ entry->i2c.msgs = msg; ++ entry->i2c.msgs[0].buf = msgbuf0; ++ entry->i2c.msgs[1].buf = msgbuf1; ++ ++ msg[0].addr = entry->smbus.addr; ++ msg[0].flags = entry->smbus.flags; ++ msg[0].len = 1; ++ msg[1].addr = entry->smbus.addr; ++ msg[1].flags = entry->smbus.flags | I2C_M_RD; ++ msg[1].len = 1; ++ ++ msgbuf0[0] = entry->smbus.command; ++ switch(entry->smbus.size) { + case I2C_SMBUS_QUICK: + msg[0].len = 0; + /* Special case: The read/write field is used as data */ +- msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0; ++ msg[0].flags = (entry->smbus.flags | ++ ((entry->smbus.read_write==I2C_SMBUS_READ) ++ ? I2C_M_RD : 0)); + num = 1; + break; + case I2C_SMBUS_BYTE: +- if (read_write == I2C_SMBUS_READ) { ++ if (entry->smbus.read_write == I2C_SMBUS_READ) { + /* Special case: only a read! */ +- msg[0].flags = I2C_M_RD | flags; ++ msg[0].flags = I2C_M_RD | entry->smbus.flags; + num = 1; + } + break; + case I2C_SMBUS_BYTE_DATA: +- if (read_write == I2C_SMBUS_READ) ++ if (entry->smbus.read_write == I2C_SMBUS_READ) + msg[1].len = 1; + else { + msg[0].len = 2; +- msgbuf0[1] = data->byte; ++ msgbuf0[1] = entry->smbus.data->byte; + } + break; + case I2C_SMBUS_WORD_DATA: +- if (read_write == I2C_SMBUS_READ) ++ if (entry->smbus.read_write == I2C_SMBUS_READ) + msg[1].len = 2; + else { + msg[0].len=3; +- msgbuf0[1] = data->word & 0xff; +- msgbuf0[2] = (data->word >> 8) & 0xff; ++ msgbuf0[1] = entry->smbus.data->word & 0xff; ++ msgbuf0[2] = (entry->smbus.data->word >> 8) & 0xff; + } + break; + case I2C_SMBUS_PROC_CALL: + num = 2; /* Special case */ +- read_write = I2C_SMBUS_READ; ++ entry->smbus.read_write = I2C_SMBUS_READ; + msg[0].len = 3; + msg[1].len = 2; +- msgbuf0[1] = data->word & 0xff; +- msgbuf0[2] = (data->word >> 8) & 0xff; ++ msgbuf0[1] = entry->smbus.data->word & 0xff; ++ msgbuf0[2] = (entry->smbus.data->word >> 8) & 0xff; + break; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_DATA_PEC: +- if (read_write == I2C_SMBUS_READ) { +- dev_err(&adapter->dev, "Block read not supported " ++ if (entry->smbus.read_write == I2C_SMBUS_READ) { ++ dev_err(&adap->dev, "Block read not supported " + "under I2C emulation!\n"); + return -1; + } else { +- msg[0].len = data->block[0] + 2; ++ msg[0].len = entry->smbus.data->block[0] + 2; + if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { +- dev_err(&adapter->dev, "smbus_access called with " ++ dev_err(&adap->dev, ++ "smbus_access called with " + "invalid block write size (%d)\n", +- data->block[0]); ++ entry->smbus.data->block[0]); + return -1; + } +- if(size == I2C_SMBUS_BLOCK_DATA_PEC) ++ if(entry->smbus.size == I2C_SMBUS_BLOCK_DATA_PEC) + (msg[0].len)++; + for (i = 1; i <= msg[0].len; i++) +- msgbuf0[i] = data->block[i-1]; ++ msgbuf0[i] = entry->smbus.data->block[i-1]; + } + break; + case I2C_SMBUS_BLOCK_PROC_CALL: + case I2C_SMBUS_BLOCK_PROC_CALL_PEC: +- dev_dbg(&adapter->dev, "Block process call not supported " ++ dev_dbg(&adap->dev, "Block process call not supported " + "under I2C emulation!\n"); + return -1; + case I2C_SMBUS_I2C_BLOCK_DATA: +- if (read_write == I2C_SMBUS_READ) { ++ if (entry->smbus.read_write == I2C_SMBUS_READ) { + msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX; + } else { +- msg[0].len = data->block[0] + 1; ++ msg[0].len = entry->smbus.data->block[0] + 1; + if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) { +- dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with " ++ dev_err(&adap->dev, ++ "i2c_smbus_xfer_emulated called with " + "invalid block write size (%d)\n", +- data->block[0]); ++ entry->smbus.data->block[0]); + return -1; + } +- for (i = 1; i <= data->block[0]; i++) +- msgbuf0[i] = data->block[i]; ++ for (i = 1; i <= entry->smbus.data->block[0]; i++) ++ msgbuf0[i] = entry->smbus.data->block[i]; + } + break; + default: +- dev_err(&adapter->dev, "smbus_access called with invalid size (%d)\n", +- size); ++ dev_err(&adap->dev, ++ "smbus_access called with invalid size (%d)\n", ++ entry->smbus.size); + return -1; + } + +- if (i2c_transfer(adapter, msg, num) < 0) +- return -1; +- +- if (read_write == I2C_SMBUS_READ) +- switch(size) { +- case I2C_SMBUS_BYTE: +- data->byte = msgbuf0[0]; +- break; +- case I2C_SMBUS_BYTE_DATA: +- data->byte = msgbuf1[0]; +- break; +- case I2C_SMBUS_WORD_DATA: +- case I2C_SMBUS_PROC_CALL: +- data->word = msgbuf1[0] | (msgbuf1[1] << 8); +- break; +- case I2C_SMBUS_I2C_BLOCK_DATA: +- /* fixed at 32 for now */ +- data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX; +- for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++) +- data->block[i+1] = msgbuf1[i]; +- break; +- } ++ entry->xfer_type = I2C_OP_I2C; ++ entry->i2c.msgs = msg; ++ entry->i2c.num = num; ++ entry->complete = i2c_smbus_emu_complete; + return 0; + } + ++/* Simulate a SMBus command using the i2c protocol ++ No checking of parameters is done! */ ++static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adap, ++ struct i2c_op_q_entry * entry) ++ ++{ ++ if (i2c_smbus_emu_format(adap, entry)) ++ return -EINVAL; ++ ++ if (i2c_transfer_entry(adap, entry) < 0) ++ return -EINVAL; + +-s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, ++ return entry->result; ++} ++ ++s32 i2c_smbus_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, + char read_write, u8 command, int size, + union i2c_smbus_data * data) + { +- s32 res; +- int swpec = 0; +- u8 partial = 0; +- +- flags &= I2C_M_TEN | I2C_CLIENT_PEC; +- if((flags & I2C_CLIENT_PEC) && +- !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) { +- swpec = 1; +- if(read_write == I2C_SMBUS_READ && +- size == I2C_SMBUS_BLOCK_DATA) +- size = I2C_SMBUS_BLOCK_DATA_PEC; +- else if(size == I2C_SMBUS_PROC_CALL) +- size = I2C_SMBUS_PROC_CALL_PEC; +- else if(size == I2C_SMBUS_BLOCK_PROC_CALL) { +- i2c_smbus_add_pec(addr, command, +- I2C_SMBUS_BLOCK_DATA, data); +- partial = data->block[data->block[0] + 1]; +- size = I2C_SMBUS_BLOCK_PROC_CALL_PEC; +- } else if(read_write == I2C_SMBUS_WRITE && +- size != I2C_SMBUS_QUICK && +- size != I2C_SMBUS_I2C_BLOCK_DATA) +- size = i2c_smbus_add_pec(addr, command, size, data); +- } +- +- if (adapter->algo->smbus_xfer) { +- down(&adapter->bus_lock); +- res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, +- command,size,data); +- up(&adapter->bus_lock); +- } else +- res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, +- command,size,data); +- +- if(res >= 0 && swpec && +- size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA && +- (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC || +- size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) { +- if(i2c_smbus_check_pec(addr, command, size, partial, data)) +- return -1; ++ struct i2c_op_q_entry *entry; ++ struct i2c_algorithm *algo = adap->algo; ++ int result; ++ ++ ++ entry = kmalloc(sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return -ENOMEM; ++ ++ entry->xfer_type = I2C_OP_SMBUS; ++ entry->smbus.addr = addr; ++ entry->smbus.flags = flags; ++ entry->smbus.read_write = read_write; ++ entry->smbus.command = command; ++ entry->smbus.size = size; ++ entry->smbus.data = data; ++ ++ i2c_smbus_format_entry(adap, entry); ++ ++ if (algo->smbus_start) { ++ i2c_perform_op_wait(adap, entry); ++ } else if (algo->smbus_xfer) { ++ down(&adap->bus_lock); ++ entry->result = adap->algo->smbus_xfer(adap, ++ entry->smbus.addr, ++ entry->smbus.flags, ++ entry->smbus.read_write, ++ entry->smbus.command, ++ entry->smbus.size, ++ entry->smbus.data); ++ up(&adap->bus_lock); ++ } else { ++ i2c_smbus_xfer_emulated(adap, entry); + } +- return res; ++ ++ result = entry->result; ++ kfree(entry); ++ return result; + } + ++int i2c_non_blocking_capable(struct i2c_adapter *adap) ++{ ++ return adap->algo->poll != NULL; ++} ++ ++void i2c_poll(struct i2c_client *client, ++ unsigned int us_since_last_call) ++{ ++ struct i2c_adapter *adap = client->adapter; ++ struct i2c_op_q_entry *entry; ++ ++ entry = i2c_entry_get(adap); ++ if (!entry) ++ return; ++ adap->algo->poll(adap, entry, us_since_last_call); ++ i2c_entry_put(adap, entry); ++} ++ ++int i2c_non_blocking_op(struct i2c_client *client, ++ struct i2c_op_q_entry *entry) ++{ ++ unsigned long flags; ++ struct i2c_adapter *adap = client->adapter; ++ ++ if (!i2c_non_blocking_capable(adap)) ++ return -ENOSYS; ++ ++ entry->smbus.addr = client->addr; ++ entry->smbus.flags = client->flags; ++ ++ if (entry->xfer_type == I2C_OP_SMBUS) { ++ i2c_smbus_format_entry(adap, entry); ++ if (!adap->algo->smbus_start) { ++ if (i2c_smbus_emu_format(adap, entry)) ++ return -EINVAL; ++ } ++ } ++ ++ entry->start = NULL; ++ entry->started = 0; ++ entry->completed = 0; ++ entry->result = 0; ++ entry->use_timer = 1; /* Let the timer code poll it. */ ++ entry->data = NULL; ++ atomic_set(&entry->usecount, 1); ++ ++ spin_lock_irqsave(&adap->q_lock, flags); ++ list_add_tail(&entry->link, &adap->q); ++ if (adap->q.next == &entry->link) { ++ /* Added to the list head, start it */ ++ spin_unlock_irqrestore(&adap->q_lock, flags); ++ i2c_start_entry(adap, entry); ++ } else ++ spin_unlock_irqrestore(&adap->q_lock, flags); ++ return 0; ++} + + /* You should always define `functionality'; the 'else' is just for + backward compatibility. */ +@@ -1258,6 +1717,7 @@ + EXPORT_SYMBOL(i2c_clients_command); + EXPORT_SYMBOL(i2c_check_addr); + ++EXPORT_SYMBOL(i2c_op_done); + EXPORT_SYMBOL(i2c_master_send); + EXPORT_SYMBOL(i2c_master_recv); + EXPORT_SYMBOL(i2c_control); +@@ -1278,6 +1738,10 @@ + EXPORT_SYMBOL(i2c_smbus_write_block_data); + EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); + ++EXPORT_SYMBOL(i2c_non_blocking_capable); ++EXPORT_SYMBOL(i2c_poll); ++EXPORT_SYMBOL(i2c_non_blocking_op); ++ + EXPORT_SYMBOL(i2c_get_functionality); + EXPORT_SYMBOL(i2c_check_functionality); + +Index: linux-2.6.11-rc2/include/linux/i2c.h +=================================================================== +--- linux-2.6.11-rc2.orig/include/linux/i2c.h 2005-01-26 15:59:53.000000000 -0600 ++++ linux-2.6.11-rc2/include/linux/i2c.h 2005-01-28 08:53:31.000000000 -0600 +@@ -32,7 +32,11 @@ + #include <linux/types.h> + #include <linux/i2c-id.h> + #include <linux/device.h> /* for struct device */ ++#include <linux/list.h> ++#include <linux/spinlock.h> ++#include <linux/timer.h> + #include <asm/semaphore.h> ++#include <asm/atomic.h> + + /* --- General options ------------------------------------------------ */ + +@@ -43,6 +47,7 @@ + struct i2c_driver; + struct i2c_client_address_data; + union i2c_smbus_data; ++struct i2c_op_q_entry; + + /* + * The master routines are the ones normally used to transmit data to devices +@@ -55,7 +60,7 @@ + + /* Transfer num messages. + */ +-extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],int num); ++extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msg,int num); + + /* + * Some adapter types (i.e. PCF 8584 based ones) may support slave behaviuor. +@@ -95,6 +100,25 @@ + extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, + u8 command, u8 *values); + ++/* Non-blocking interface. The user should fill out the public ++ portions of the entry structure. All data in the entry structure ++ should be guaranteed to be available until the handler callback is ++ called with the entry. */ ++typedef void (*i2c_op_done_cb)(struct i2c_op_q_entry *entry); ++ ++extern int i2c_non_blocking_op(struct i2c_client *client, ++ struct i2c_op_q_entry *entry); ++ ++/* Can the adapter do non-blocking operations? */ ++extern int i2c_non_blocking_capable(struct i2c_adapter *adap); ++ ++/* Poll the i2c interface. This should only be called in a situation ++ where scheduling and interrupts are off. You should put the amount ++ of microseconds between calls in us_since_last_call. */ ++extern void i2c_poll(struct i2c_client *client, ++ unsigned int us_since_last_call); ++ ++ + /* + * A driver is capable of handling one or more physical devices present on + * I2C adapters. This information is used to inform the driver of adapter +@@ -181,6 +205,33 @@ + } + + /* ++ * About locking and the non-blocking interface. ++ * ++ * The poll operations are called single-threaded (along with the ++ * xxx_start operations), so if the driver is only polled then there ++ * is no need to do any locking. If you are using interrupts, then ++ * the timer operations and interrupts can race and you need to lock ++ * appropriately. ++ * ++ * i2c_op_done() can be called multiple times on the same entry (as ++ * long as each one has a get operation). This handles poll and ++ * interrupt races calling i2c_op_done(). It will do the right thing. ++ */ ++ ++/* Called from an non-blocking interface to get the current working ++ entry. Returns NULL if there is none. This is primarily for ++ interrupt handlers to determine what they should be working on. ++ Note that if you call i2c_entry_get() and get a non-null entry, you ++ must call i2c_entry_put() on it. */ ++struct i2c_op_q_entry *i2c_entry_get(struct i2c_adapter * adap); ++void i2c_entry_put(struct i2c_adapter * adap, ++ struct i2c_op_q_entry * entry); ++ ++/* Called from an non-blocking interface to report that an operation ++ has completed. Can be called from interrupt context. */ ++void i2c_op_done(struct i2c_adapter *adap, struct i2c_op_q_entry *entry); ++ ++/* + * The following structs are for those who like to implement new bus drivers: + * i2c_algorithm is the interface to a class of hardware solutions which can + * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584 +@@ -190,15 +241,40 @@ + char name[32]; /* textual description */ + unsigned int id; + +- /* If an adapter algorithm can't to I2C-level access, set master_xfer ++ /* If an adapter algorithm can't do I2C-level access, set master_xfer + to NULL. If an adapter algorithm can do SMBus access, set + smbus_xfer. If set to NULL, the SMBus protocol is simulated + using common I2C messages */ +- int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg msgs[], +- int num); +- int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, +- unsigned short flags, char read_write, +- u8 command, int size, union i2c_smbus_data * data); ++ int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs, ++ int num); ++ int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr, ++ unsigned short flags, char read_write, ++ u8 command, int size, union i2c_smbus_data * data); ++ ++ /* These are like the previous calls, but they will only start ++ the operation. The poll call will be called periodically ++ to drive the operation of the bus. Each of these calls ++ should set the result on an error, and set the timeout as ++ necessary. Note that even interrupt driven drivers need to ++ poll so they can time out operations. When the operation ++ is complete, these should call i2c_op_done(). Note that ++ all the data structures passed in are guaranteed to be kept ++ around until the operation completes. These may be called ++ from interrupt context. If the start operation fails, this ++ should set the result and call i2c_op_done(). */ ++ void (*master_start)(struct i2c_adapter *adap, ++ struct i2c_op_q_entry *entry); ++ void (*smbus_start)(struct i2c_adapter *adap, ++ struct i2c_op_q_entry *entry); ++ /* us_since_last_poll is the amount of time since the last ++ time poll was called. Note that this may be *less* than the ++ time you requested, so always use this number and don't ++ assume it's the one you gave it. This time is approximate ++ and is only guaranteed to be >= the time since the last ++ poll. The value may be zero. */ ++ void (*poll)(struct i2c_adapter *adap, ++ struct i2c_op_q_entry *entry, ++ unsigned int us_since_last_poll); + + /* --- these optional/future use for some adapter types.*/ + int (*slave_send)(struct i2c_adapter *,char*,int); +@@ -212,6 +288,21 @@ + }; + + /* ++ * The timer has it's own separately allocated data structure because ++ * it needs to be able to exist even if the adapter is deleted (due to ++ * timer cancellation races). ++ */ ++struct i2c_timer { ++ spinlock_t lock; ++ int deleted; ++ struct timer_list timer; ++ int running; ++ unsigned int next_call_time; ++ struct i2c_adapter *adapter; ++ unsigned int sequence; ++}; ++ ++/* + * i2c_adapter is the structure used to identify a physical i2c bus along + * with the access algorithms necessary to access it. + */ +@@ -228,8 +319,15 @@ + int (*client_unregister)(struct i2c_client *); + + /* data fields that are valid for all devices */ ++ struct list_head q; ++ spinlock_t q_lock; ++ + struct semaphore bus_lock; +- struct semaphore clist_lock; ++ ++ /* Used to time non-blocking operations. The sequence is used ++ to handle race conditions in the timer handler. */ ++ struct i2c_timer *timer; ++ unsigned int timer_sequence; + + int timeout; + int retries; +@@ -242,9 +340,14 @@ + #endif /* def CONFIG_PROC_FS */ + + int nr; ++ ++ struct semaphore clist_lock; + struct list_head clients; ++ + struct list_head list; ++ + char name[I2C_NAME_SIZE]; ++ + struct completion dev_released; + struct completion class_dev_released; + }; +@@ -395,6 +498,90 @@ + __u8 *buf; /* pointer to msg data */ + }; + ++/* ++ * Hold a queue of I2C operations to perform, and used to pass data ++ * around. ++ */ ++#define I2C_OP_I2C 0 ++#define I2C_OP_SMBUS 1 ++struct i2c_op_q_entry { ++ /* The result will be set to the result of the operation when ++ it completes. */ ++ s32 result; ++ ++ /**************************************************************/ ++ /* Public interface. The user should set these up (and the ++ proper structure below). */ ++ int xfer_type; ++ ++ /* Handler may be called from interrupt context, so be ++ careful. */ ++ i2c_op_done_cb handler; ++ void *handler_data; ++ ++ /* Note that this is not a union because an smbus operation ++ may be converted into an i2c operation (thus both ++ structures will be used). The data in these may be changd ++ by the driver. */ ++ struct { ++ struct i2c_msg *msgs; ++ int num; ++ } i2c; ++ struct { ++ /* Addr and flags are filled in by the non-blocking ++ send routine that takes a client. */ ++ u16 addr; ++ unsigned short flags; ++ ++ char read_write; ++ u8 command; ++ ++ /* Note that the size is *not* the length of the data. ++ It is the transaction type, like I2C_SMBUS_QUICK ++ and the ones after that below. If this is a block ++ transaction, the length of the rest of the data is ++ in the first byte of the data, for both transmit ++ and receive. */ ++ int size; ++ union i2c_smbus_data *data; ++ } smbus; ++ ++ /**************************************************************/ ++ /* For use by the bus interface. The bus interface sets the ++ timeout in microseconds until the next poll operation. ++ This *must* be set in the start operation. The time_left ++ and data can be used for anything the bus interface likes. ++ data will be set to NULL before being started so the bus ++ interface can use that to tell if it has been set up ++ yet. */ ++ unsigned int call_again_us; ++ long time_left; ++ void *data; ++ ++ /**************************************************************/ ++ /* Internals */ ++ struct list_head link; ++ struct completion *start; ++ unsigned int started : 1; ++ unsigned int completed : 1; ++ unsigned int use_timer : 1; ++ u8 swpec; ++ u8 partial; ++ void (*complete)(struct i2c_adapter *adap, ++ struct i2c_op_q_entry *entry); ++ ++ /* It's wierd, but we use a usecount to track if an q entry is ++ in use and when it should be reported back to the user. */ ++ atomic_t usecount; ++ ++ /* These are here for SMBus emulation over I2C. I don't like ++ them taking this much room in the data structure, but they ++ need to be available in this case. */ ++ unsigned char msgbuf0[34]; ++ unsigned char msgbuf1[34]; ++ struct i2c_msg msg[2]; ++}; ++ + /* To determine what functionality is present */ + + #define I2C_FUNC_I2C 0x00000001 +@@ -423,22 +610,22 @@ + #define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC 0x40000000 /* SMBus 2.0 */ + #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */ + +-#define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \ +- I2C_FUNC_SMBUS_WRITE_BYTE +-#define I2C_FUNC_SMBUS_BYTE_DATA I2C_FUNC_SMBUS_READ_BYTE_DATA | \ +- I2C_FUNC_SMBUS_WRITE_BYTE_DATA +-#define I2C_FUNC_SMBUS_WORD_DATA I2C_FUNC_SMBUS_READ_WORD_DATA | \ +- I2C_FUNC_SMBUS_WRITE_WORD_DATA +-#define I2C_FUNC_SMBUS_BLOCK_DATA I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ +- I2C_FUNC_SMBUS_WRITE_BLOCK_DATA +-#define I2C_FUNC_SMBUS_I2C_BLOCK I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ +- I2C_FUNC_SMBUS_WRITE_I2C_BLOCK +-#define I2C_FUNC_SMBUS_I2C_BLOCK_2 I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \ +- I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 +-#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \ +- I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC +-#define I2C_FUNC_SMBUS_WORD_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \ +- I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC ++#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ ++ I2C_FUNC_SMBUS_WRITE_BYTE) ++#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \ ++ I2C_FUNC_SMBUS_WRITE_BYTE_DATA) ++#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \ ++ I2C_FUNC_SMBUS_WRITE_WORD_DATA) ++#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ ++ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) ++#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ ++ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) ++#define I2C_FUNC_SMBUS_I2C_BLOCK_2 (I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \ ++ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2) ++#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC (I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \ ++ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC) ++#define I2C_FUNC_SMBUS_WORD_DATA_PEC (I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \ ++ I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC) + + #define I2C_FUNC_SMBUS_READ_BYTE_PEC I2C_FUNC_SMBUS_READ_BYTE_DATA + #define I2C_FUNC_SMBUS_WRITE_BYTE_PEC I2C_FUNC_SMBUS_WRITE_BYTE_DATA +@@ -447,14 +634,14 @@ + #define I2C_FUNC_SMBUS_BYTE_PEC I2C_FUNC_SMBUS_BYTE_DATA + #define I2C_FUNC_SMBUS_BYTE_DATA_PEC I2C_FUNC_SMBUS_WORD_DATA + +-#define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \ +- I2C_FUNC_SMBUS_BYTE | \ +- I2C_FUNC_SMBUS_BYTE_DATA | \ +- I2C_FUNC_SMBUS_WORD_DATA | \ +- I2C_FUNC_SMBUS_PROC_CALL | \ +- I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ +- I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \ +- I2C_FUNC_SMBUS_I2C_BLOCK ++#define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | \ ++ I2C_FUNC_SMBUS_BYTE | \ ++ I2C_FUNC_SMBUS_BYTE_DATA | \ ++ I2C_FUNC_SMBUS_WORD_DATA | \ ++ I2C_FUNC_SMBUS_PROC_CALL | \ ++ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ ++ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \ ++ I2C_FUNC_SMBUS_I2C_BLOCK) + + /* + * Data for SMBus Messages diff --git a/a/content_digest b/N1/content_digest index cdfe916..a5ea91d 100644 --- a/a/content_digest +++ b/N1/content_digest @@ -2,14 +2,14 @@ "ref\041F984D4.5030306@verizon.net\0" "ref\041F9C2EC.5070806@acm.org\0" "ref\041F9E183.5A9B1BA2@gte.net\0" - "From\0minyard@acm.org (Corey Minyard)\0" + "From\0Corey Minyard <minyard@acm.org>\0" "Subject\0[PATCH] Add a non-blocking I2C interface\0" - "Date\0Thu, 19 May 2005 06:25:33 +0000\0" + "Date\0Fri, 28 Jan 2005 09:08:06 -0600\0" "To\0Bukie Mabayoje <bukiemab@gte.net>\0" "Cc\0Mark Studebaker <mds4@verizon.net>" Sensors <sensors@stimpy.netroedge.com> " lkml <linux-kernel@vger.kernel.org>\0" - "\00:1\0" + "\01:1\0" "b\0" "Here's the code that I have so far for adding a non-blocking interface \n" "to the I2C interface. I've debated whether to do this as a patch or \n" @@ -38,7 +38,7 @@ "\n" "This patch requires the fixes to the completion code that Mike Waychison \n" "posted a few days ago \n" - "(http://marc.theaimsgroup.com/?l=linux-kernel&m\0210669761400454&w=2). \n" + "(http://marc.theaimsgroup.com/?l=linux-kernel&m=110669761400454&w=2). \n" "Otherwise the wait_for_completion_interruptible() and \n" "wait_for_completion_timeout() are broken.\n" "\n" @@ -49,10 +49,13 @@ "current I2C driver requires a task context, but you can't exactly do \n" "things at panic time with a task context.\n" "\n" - "-Corey\n" - "-------------- next part --------------\n" + -Corey + "\01:2\0" + "fn\0i2c_async.diff\0" + "b\0" "Index: linux-2.6.11-rc2/drivers/i2c/i2c-core.c\n" - "=================================--- linux-2.6.11-rc2.orig/drivers/i2c/i2c-core.c\t2005-01-26 15:59:53.000000000 -0600\n" + "===================================================================\n" + "--- linux-2.6.11-rc2.orig/drivers/i2c/i2c-core.c\t2005-01-26 15:59:53.000000000 -0600\n" "+++ linux-2.6.11-rc2/drivers/i2c/i2c-core.c\t2005-01-28 08:54:00.000000000 -0600\n" "@@ -30,8 +30,14 @@\n" " #include <linux/init.h>\n" @@ -229,7 +232,7 @@ "+\n" "+\twait_jiffies = ((entry->call_again_us + USEC_PER_JIFFIE - 1)\n" "+\t\t\t/ USEC_PER_JIFFIE);\n" - "+\tif (wait_jiffies = 0)\n" + "+\tif (wait_jiffies == 0)\n" "+\t\twait_jiffies = 1;\n" "+\t/* This won't be polled from the user code, so\n" "+\t start a timer to poll it. */\n" @@ -270,7 +273,7 @@ "+\n" "+\tadap = t->adapter;\n" "+\tt->running = 0;\n" - "+\tsequence_match = adap->timer_sequence = t->sequence;\n" + "+\tsequence_match = adap->timer_sequence == t->sequence;\n" "+\tspin_unlock_irqrestore(&t->lock, flags);\n" "+\n" "+\tentry = i2c_entry_get(adap);\n" @@ -352,7 +355,7 @@ "+\tatomic_set(&entry->usecount, 1);\n" "+\tspin_lock_irqsave(&adap->q_lock, flags);\n" "+\tlist_add_tail(&entry->link, &adap->q);\n" - "+\tif (adap->q.next = &entry->link) {\n" + "+\tif (adap->q.next == &entry->link) {\n" "+\t\t/* Added to the list head, start it */\n" "+\t\tspin_unlock_irqrestore(&adap->q_lock, flags);\n" "+\t\ti2c_start_entry(adap, entry);\n" @@ -382,7 +385,7 @@ "+\t\tunsigned int timeout = entry->call_again_us;\n" "+\t\ttimeout += (USEC_PER_JIFFIE - 1);\n" "+\t\ttimeout /= USEC_PER_JIFFIE;\n" - "+\t\tif (timeout = 0)\n" + "+\t\tif (timeout == 0)\n" "+\t\t\ttimeout = 1;\n" "+\t\twait_for_completion_timeout(&done, timeout);\n" "+\t\tif (entry->completed)\n" @@ -460,7 +463,7 @@ "-\t\t/* if everything went ok (i.e. 1 msg transmitted), return #bytes\n" "-\t\t * transmitted, else error code.\n" "-\t\t */\n" - "-\t\treturn (ret = 1 )? count : ret;\n" + "-\t\treturn (ret == 1 )? count : ret;\n" "-\t} else {\n" "-\t\tdev_err(&client->adapter->dev, \"I2C level transfers not supported\\n\");\n" "-\t\treturn -ENOSYS;\n" @@ -472,7 +475,7 @@ "+\t/* if everything went ok (i.e. 1 msg transmitted), return #bytes\n" "+\t * transmitted, else error code.\n" "+\t */\n" - "+\treturn (ret = 1 )? count : ret;\n" + "+\treturn (ret == 1 )? count : ret;\n" " }\n" " \n" " int i2c_master_recv(struct i2c_client *client, char *buf ,int count)\n" @@ -514,7 +517,7 @@ "-\t\t/* if everything went ok (i.e. 1 msg transmitted), return #bytes\n" "-\t \t* transmitted, else error code.\n" "-\t \t*/\n" - "-\t\treturn (ret = 1 )? count : ret;\n" + "-\t\treturn (ret == 1 )? count : ret;\n" "-\t} else {\n" "-\t\tdev_err(&client->adapter->dev, \"I2C level transfers not supported\\n\");\n" "-\t\treturn -ENOSYS;\n" @@ -522,7 +525,7 @@ "+\t/* if everything went ok (i.e. 1 msg transmitted), return #bytes\n" "+\t * transmitted, else error code.\n" "+\t */\n" - "+\treturn (ret = 1 )? count : ret;\n" + "+\treturn (ret == 1 )? count : ret;\n" " }\n" " \n" " \n" @@ -553,7 +556,7 @@ "-\t simpler. */\n" "-\tunsigned char msgbuf0[34];\n" "-\tunsigned char msgbuf1[34];\n" - "-\tint num = read_write = I2C_SMBUS_READ?2:1;\n" + "-\tint num = read_write == I2C_SMBUS_READ?2:1;\n" "-\tstruct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, \n" "-\t { addr, flags | I2C_M_RD, 0, msgbuf1 }\n" "-\t };\n" @@ -567,9 +570,9 @@ "+\tif(entry->result >= 0 && entry->swpec &&\n" "+\t entry->smbus.size != I2C_SMBUS_QUICK &&\n" "+\t entry->smbus.size != I2C_SMBUS_I2C_BLOCK_DATA &&\n" - "+\t (entry->smbus.read_write = I2C_SMBUS_READ ||\n" - "+\t entry->smbus.size = I2C_SMBUS_PROC_CALL_PEC ||\n" - "+\t entry->smbus.size = I2C_SMBUS_BLOCK_PROC_CALL_PEC)) {\n" + "+\t (entry->smbus.read_write == I2C_SMBUS_READ ||\n" + "+\t entry->smbus.size == I2C_SMBUS_PROC_CALL_PEC ||\n" + "+\t entry->smbus.size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) {\n" "+\t\tif(i2c_smbus_check_pec(entry->smbus.addr,\n" "+\t\t\t\t entry->smbus.command,\n" "+\t\t\t\t entry->smbus.size,\n" @@ -588,12 +591,12 @@ "+\tif((entry->smbus.flags & I2C_CLIENT_PEC) &&\n" "+\t !(i2c_check_functionality(adap, I2C_FUNC_SMBUS_HWPEC_CALC))) {\n" "+\t\tentry->swpec = 1;\n" - "+\t\tif(entry->smbus.read_write = I2C_SMBUS_READ &&\n" - "+\t\t entry->smbus.size = I2C_SMBUS_BLOCK_DATA)\n" + "+\t\tif(entry->smbus.read_write == I2C_SMBUS_READ &&\n" + "+\t\t entry->smbus.size == I2C_SMBUS_BLOCK_DATA)\n" "+\t\t\tentry->smbus.size = I2C_SMBUS_BLOCK_DATA_PEC;\n" - "+\t\telse if(entry->smbus.size = I2C_SMBUS_PROC_CALL)\n" + "+\t\telse if(entry->smbus.size == I2C_SMBUS_PROC_CALL)\n" "+\t\t\tentry->smbus.size = I2C_SMBUS_PROC_CALL_PEC;\n" - "+\t\telse if(entry->smbus.size = I2C_SMBUS_BLOCK_PROC_CALL) {\n" + "+\t\telse if(entry->smbus.size == I2C_SMBUS_BLOCK_PROC_CALL) {\n" "+\t\t\tunsigned char *data = entry->smbus.data->block;\n" "+\t\t\ti2c_smbus_add_pec(entry->smbus.addr,\n" "+\t\t\t\t\t entry->smbus.command,\n" @@ -601,10 +604,11 @@ "+\t\t\t\t\t entry->smbus.data);\n" "+\t\t\tentry->partial = data[data[0] + 1];\n" "+\t\t\tentry->smbus.size = I2C_SMBUS_BLOCK_PROC_CALL_PEC;\n" - "+\t\t} else if(entry->smbus.read_write = I2C_SMBUS_WRITE &&\n" + "+\t\t} else if(entry->smbus.read_write == I2C_SMBUS_WRITE &&\n" "+\t\t entry->smbus.size != I2C_SMBUS_QUICK &&\n" "+\t\t entry->smbus.size != I2C_SMBUS_I2C_BLOCK_DATA)\n" - "+\t\t\tentry->smbus.size +\t\t\t\ti2c_smbus_add_pec(entry->smbus.addr,\n" + "+\t\t\tentry->smbus.size =\n" + "+\t\t\t\ti2c_smbus_add_pec(entry->smbus.addr,\n" "+\t\t\t\t\t\t entry->smbus.command,\n" "+\t\t\t\t\t\t entry->smbus.size,\n" "+\t\t\t\t\t\t entry->smbus.data);\n" @@ -657,7 +661,7 @@ "+\t keep the code below somewhat simpler. */\n" "+\tunsigned char *msgbuf0 = entry->msgbuf0;\n" "+\tunsigned char *msgbuf1 = entry->msgbuf1;\n" - "+\tint num = entry->smbus.read_write = I2C_SMBUS_READ?2:1;\n" + "+\tint num = entry->smbus.read_write == I2C_SMBUS_READ?2:1;\n" "+\tstruct i2c_msg *msg = entry->msg;\n" "+\tint i;\n" "+\n" @@ -677,15 +681,15 @@ " \tcase I2C_SMBUS_QUICK:\n" " \t\tmsg[0].len = 0;\n" " \t\t/* Special case: The read/write field is used as data */\n" - "-\t\tmsg[0].flags = flags | (read_write=I2C_SMBUS_READ)?I2C_M_RD:0;\n" + "-\t\tmsg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0;\n" "+\t\tmsg[0].flags = (entry->smbus.flags |\n" - "+\t\t\t\t((entry->smbus.read_write=I2C_SMBUS_READ)\n" + "+\t\t\t\t((entry->smbus.read_write==I2C_SMBUS_READ)\n" "+\t\t\t\t ? I2C_M_RD : 0));\n" " \t\tnum = 1;\n" " \t\tbreak;\n" " \tcase I2C_SMBUS_BYTE:\n" - "-\t\tif (read_write = I2C_SMBUS_READ) {\n" - "+\t\tif (entry->smbus.read_write = I2C_SMBUS_READ) {\n" + "-\t\tif (read_write == I2C_SMBUS_READ) {\n" + "+\t\tif (entry->smbus.read_write == I2C_SMBUS_READ) {\n" " \t\t\t/* Special case: only a read! */\n" "-\t\t\tmsg[0].flags = I2C_M_RD | flags;\n" "+\t\t\tmsg[0].flags = I2C_M_RD | entry->smbus.flags;\n" @@ -693,8 +697,8 @@ " \t\t}\n" " \t\tbreak;\n" " \tcase I2C_SMBUS_BYTE_DATA:\n" - "-\t\tif (read_write = I2C_SMBUS_READ)\n" - "+\t\tif (entry->smbus.read_write = I2C_SMBUS_READ)\n" + "-\t\tif (read_write == I2C_SMBUS_READ)\n" + "+\t\tif (entry->smbus.read_write == I2C_SMBUS_READ)\n" " \t\t\tmsg[1].len = 1;\n" " \t\telse {\n" " \t\t\tmsg[0].len = 2;\n" @@ -703,8 +707,8 @@ " \t\t}\n" " \t\tbreak;\n" " \tcase I2C_SMBUS_WORD_DATA:\n" - "-\t\tif (read_write = I2C_SMBUS_READ)\n" - "+\t\tif (entry->smbus.read_write = I2C_SMBUS_READ)\n" + "-\t\tif (read_write == I2C_SMBUS_READ)\n" + "+\t\tif (entry->smbus.read_write == I2C_SMBUS_READ)\n" " \t\t\tmsg[1].len = 2;\n" " \t\telse {\n" " \t\t\tmsg[0].len=3;\n" @@ -727,9 +731,9 @@ " \t\tbreak;\n" " \tcase I2C_SMBUS_BLOCK_DATA:\n" " \tcase I2C_SMBUS_BLOCK_DATA_PEC:\n" - "-\t\tif (read_write = I2C_SMBUS_READ) {\n" + "-\t\tif (read_write == I2C_SMBUS_READ) {\n" "-\t\t\tdev_err(&adapter->dev, \"Block read not supported \"\n" - "+\t\tif (entry->smbus.read_write = I2C_SMBUS_READ) {\n" + "+\t\tif (entry->smbus.read_write == I2C_SMBUS_READ) {\n" "+\t\t\tdev_err(&adap->dev, \"Block read not supported \"\n" " \t\t\t \"under I2C emulation!\\n\");\n" " \t\t\treturn -1;\n" @@ -745,8 +749,8 @@ "+\t\t\t\t entry->smbus.data->block[0]);\n" " \t\t\t\treturn -1;\n" " \t\t\t}\n" - "-\t\t\tif(size = I2C_SMBUS_BLOCK_DATA_PEC)\n" - "+\t\t\tif(entry->smbus.size = I2C_SMBUS_BLOCK_DATA_PEC)\n" + "-\t\t\tif(size == I2C_SMBUS_BLOCK_DATA_PEC)\n" + "+\t\t\tif(entry->smbus.size == I2C_SMBUS_BLOCK_DATA_PEC)\n" " \t\t\t\t(msg[0].len)++;\n" " \t\t\tfor (i = 1; i <= msg[0].len; i++)\n" "-\t\t\t\tmsgbuf0[i] = data->block[i-1];\n" @@ -760,8 +764,8 @@ " \t\t \"under I2C emulation!\\n\");\n" " \t\treturn -1;\n" " \tcase I2C_SMBUS_I2C_BLOCK_DATA:\n" - "-\t\tif (read_write = I2C_SMBUS_READ) {\n" - "+\t\tif (entry->smbus.read_write = I2C_SMBUS_READ) {\n" + "-\t\tif (read_write == I2C_SMBUS_READ) {\n" + "+\t\tif (entry->smbus.read_write == I2C_SMBUS_READ) {\n" " \t\t\tmsg[1].len = I2C_SMBUS_I2C_BLOCK_MAX;\n" " \t\t} else {\n" "-\t\t\tmsg[0].len = data->block[0] + 1;\n" @@ -793,7 +797,7 @@ "-\tif (i2c_transfer(adapter, msg, num) < 0)\n" "-\t\treturn -1;\n" "-\n" - "-\tif (read_write = I2C_SMBUS_READ)\n" + "-\tif (read_write == I2C_SMBUS_READ)\n" "-\t\tswitch(size) {\n" "-\t\t\tcase I2C_SMBUS_BYTE:\n" "-\t\t\t\tdata->byte = msgbuf0[0];\n" @@ -847,17 +851,17 @@ "-\tif((flags & I2C_CLIENT_PEC) &&\n" "-\t !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) {\n" "-\t\tswpec = 1;\n" - "-\t\tif(read_write = I2C_SMBUS_READ &&\n" - "-\t\t size = I2C_SMBUS_BLOCK_DATA)\n" + "-\t\tif(read_write == I2C_SMBUS_READ &&\n" + "-\t\t size == I2C_SMBUS_BLOCK_DATA)\n" "-\t\t\tsize = I2C_SMBUS_BLOCK_DATA_PEC;\n" - "-\t\telse if(size = I2C_SMBUS_PROC_CALL)\n" + "-\t\telse if(size == I2C_SMBUS_PROC_CALL)\n" "-\t\t\tsize = I2C_SMBUS_PROC_CALL_PEC;\n" - "-\t\telse if(size = I2C_SMBUS_BLOCK_PROC_CALL) {\n" + "-\t\telse if(size == I2C_SMBUS_BLOCK_PROC_CALL) {\n" "-\t\t\ti2c_smbus_add_pec(addr, command,\n" "-\t\t I2C_SMBUS_BLOCK_DATA, data);\n" "-\t\t\tpartial = data->block[data->block[0] + 1];\n" "-\t\t\tsize = I2C_SMBUS_BLOCK_PROC_CALL_PEC;\n" - "-\t\t} else if(read_write = I2C_SMBUS_WRITE &&\n" + "-\t\t} else if(read_write == I2C_SMBUS_WRITE &&\n" "-\t\t size != I2C_SMBUS_QUICK &&\n" "-\t\t size != I2C_SMBUS_I2C_BLOCK_DATA)\n" "-\t\t\tsize = i2c_smbus_add_pec(addr, command, size, data);\n" @@ -874,8 +878,8 @@ "-\n" "-\tif(res >= 0 && swpec &&\n" "-\t size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA &&\n" - "-\t (read_write = I2C_SMBUS_READ || size = I2C_SMBUS_PROC_CALL_PEC ||\n" - "-\t size = I2C_SMBUS_BLOCK_PROC_CALL_PEC)) {\n" + "-\t (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC ||\n" + "-\t size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) {\n" "-\t\tif(i2c_smbus_check_pec(addr, command, size, partial, data))\n" "-\t\t\treturn -1;\n" "+\tstruct i2c_op_q_entry *entry;\n" @@ -949,7 +953,7 @@ "+\tentry->smbus.addr = client->addr;\n" "+\tentry->smbus.flags = client->flags;\n" "+\n" - "+\tif (entry->xfer_type = I2C_OP_SMBUS) {\n" + "+\tif (entry->xfer_type == I2C_OP_SMBUS) {\n" "+\t\ti2c_smbus_format_entry(adap, entry);\n" "+\t\tif (!adap->algo->smbus_start) {\n" "+\t\t\tif (i2c_smbus_emu_format(adap, entry))\n" @@ -967,7 +971,7 @@ "+\n" "+\tspin_lock_irqsave(&adap->q_lock, flags);\n" "+\tlist_add_tail(&entry->link, &adap->q);\n" - "+\tif (adap->q.next = &entry->link) {\n" + "+\tif (adap->q.next == &entry->link) {\n" "+\t\t/* Added to the list head, start it */\n" "+\t\tspin_unlock_irqrestore(&adap->q_lock, flags);\n" "+\t\ti2c_start_entry(adap, entry);\n" @@ -998,7 +1002,8 @@ " EXPORT_SYMBOL(i2c_check_functionality);\n" " \n" "Index: linux-2.6.11-rc2/include/linux/i2c.h\n" - "=================================--- linux-2.6.11-rc2.orig/include/linux/i2c.h\t2005-01-26 15:59:53.000000000 -0600\n" + "===================================================================\n" + "--- linux-2.6.11-rc2.orig/include/linux/i2c.h\t2005-01-26 15:59:53.000000000 -0600\n" "+++ linux-2.6.11-rc2/include/linux/i2c.h\t2005-01-28 08:53:31.000000000 -0600\n" "@@ -32,7 +32,11 @@\n" " #include <linux/types.h>\n" @@ -1344,4 +1349,4 @@ " /* \n" * Data for SMBus Messages -9c565fb2c179cb1800fc0fea8e26e7c06daf1b8381b2b1f5d58fcb585b112300 +479753fabd401a053515e21c5f1a0d42445229bfb11e8ab415384152b064a03b
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.