1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
|
--- linux/arch/mips/au1000/mtx-2/Makefile.org 2006-05-29 10:45:47.702096500 +0200
+++ linux/arch/mips/au1000/mtx-2/Makefile 2006-05-29 10:46:05.643217750 +0200
@@ -15,6 +15,6 @@
O_TARGET := mtx-2.o
-obj-y := init.o board_setup.o irqmap.o slic.o lcd.o
+obj-y := init.o board_setup.o irqmap.o slic.o lcd.o pollbtn.o
include $(TOPDIR)/Rules.make
--- linux/arch/mips/au1000/mtx-2/pollbtn.c.org 1970-01-01 01:00:00.000000000 +0100
+++ linux/arch/mips/au1000/mtx-2/pollbtn.c 2006-05-29 10:42:53.071182750 +0200
@@ -0,0 +1,233 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/uaccess.h>
+#include <asm/au1000.h>
+
+static int mtx_btn_ms = 100;
+MODULE_PARM(mtx_btn_ms, "i");
+MODULE_PARM_DESC(mtx_btn_ms, "The time in ms to wait between polls (default 100)");
+
+/* Bitposition of button in GPIO-byte */
+#define SB2_BTNPOWER_GPIO (11)
+#define SB2_BTNRESET_GPIO (12) /* The MTX-1 Button is attached to GPIO207. */
+#define SB2_BTNCONNECT_GPIO (13)
+#define SB2_BTNDISPLAY_GPIO (14)
+#define SB2_BTN_4_GPIO (15)
+
+/* IRQs for buttons */
+#define SB2_BTN_IRQ (AU1500_GPIO_208_218)
+
+/* Pinstate of GPIO-port */
+#define SB2_BTN_PINSTATE (GPIO2_PINSTATE)
+
+/* Direction of GPIO-register */
+#define SB2_BTN_DIR (GPIO2_DIR)
+
+static struct timer_list check_button_timer;
+static int restart_timer = 1;
+
+#define MAX_ACCESS 4
+struct priv_data {
+ char in_use;
+ char state_changed;
+ char last_state;
+ char current_state;
+ wait_queue_head_t btn_wait_queue;
+};
+static struct priv_data priv_data[MAX_ACCESS];
+
+/*---------[ Hardware Functions ]-----------------*/
+
+static void mtx_initbuttons (void)
+{
+ int i;
+ for (i = 11; i <= 15; ++i) {
+ /* Clear dir-bit to configure GPIO as input */
+ au_writel (au_readl(SB2_BTN_DIR) & ~(1 << i), SB2_BTN_DIR);
+ }
+}
+
+static unsigned char lval=0, cval = 0;
+
+static void check_buttons (unsigned long timer_task) {
+ int i;
+ cval = (au_readl(GPIO2_PINSTATE) >> 11) & 0x1f;
+ if (lval != cval) {
+ for (i=0; i<MAX_ACCESS; ++i) {
+ if (priv_data[i].in_use == 1 && cval != priv_data[i].last_state) {
+ priv_data[i].current_state = cval;
+ priv_data[i].state_changed = 1;
+ wake_up_interruptible(&priv_data[i].btn_wait_queue);
+ }
+ }
+ lval = cval;
+ }
+
+ if ( restart_timer ) {
+ check_button_timer.expires += mtx_btn_ms/10;
+ add_timer(&check_button_timer);
+ }
+}
+
+/*---------[ File Functions ]-----------------*/
+
+static int mtxsysbtn_minor = -1, is_inuse = 0;
+
+static int mtxsysbtn_open (struct inode *inode, struct file *file)
+{
+ struct priv_data *pd=NULL;
+ int i;
+ if (MINOR(inode->i_rdev) != mtxsysbtn_minor)
+ return -ENODEV;
+
+ MOD_INC_USE_COUNT;
+
+ // search an unused priv_data
+ for (i=0; i<MAX_ACCESS; ++i) {
+ if (priv_data[i].in_use == 0 ) {
+ priv_data[i].last_state = cval;
+ priv_data[i].current_state = cval;
+ priv_data[i].state_changed = 0;
+ pd = file->private_data = &priv_data[i];
+ init_waitqueue_head(&pd->btn_wait_queue);
+ priv_data[i].in_use = 1;
+ break;
+ }
+ }
+
+ if (file->private_data==NULL) {
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int mtxsysbtn_release (struct inode *inode, struct file *file)
+{
+ struct priv_data *pd = (struct priv_data*)file->private_data;
+ if ( pd ) {
+ pd->in_use = 0;
+ file->private_data=NULL;
+ }
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static ssize_t mtxsysbtn_read (struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+ struct priv_data *pd = (struct priv_data*)file->private_data;
+ if (count < 1 || !pd )
+ return -EINVAL;
+ if (!pd->state_changed) {
+ interruptible_sleep_on(&pd->btn_wait_queue);
+ }
+ char chg = pd->current_state ^ pd->last_state;
+ char chgack=0;
+
+ int r[5],i,c=0;
+ for (i = 0; i<5; i++) {
+ if ( chg & (1 << i)) {
+ r[c] = i+1;
+ if ((pd->current_state & (1 << i)) == 0)
+ r[c] |= 0x80;
+ chgack |= (1<<i);
+ if ( ++c > count ) {
+ break;
+ }
+ }
+ }
+ pd->last_state ^= chgack;
+
+ if ( pd->last_state == pd->current_state ) {
+ pd->state_changed = 0;
+ }
+
+ if (copy_to_user(buf, r, c)) {
+ return -EFAULT;
+ }
+
+ return c;
+}
+
+static unsigned int mtxsysbtn_poll (struct file *file, poll_table * wait)
+{
+ unsigned int mask = 0;
+ struct priv_data *pd = (struct priv_data*)file->private_data;
+ if (!pd)
+ return -EINVAL;
+
+ poll_wait(file, &pd->btn_wait_queue, wait);
+ if (pd->state_changed) /* state changed since last time. */
+ mask |= POLLIN | POLLRDNORM;
+ return mask;
+}
+
+/*---------[ Module stuff ]-----------------*/
+
+static struct file_operations mtxsysbtn_fops = {
+ .owner = THIS_MODULE,
+ .read = mtxsysbtn_read,
+ .poll = mtxsysbtn_poll,
+ .open = mtxsysbtn_open,
+ .release = mtxsysbtn_release
+};
+
+static struct miscdevice mtxsysbtn_miscdev = {
+ MISC_DYNAMIC_MINOR /* SYSBTN_MINOR */ ,
+ "btn",
+ &mtxsysbtn_fops
+};
+
+void __exit cleanup_mtx_sysbtn (void)
+{
+ restart_timer = 0;
+ del_timer_sync(&check_button_timer);
+ is_inuse = 1;
+ misc_deregister(&mtxsysbtn_miscdev);
+ is_inuse = 0;
+}
+
+int __init init_mtx_sysbtn (void)
+{
+ memset(priv_data, 0, sizeof(struct priv_data)*MAX_ACCESS);
+ init_timer(&check_button_timer);
+ check_button_timer.function = check_buttons;
+ check_button_timer.data = 0;
+ check_button_timer.expires = jiffies+100;
+ add_timer(&check_button_timer);
+
+ is_inuse = 1;
+ mtx_initbuttons();
+ if (misc_register(&mtxsysbtn_miscdev) >= 0) {
+ mtxsysbtn_minor = mtxsysbtn_miscdev.minor;
+ printk(KERN_INFO "MTX-1 System Button minor: %d\n",
+ mtxsysbtn_miscdev.minor);
+ if (1) {
+ is_inuse = 0;
+ return 0;
+ }
+
+ misc_deregister(&mtxsysbtn_miscdev);
+ }
+ is_inuse = 0;
+ return 1;
+}
+
+module_init(init_mtx_sysbtn);
+module_exit(cleanup_mtx_sysbtn);
+
+MODULE_AUTHOR("Simon Krahnke");
+MODULE_DESCRIPTION("Driver for MTX buttons");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
|