OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [input/] [keyboard/] [locomokbd.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *  Copyright (c) 2005 John Lenz
3
 *
4
 * Based on from xtkbd.c
5
 */
6
 
7
/*
8
 * LoCoMo keyboard driver for Linux/ARM
9
 */
10
 
11
/*
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
 *
26
 */
27
 
28
#include <linux/slab.h>
29
#include <linux/module.h>
30
#include <linux/init.h>
31
#include <linux/input.h>
32
#include <linux/delay.h>
33
#include <linux/device.h>
34
#include <linux/interrupt.h>
35
#include <linux/ioport.h>
36
 
37
#include <asm/hardware/locomo.h>
38
#include <asm/irq.h>
39
 
40
MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
41
MODULE_DESCRIPTION("LoCoMo keyboard driver");
42
MODULE_LICENSE("GPL");
43
 
44
#define LOCOMOKBD_NUMKEYS       128
45
 
46
#define KEY_ACTIVITY            KEY_F16
47
#define KEY_CONTACT             KEY_F18
48
#define KEY_CENTER              KEY_F15
49
 
50
static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
51
        0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0,                          /* 0 - 9 */
52
        0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT,                  /* 10 - 19 */
53
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                             /* 20 - 29 */
54
        0, 0, 0, KEY_CENTER, 0, KEY_MAIL, 0, 0, 0, 0,                           /* 30 - 39 */
55
        0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RIGHT,                                    /* 40 - 49 */
56
        KEY_UP, KEY_LEFT, 0, 0, KEY_P, 0, KEY_O, KEY_I, KEY_Y, KEY_T,              /* 50 - 59 */
57
        KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_ENTER, 0, 0,                  /* 60 - 69 */
58
        KEY_BACKSPACE, 0, KEY_L, KEY_U, KEY_H, KEY_R, KEY_D, KEY_Q, 0, 0,  /* 70 - 79 */
59
        0, 0, 0, 0, 0, 0, KEY_ENTER, KEY_RIGHTSHIFT, KEY_K, KEY_J,            /* 80 - 89 */
60
        KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0,                         /* 90 - 99 */
61
        0, 0, KEY_DOT, 0, KEY_COMMA, KEY_N, KEY_B, KEY_C, KEY_Z, KEY_A,            /* 100 - 109 */
62
        KEY_LEFTSHIFT, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, 0, 0,             /* 110 - 119 */
63
        KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0                /* 120 - 128 */
64
};
65
 
66
#define KB_ROWS                 16
67
#define KB_COLS                 8
68
#define KB_ROWMASK(r)           (1 << (r))
69
#define SCANCODE(c,r)           ( ((c)<<4) + (r) + 1 )
70
#define NR_SCANCODES            128
71
 
72
#define KB_DELAY                8
73
#define SCAN_INTERVAL           (HZ/10)
74
#define LOCOMOKBD_PRESSED       1
75
 
76
struct locomokbd {
77
        unsigned char keycode[LOCOMOKBD_NUMKEYS];
78
        struct input_dev *input;
79
        char phys[32];
80
 
81
        struct locomo_dev *ldev;
82
        unsigned long base;
83
        spinlock_t lock;
84
 
85
        struct timer_list timer;
86
};
87
 
88
/* helper functions for reading the keyboard matrix */
89
static inline void locomokbd_charge_all(unsigned long membase)
90
{
91
        locomo_writel(0x00FF, membase + LOCOMO_KSC);
92
}
93
 
94
static inline void locomokbd_activate_all(unsigned long membase)
95
{
96
        unsigned long r;
97
 
98
        locomo_writel(0, membase + LOCOMO_KSC);
99
        r = locomo_readl(membase + LOCOMO_KIC);
100
        r &= 0xFEFF;
101
        locomo_writel(r, membase + LOCOMO_KIC);
102
}
103
 
104
static inline void locomokbd_activate_col(unsigned long membase, int col)
105
{
106
        unsigned short nset;
107
        unsigned short nbset;
108
 
109
        nset = 0xFF & ~(1 << col);
110
        nbset = (nset << 8) + nset;
111
        locomo_writel(nbset, membase + LOCOMO_KSC);
112
}
113
 
114
static inline void locomokbd_reset_col(unsigned long membase, int col)
115
{
116
        unsigned short nbset;
117
 
118
        nbset = ((0xFF & ~(1 << col)) << 8) + 0xFF;
119
        locomo_writel(nbset, membase + LOCOMO_KSC);
120
}
121
 
122
/*
123
 * The LoCoMo keyboard only generates interrupts when a key is pressed.
124
 * So when a key is pressed, we enable a timer.  This timer scans the
125
 * keyboard, and this is how we detect when the key is released.
126
 */
127
 
128
/* Scan the hardware keyboard and push any changes up through the input layer */
129
static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
130
{
131
        unsigned int row, col, rowd, scancode;
132
        unsigned long flags;
133
        unsigned int num_pressed;
134
        unsigned long membase = locomokbd->base;
135
 
136
        spin_lock_irqsave(&locomokbd->lock, flags);
137
 
138
        locomokbd_charge_all(membase);
139
 
140
        num_pressed = 0;
141
        for (col = 0; col < KB_COLS; col++) {
142
 
143
                locomokbd_activate_col(membase, col);
144
                udelay(KB_DELAY);
145
 
146
                rowd = ~locomo_readl(membase + LOCOMO_KIB);
147
                for (row = 0; row < KB_ROWS; row++) {
148
                        scancode = SCANCODE(col, row);
149
                        if (rowd & KB_ROWMASK(row)) {
150
                                num_pressed += 1;
151
                                input_report_key(locomokbd->input, locomokbd->keycode[scancode], 1);
152
                        } else {
153
                                input_report_key(locomokbd->input, locomokbd->keycode[scancode], 0);
154
                        }
155
                }
156
                locomokbd_reset_col(membase, col);
157
        }
158
        locomokbd_activate_all(membase);
159
 
160
        input_sync(locomokbd->input);
161
 
162
        /* if any keys are pressed, enable the timer */
163
        if (num_pressed)
164
                mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL);
