]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/misc/sti/sti-fifo.c
Merge branch 'omap-fixes'
[linux-2.6-omap-h63xx.git] / drivers / misc / sti / sti-fifo.c
1 /*
2  * STI RX FIFO Support
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation
5  * Written by:  Paul Mundt <paul.mundt@nokia.com> and
6  *              Roman Tereshonkov <roman.tereshonkov@nokia.com>
7  *
8  * This file is subject to the terms and conditions of the GNU General Public
9  * License.  See the file "COPYING" in the main directory of this archive
10  * for more details.
11  */
12 #include <linux/init.h>
13 #include <linux/interrupt.h>
14 #include <linux/err.h>
15 #include <linux/module.h>
16 #include <mach/sti.h>
17
18 #define STI_READ_BUFFER_SIZE    1024
19 #define sti_buf_pos(pos)        ((sti_crb->bufpos + (pos)) % \
20                                  STI_READ_BUFFER_SIZE)
21
22 static struct sti_cycle_buffer {
23         int bufpos;
24         int datalen;
25         unsigned char *buf;
26 } *sti_crb;
27
28 /**
29  * sti_read_packet - STI read packet (read an entire STI packet)
30  * @buf: Buffer to store the packet.
31  * @maxsize: Maximum size requested.
32  *
33  * This reads in a single completed STI packet from the RX FIFOs and
34  * places it in @buf for further processing.
35  *
36  * The return value is < 0 on error, and >= 0 for the number of bytes
37  * actually read. As per the STI specification, we require a 0xC1 to
38  * indicate the end of the packet, and we don't return the packet until
39  * we've read the entire thing in.
40  *
41  * Due to the size of the FIFOs, it's unrealistic to constantly drain
42  * this for 1 or 2 bytes at a time, so we assemble it here and return
43  * the whole thing.
44  */
45 int sti_read_packet(unsigned char *buf, int maxsize)
46 {
47         unsigned int pos;
48
49         if (unlikely(!buf))
50                 return -EINVAL;
51         if (!sti_crb->datalen)
52                 return 0;
53
54         pos = sti_buf_pos(sti_crb->datalen - 1);
55         /* End of packet */
56         if (sti_crb->buf[pos] == 0xC1) {
57                 int i;
58
59                 for (i = 0; i < sti_crb->datalen && i < maxsize; i++) {
60                         pos = sti_buf_pos(i);
61                         buf[i] = sti_crb->buf[pos];
62                 }
63
64                 sti_crb->bufpos = sti_buf_pos(i);
65                 sti_crb->datalen -= i;
66
67                 return i;
68         }
69
70         return 0;
71 }
72 EXPORT_SYMBOL(sti_read_packet);
73
74 static void sti_fifo_irq(unsigned long arg)
75 {
76         /* If there is data read it */
77         while (!(sti_readl(STI_RX_STATUS) & STI_RXFIFO_EMPTY)) {
78                 unsigned int pos = sti_buf_pos(sti_crb->datalen);
79
80                 sti_crb->buf[pos] = sti_readl(STI_RX_DR);
81                 sti_crb->datalen++;
82         }
83
84         sti_ack_irq(STI_RX_INT);
85 }
86
87 static int __init sti_fifo_init(void)
88 {
89         unsigned int size;
90         int ret;
91
92         size = sizeof(struct sti_cycle_buffer) + STI_READ_BUFFER_SIZE;
93         sti_crb = kmalloc(size, GFP_KERNEL);
94         if (!sti_crb)
95                 return -ENOMEM;
96
97         sti_crb->bufpos = sti_crb->datalen = 0;
98         sti_crb->buf = (unsigned char *)(sti_crb + sizeof(*sti_crb));
99
100         ret = sti_request_irq(STI_RX_INT, sti_fifo_irq, 0);
101         if (ret != 0)
102                 kfree(sti_crb);
103
104         return ret;
105 }
106
107 static void __exit sti_fifo_exit(void)
108 {
109         sti_free_irq(STI_RX_INT);
110         kfree(sti_crb);
111 }
112
113 module_init(sti_fifo_init);
114 module_exit(sti_fifo_exit);
115
116 MODULE_AUTHOR("Paul Mundt, Roman Tereshonkov");
117 MODULE_LICENSE("GPL");