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
|
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/timer.h>
/*
* Unsigned ints containing the BCM pin numbers for the pins used, __initdata
* helps with the loading and unloading of data in memory
*/
static __initdata unsigned int column_pins[10] = {10, 24, 23, 22, 27, 18, 17, 15, 14, 4};
static __initdata unsigned int row_pins[3] = {3, 6, 5};
/*
* GPIO labels
*/
static __initdata char * clabels[10] = {"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9",};
static __initdata char * rlabels[3] = {"R0", "R1", "R2"};
/*
* timer period in ms and timer struct
*/
static struct timer_list update_timer;
static int update_period = 5;
/*
*This function is called every timer-period to actually read the keyboard
*/
static void skey_update (unsigned long unused) {
printk(KERN_INFO "skey: updated keyboard\n");
//reads the keyboard
int row_index = 0;
int column_index = 0;
while (column_index < 10) {
//sets the column pin high for reading
gpio_set_value(column_pins[column_index],1);
//reads with all the rows
row_index = 0;
while (row_index < 3) {
if (gpio_get_value(row_pins[row_index])) {
printk(KERN_INFO "skey: key pressed at column %d, row %d\n", column_index, row_index);
}
row_index++;
}
//sets the row pin low
gpio_set_value(column_pins[column_index],0);
column_index++;
}
//updates the timer
mod_timer(&update_timer, jiffies + msecs_to_jiffies(update_period));
}
/*
* This function is called when the module is loaded
* __init functions similar to __initdata
*/
static int __init skey_init (void) {
printk(KERN_INFO "skey: module initiating...\n");
int i = 0;
//claims the column pins
while (i < 10) {
//checks to see if the gpios are valid
if (!gpio_is_valid(column_pins[i])) {
printk(KERN_ALERT "skey: column_pins[%d], BCM %d request invalid\n", i, column_pins[i]);
return -EINVAL;
}
//requests access of the GPIO
if (gpio_request_one(column_pins[i], GPIOF_OUT_INIT_LOW ,clabels[i])) {
printk(KERN_ALERT "skey: column_pins[%d], BCM %d request failed\n", i, column_pins[i]);
return -EINVAL;
}
i++;
}
//ditto for row pins
int j = 0;
while (j < 3) {
//checks to see if the gpios are valid
if (!gpio_is_valid(row_pins[j])) {
printk(KERN_ALERT "skey: row_pins[%d], BCM %d request invalid\n", j, row_pins[j]);
return -EINVAL;
}
//requests access of the GPIO
if (gpio_request_one(row_pins[j], GPIOF_DIR_IN ,rlabels[j])) {
printk(KERN_ALERT "skey: row_pins[%d], BCM %d request failed\n", j, row_pins[j]);
return -EINVAL;
}
j++;
}
//sets up timer for keyboard read function
setup_timer(&update_timer, skey_update, 0);
if (mod_timer(&update_timer, jiffies + msecs_to_jiffies(update_period))) {
printk(KERN_ALERT "skey: failed to set up timer\n");
return -EINVAL;
}
printk(KERN_INFO "skey: module finished initiating\n");
return 0;
}
/*
* This function is called when the module is unloaded
*
*/
static void __exit skey_exit (void) {
printk(KERN_INFO "skey: module exiting...\n");
//frees column and row pins
int i = 0;
while (i < 10) {
gpio_free(column_pins[i]);
i++;
}
int j = 0;
while (j < 3) {
gpio_free(row_pins[j]);
j++;
}
//deletes update timer
del_timer(&update_timer);
printk(KERN_INFO "skey: module exited\n");
return;
}
/*
* Registers the init and exit functions
*/
module_init(skey_init);
module_exit(skey_exit);
/*
* registers module metadata
*/
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Haoran S. Diao <1339802534.kk@gmail.com>");
MODULE_DESCRIPTION("Driver for the omnicom switch keyboard");
/*
*this sets the name of device files used by this module, this is used
*when the kernel makes devices automatically
*/
MODULE_SUPPORTED_DEVICE("skeydev");
|