summaryrefslogtreecommitdiff
path: root/skey.c
blob: d9bdef9ef790ec6203ffb868a01891d98d2741dd (plain)
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");