diff options
author | Rob Herring <r.herring@freescale.com> | 2009-10-19 14:43:19 -0500 |
---|---|---|
committer | Rob Herring <r.herring@freescale.com> | 2009-10-26 16:57:04 -0500 |
commit | 460b55880e47a98943f5072bc03ffcfcc8a40a14 (patch) | |
tree | 5690552665f0b7843e6552e4d5fe7b63cbc78f51 /drivers/i2c-slave/i2c_slave_ring_buffer.c | |
parent | 40abba66d676c6c7aff57a5fbd1345974c90b2fe (diff) |
ENGR00117389 Port 5.0.0 release to 2.6.31
This is i.MX BSP 5.0.0 release ported to 2.6.31
Signed-off-by: Rob Herring <r.herring@freescale.com>
Signed-off-by: Alan Tull <r80115@freescale.com>
Signed-off-by: Xinyu Chen <xinyu.chen@freescale.com>
Diffstat (limited to 'drivers/i2c-slave/i2c_slave_ring_buffer.c')
-rw-r--r-- | drivers/i2c-slave/i2c_slave_ring_buffer.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/drivers/i2c-slave/i2c_slave_ring_buffer.c b/drivers/i2c-slave/i2c_slave_ring_buffer.c new file mode 100644 index 000000000000..4a55e099235f --- /dev/null +++ b/drivers/i2c-slave/i2c_slave_ring_buffer.c @@ -0,0 +1,185 @@ +/* + * Copyright 2007-2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/slab.h> +#include <linux/hardirq.h> +#include "i2c_slave_ring_buffer.h" + +i2c_slave_ring_buffer_t *i2c_slave_rb_alloc(int size) +{ + i2c_slave_ring_buffer_t *ring_buf; + + ring_buf = + (i2c_slave_ring_buffer_t *) kzalloc(sizeof(i2c_slave_ring_buffer_t), + GFP_KERNEL); + if (!ring_buf) { + pr_debug("%s: alloc ring_buf error\n", __func__); + goto error; + } + + ring_buf->buffer = kmalloc(size, GFP_KERNEL); + if (!ring_buf->buffer) { + pr_debug("%s: alloc buffer error\n", __func__); + goto error1; + } + + ring_buf->total = size; + + ring_buf->lock = __SPIN_LOCK_UNLOCKED(ring_buf->lock); + return ring_buf; + + error1: + kfree(ring_buf); + error: + return NULL; +} + +void i2c_slave_rb_release(i2c_slave_ring_buffer_t *ring) +{ + unsigned long flags; + + spin_lock_irqsave(ring->lock, flags); + kfree(ring->buffer); + spin_unlock_irqrestore(ring->lock, flags); + kfree(ring); +} + +int i2c_slave_rb_produce(i2c_slave_ring_buffer_t *ring, int num, char *data) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(ring->lock, flags); + + if (ring->start < ring->end) { + if ((ring->start + num) < ring->end) { /*have enough space */ + memcpy(&ring->buffer[ring->start], data, num); + ring->start += num; + ret = num; + } else { /*space not enough, just copy part of it. */ + ret = ring->end - ring->start; + memcpy(&ring->buffer[ring->start], data, ret); + ring->start += ret; + ring->full = 1; + } + } else if (ring->start >= ring->end && !ring->full) { + if (ring->start + num <= ring->total) { /*space enough */ + ret = num; + memcpy(&ring->buffer[ring->start], data, ret); + ring->start += ret; + } else { /*turn ring->start around */ + ret = ring->total - ring->start; + memcpy(&ring->buffer[ring->start], data, ret); + ring->start = 0; + num -= ret; + data += ret; + if (num < ring->end) { /*space enough */ + ret += num; + memcpy(&ring->buffer[ring->start], data, num); + } else { /*space not enough, just copy part of it. */ + ret += ring->end; + memcpy(&ring->buffer[ring->start], data, + ring->end); + ring->start = ring->end; + ring->full = 1; + } + } + } else { /*(ring->data == ring->end) && ring->full ) : full */ + ret = 0; + } + + spin_unlock_irqrestore(ring->lock, flags); + return ret; +} + +int i2c_slave_rb_consume(i2c_slave_ring_buffer_t *ring, int num, char *data) +{ + int ret; + unsigned long flags; + spin_lock_irqsave(ring->lock, flags); + if (num <= 0) { + ret = 0; + goto out; + } + + if (ring->start > ring->end) { + if (num <= ring->start - ring->end) { /*enough */ + ret = num; + memcpy(data, &ring->buffer[ring->end], ret); + ring->end += ret; + } else { /*not enough */ + ret = ring->start - ring->end; + memcpy(data, &ring->buffer[ring->end], ret); + ring->end += ret; + } + } else if (ring->start < ring->end || ring->full) { + if (num <= ring->total - ring->end) { + ret = ring->total - ring->end; + memcpy(data, &ring->buffer[ring->end], ret); + ring->end += ret; + } else if (num <= ring->total - ring->end + ring->start) { + ret = ring->total - ring->end; + memcpy(data, &ring->buffer[ring->end], ret); + ring->end = 0; + data += ret; + num -= ret; + memcpy(data, &ring->buffer[ring->end], num); + ring->end = num; + ret += num; + } else { + ret = ring->total - ring->end; + memcpy(data, &ring->buffer[ring->end], ret); + ring->end = 0; + data += ret; + num -= ret; + memcpy(data, &ring->buffer[ring->end], ring->start); + ring->end = ring->start; + ret += ring->start; + } + ring->full = 0; + } else { /*empty */ + ret = 0; + } + + out: + spin_unlock_irqrestore(ring->lock, flags); + + return ret; +} + +int i2c_slave_rb_num(i2c_slave_ring_buffer_t *ring) +{ + int ret; + unsigned long flags; + spin_lock_irqsave(ring->lock, flags); + if (ring->start > ring->end) { + ret = ring->start - ring->end; + } else if (ring->start < ring->end) { + ret = ring->total - ring->end + ring->start; + } else if (ring->full) { + ret = ring->total; + } else { + ret = 0; + } + spin_unlock_irqrestore(ring->lock, flags); + return ret; +} + +void i2c_slave_rb_clear(i2c_slave_ring_buffer_t *ring) +{ + unsigned long flags; + spin_lock_irqsave(ring->lock, flags); + + ring->start = ring->end = 0; + ring->full = 0; + spin_unlock_irqrestore(ring->lock, flags); +} |