summaryrefslogtreecommitdiff
path: root/skey.c
blob: 2d5b4aa0fc658098e559ff67069df75a5decb518 (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
130
131
132
133
134
135
#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;
		}
		if (gpio_direction_output(column_pins[i], 0)) {
			printk(KERN_ALERT "skey: column_pins[%d], BCM %d, set output failed\n",i, column_pins[i]);
		}
		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;
		}
		if (gpio_direction_input(row_pins[j])) {
			printk(KERN_ALERT "skey: row_pins[%d], BCM %d, set output failed\n",j, row_pins[j]);
		}
		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");