165
 
166
        spin_unlock_irqrestore(&locomokbd->lock, flags);
167
}
168
 
169
/*
170
 * LoCoMo keyboard interrupt handler.
171
 */
172
static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
173
{
174
        struct locomokbd *locomokbd = dev_id;
175
        /** wait chattering delay **/
176
        udelay(100);
177
 
178
        locomokbd_scankeyboard(locomokbd);
179
 
180
        return IRQ_HANDLED;
181
}
182
 
183
/*
184
 * LoCoMo timer checking for released keys
185
 */
186
static void locomokbd_timer_callback(unsigned long data)
187
{
188
        struct locomokbd *locomokbd = (struct locomokbd *) data;
189
        locomokbd_scankeyboard(locomokbd);
190
}
191
 
192
static int locomokbd_probe(struct locomo_dev *dev)
193
{
194
        struct locomokbd *locomokbd;
195
        struct input_dev *input_dev;
196
        int i, err;
197
 
198
        locomokbd = kzalloc(sizeof(struct locomokbd), GFP_KERNEL);
199
        input_dev = input_allocate_device();
200
        if (!locomokbd || !input_dev) {
201
                err = -ENOMEM;
202
                goto err_free_mem;
203
        }
204
 
205
        /* try and claim memory region */
206
        if (!request_mem_region((unsigned long) dev->mapbase,
207
                                dev->length,
208
                                LOCOMO_DRIVER_NAME(dev))) {
209
                err = -EBUSY;
210
                printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n");
211
                goto err_free_mem;
212
        }
213
 
214
        locomokbd->ldev = dev;
215
        locomo_set_drvdata(dev, locomokbd);
216
 
217
        locomokbd->base = (unsigned long) dev->mapbase;
218
 
219
        spin_lock_init(&locomokbd->lock);
220
 
221
        init_timer(&locomokbd->timer);
222
        locomokbd->timer.function = locomokbd_timer_callback;
223
        locomokbd->timer.data = (unsigned long) locomokbd;
224
 
225
        locomokbd->input = input_dev;
226
        strcpy(locomokbd->phys, "locomokbd/input0");
227
 
228
        input_dev->name = "LoCoMo keyboard";
229
        input_dev->phys = locomokbd->phys;
230
        input_dev->id.bustype = BUS_HOST;
231
        input_dev->id.vendor = 0x0001;
232
        input_dev->id.product = 0x0001;
233
        input_dev->id.version = 0x0100;
234
        input_dev->dev.parent = &dev->dev;
235
 
236
        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
237
        input_dev->keycode = locomokbd->keycode;
238
        input_dev->keycodesize = sizeof(unsigned char);
239
        input_dev->keycodemax = ARRAY_SIZE(locomokbd_keycode);
240
 
241
        memcpy(locomokbd->keycode, locomokbd_keycode, sizeof(locomokbd->keycode));
242
        for (i = 0; i < LOCOMOKBD_NUMKEYS; i++)
243
                set_bit(locomokbd->keycode[i], input_dev->keybit);
244
        clear_bit(0, input_dev->keybit);
245
 
246
        /* attempt to get the interrupt */
247
        err = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd);
248
        if (err) {
249
                printk(KERN_ERR "locomokbd: Can't get irq for keyboard\n");
250
                goto err_release_region;
251
        }
252
 
253
        err = input_register_device(locomokbd->input);
254
        if (err)
255
                goto err_free_irq;
256
 
257
        return 0;
258
 
259
 err_free_irq:
260
        free_irq(dev->irq[0], locomokbd);
261
 err_release_region:
262
        release_mem_region((unsigned long) dev->mapbase, dev->length);
263
        locomo_set_drvdata(dev, NULL);
264
 err_free_mem:
265
        input_free_device(input_dev);
266
        kfree(locomokbd);
267
 
268
        return err;
269
}
270
 
271
static int locomokbd_remove(struct locomo_dev *dev)
272
{
273
        struct locomokbd *locomokbd = locomo_get_drvdata(dev);
274
 
275
        free_irq(dev->irq[0], locomokbd);
276
 
277
        del_timer_sync(&locomokbd->timer);
278
 
279
        input_unregister_device(locomokbd->input);
280
        locomo_set_drvdata(dev, NULL);
281
 
282
        release_mem_region((unsigned long) dev->mapbase, dev->length);
283
 
284
        kfree(locomokbd);
285
 
286
        return 0;
287
}
288
 
289
static struct locomo_driver keyboard_driver = {
290
        .drv = {
291
                .name = "locomokbd"
292
        },
293
        .devid  = LOCOMO_DEVID_KEYBOARD,
294
        .probe  = locomokbd_probe,
295
        .remove = locomokbd_remove,
296
};
297
 
298
static int __init locomokbd_init(void)
299
{
300
        return locomo_driver_register(&keyboard_driver);
301
}
302
 
303
static void __exit locomokbd_exit(void)
304
{
305
        locomo_driver_unregister(&keyboard_driver);
306
}
307
 
308
module_init(locomokbd_init);
309
module_exit(locomokbd_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.