X-Git-Url: http://www.pilppa.org/gitweb/gitweb.cgi?p=linux-2.6-omap-h63xx.git;a=blobdiff_plain;f=drivers%2Fmisc%2Fsti%2Fsti-fifo.c;fp=drivers%2Fmisc%2Fsti%2Fsti-fifo.c;h=1ea5b1896fb29decd1f5f7e1c1d093b6a0949274;hp=0000000000000000000000000000000000000000;hb=0d5f2216edfeb9904e0d6512f803b0f93871baaf;hpb=14fc69723d3442ef46f8f82b3f481e82f06a346d diff --git a/drivers/misc/sti/sti-fifo.c b/drivers/misc/sti/sti-fifo.c new file mode 100644 index 00000000000..1ea5b1896fb --- /dev/null +++ b/drivers/misc/sti/sti-fifo.c @@ -0,0 +1,117 @@ +/* + * STI RX FIFO Support + * + * Copyright (C) 2005, 2006 Nokia Corporation + * Written by: Paul Mundt and + * Roman Tereshonkov + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include + +#define STI_READ_BUFFER_SIZE 1024 +#define sti_buf_pos(pos) ((sti_crb->bufpos + (pos)) % \ + STI_READ_BUFFER_SIZE) + +static struct sti_cycle_buffer { + int bufpos; + int datalen; + unsigned char *buf; +} *sti_crb; + +/** + * sti_read_packet - STI read packet (read an entire STI packet) + * @buf: Buffer to store the packet. + * @maxsize: Maximum size requested. + * + * This reads in a single completed STI packet from the RX FIFOs and + * places it in @buf for further processing. + * + * The return value is < 0 on error, and >= 0 for the number of bytes + * actually read. As per the STI specification, we require a 0xC1 to + * indicate the end of the packet, and we don't return the packet until + * we've read the entire thing in. + * + * Due to the size of the FIFOs, it's unrealistic to constantly drain + * this for 1 or 2 bytes at a time, so we assemble it here and return + * the whole thing. + */ +int sti_read_packet(unsigned char *buf, int maxsize) +{ + unsigned int pos; + + if (unlikely(!buf)) + return -EINVAL; + if (!sti_crb->datalen) + return 0; + + pos = sti_buf_pos(sti_crb->datalen - 1); + /* End of packet */ + if (sti_crb->buf[pos] == 0xC1) { + int i; + + for (i = 0; i < sti_crb->datalen && i < maxsize; i++) { + pos = sti_buf_pos(i); + buf[i] = sti_crb->buf[pos]; + } + + sti_crb->bufpos = sti_buf_pos(i); + sti_crb->datalen -= i; + + return i; + } + + return 0; +} +EXPORT_SYMBOL(sti_read_packet); + +static void sti_fifo_irq(unsigned long arg) +{ + /* If there is data read it */ + while (!(sti_readl(STI_RX_STATUS) & STI_RXFIFO_EMPTY)) { + unsigned int pos = sti_buf_pos(sti_crb->datalen); + + sti_crb->buf[pos] = sti_readl(STI_RX_DR); + sti_crb->datalen++; + } + + sti_ack_irq(STI_RX_INT); +} + +static int __init sti_fifo_init(void) +{ + unsigned int size; + int ret; + + size = sizeof(struct sti_cycle_buffer) + STI_READ_BUFFER_SIZE; + sti_crb = kmalloc(size, GFP_KERNEL); + if (!sti_crb) + return -ENOMEM; + + sti_crb->bufpos = sti_crb->datalen = 0; + sti_crb->buf = (unsigned char *)(sti_crb + sizeof(*sti_crb)); + + ret = sti_request_irq(STI_RX_INT, sti_fifo_irq, 0); + if (ret != 0) + kfree(sti_crb); + + return ret; +} + +static void __exit sti_fifo_exit(void) +{ + sti_free_irq(STI_RX_INT); + kfree(sti_crb); +} + +module_init(sti_fifo_init); +module_exit(sti_fifo_exit); + +MODULE_AUTHOR("Paul Mundt, Roman Tereshonkov"); +MODULE_LICENSE("GPL");