Revision f024710b
ID | f024710be92a87d10ad8c50d0784a7e1f3f4a5fe |
Added actual reads from hardware to encoder.ko
Not yet tested on Gumstix (especially since I don't think we have the
encoders yet).
scout_gumstix/encoder/encoder.c | ||
---|---|---|
5 | 5 |
#include <linux/slab.h> |
6 | 6 |
#include <linux/device.h> |
7 | 7 |
#include <linux/semaphore.h> |
8 |
#include <linux/interrupt.h> |
|
9 |
#include <linux/gpio.h> |
|
8 | 10 |
#include <asm/uaccess.h> |
9 | 11 |
|
10 | 12 |
MODULE_AUTHOR("Tom Mullins"); |
11 | 13 |
MODULE_LICENSE("GPL"); |
12 | 14 |
|
13 |
/* |
|
14 |
* TODO |
|
15 |
* |
|
16 |
* clean up before final move to gumstix |
|
17 |
* add interrupt counting |
|
18 |
* |
|
19 |
*/ |
|
20 |
|
|
21 |
typedef long enc_val_t; |
|
22 |
|
|
23 | 15 |
#define BUF_LEN 20 |
24 | 16 |
#define N_ENCODERS 4 |
25 |
int enc_pins[N_ENCODERS][2] = {{78, 79}, {80, 81}, {82, 83}, {84, 85}}; |
|
17 |
const int enc_pins[N_ENCODERS][2] = {{78, 79}, {80, 81}, {82, 83}, {84, 85}};
|
|
26 | 18 |
struct class *enc_class = NULL; |
27 | 19 |
dev_t first_dev; |
28 | 20 |
|
... | ... | |
32 | 24 |
struct cdev cdev; |
33 | 25 |
struct semaphore sem; |
34 | 26 |
struct device *device; |
27 |
int irq[2]; |
|
35 | 28 |
int status; |
36 |
enc_val_t value;
|
|
29 |
atomic_t value;
|
|
37 | 30 |
dev_t dev; |
38 | 31 |
} |
39 | 32 |
encs[N_ENCODERS]; |
... | ... | |
74 | 67 |
{ |
75 | 68 |
return -ERESTARTSYS; |
76 | 69 |
} |
77 |
len = snprintf(enc->buf, BUF_LEN+1, "%ld\n", enc->value);
|
|
70 |
len = snprintf(enc->buf, BUF_LEN+1, "%d\n", atomic_read(&enc->value));
|
|
78 | 71 |
if (*offset > len) |
79 | 72 |
{ |
80 | 73 |
return 0; |
... | ... | |
94 | 87 |
size_t count, loff_t *offset) |
95 | 88 |
{ |
96 | 89 |
char *end; |
90 |
int new_value; |
|
97 | 91 |
struct enc_t *enc = file->private_data; |
98 | 92 |
if (down_interruptible(&enc->sem)) |
99 | 93 |
{ |
... | ... | |
105 | 99 |
} |
106 | 100 |
copy_from_user(enc->buf, udata, count); |
107 | 101 |
enc->buf[count] = '\0'; |
108 |
enc->value = simple_strtol(enc->buf, &end, 10); |
|
102 |
new_value = simple_strtoi(enc->buf, &end, 10); |
|
103 |
atomic_set(&enc->value, new_value); |
|
109 | 104 |
*offset += count; |
110 | 105 |
up(&enc->sem); |
111 | 106 |
return count; |
112 | 107 |
} |
113 | 108 |
|
114 |
static int enc_init(dev_t dev, struct enc_t *enc) |
|
109 |
irqreturn_t intA(int irq, void *enc, struct pt_regs *regs) { |
|
110 |
int this = gpio_get_value(enc->pins[0]); |
|
111 |
int other = gpio_get_value(enc->pins[1]); |
|
112 |
if (this == other) { |
|
113 |
atomic_inc(&enc->value); |
|
114 |
} else { |
|
115 |
atomic_dec(&enc->value); |
|
116 |
} |
|
117 |
return IRQ_HANDLED; |
|
118 |
} |
|
119 |
|
|
120 |
irqreturn_t intB(int irq, void *enc, struct pt_regs *regs) { |
|
121 |
int this = gpio_get_value(enc->pins[1]); |
|
122 |
int other = gpio_get_value(enc->pins[0]); |
|
123 |
if (this == other) { |
|
124 |
atomic_dec(&enc->value); |
|
125 |
} else { |
|
126 |
atomic_inc(&enc->value); |
|
127 |
} |
|
128 |
return IRQ_HANDLED; |
|
129 |
} |
|
130 |
|
|
131 |
static int enc_init(dev_t dev, struct enc_t *enc, int *pins) |
|
115 | 132 |
{ |
116 |
int err; |
|
133 |
int err, i;
|
|
117 | 134 |
|
118 | 135 |
// initialize members |
119 | 136 |
cdev_init(&enc->cdev, &fops); |
... | ... | |
131 | 148 |
} |
132 | 149 |
enc->status = 1; |
133 | 150 |
|
151 |
// register gpio and interrupts |
|
152 |
for (i = 0; i < 2; i++) { |
|
153 |
|
|
154 |
enc->pins[i] = pins[i]; |
|
155 |
|
|
156 |
enc->irq[i] = gpio_to_irq(pins[i]); |
|
157 |
if (enc->irq[i] < 0) { |
|
158 |
printk("Error %d requesting irq number for gpio %d\n", enc->irq[i], |
|
159 |
enc->pins[i]); |
|
160 |
return 1; |
|
161 |
} |
|
162 |
|
|
163 |
err = gpio_direction_input(enc->pins[i]); |
|
164 |
if (err < 0) { |
|
165 |
printk("Error %d setting gpio %d to input\n", err, enc->pins[i]); |
|
166 |
return 1; |
|
167 |
} |
|
168 |
|
|
169 |
err = request_irq(enc->irq[i], i? intB : intA, SA_INTERRUPT, "encoder", enc); |
|
170 |
if (err < 0) { |
|
171 |
printk("Error %d requesting irq %d\n", err, enc->irq[i]); |
|
172 |
return 1; |
|
173 |
} |
|
174 |
|
|
175 |
// TODO the error checking here does not properly clean up after itself |
|
176 |
// TODO perhaps we should use gpio_request? probably not necessary... |
|
177 |
} |
|
178 |
enc->status = 2; |
|
179 |
|
|
180 |
return 0; |
|
181 |
} |
|
182 |
|
|
183 |
int enc_create_dev(struct enc_t *enc) { |
|
184 |
|
|
134 | 185 |
// make file in /dev |
135 | 186 |
enc->device = device_create(enc_class, NULL, enc->dev, NULL, "enc%d", |
136 | 187 |
MINOR(enc->dev)); |
... | ... | |
141 | 192 |
enc_free(enc); |
142 | 193 |
return err; |
143 | 194 |
} |
144 |
enc->status = 2;
|
|
195 |
enc->status = 3;
|
|
145 | 196 |
|
146 | 197 |
return 0; |
147 | 198 |
} |
... | ... | |
150 | 201 |
{ |
151 | 202 |
switch (enc->status) |
152 | 203 |
{ |
153 |
case 2:
|
|
204 |
case 3:
|
|
154 | 205 |
device_destroy(enc_class, enc->dev); |
155 | 206 |
enc->device = NULL; |
207 |
case 2: |
|
208 |
free_irq(enc->irq[0], enc); |
|
209 |
free_irq(enc->irq[1], enc); |
|
156 | 210 |
case 1: |
157 | 211 |
cdev_del(&enc->cdev); |
158 | 212 |
} |
... | ... | |
186 | 240 |
return 1; |
187 | 241 |
} |
188 | 242 |
|
243 |
// initialize enc structures |
|
244 |
for (i = 0; i < N_ENCODERS; i++) { |
|
245 |
err = enc_init(first_dev + i, &encs[i], enc_pins[i]); |
|
246 |
if (err) |
|
247 |
{ |
|
248 |
printk(KERN_WARNING "Error %d initializing encoder %d\n", err, i); |
|
249 |
enc_exit_module(); |
|
250 |
return 1; |
|
251 |
} |
|
252 |
} |
|
253 |
|
|
189 | 254 |
// register our device class for files in /dev |
190 | 255 |
enc_class = class_create(THIS_MODULE, "encoder"); |
191 | 256 |
if (IS_ERR(enc_class)) |
... | ... | |
196 | 261 |
} |
197 | 262 |
else |
198 | 263 |
{ |
199 |
// initialize enc structures
|
|
264 |
// create each device
|
|
200 | 265 |
for (i = 0; i < N_ENCODERS; i++) { |
201 |
err = enc_init(first_dev + i, &encs[i]);
|
|
266 |
err = enc_create_dev(&encs[i]);
|
|
202 | 267 |
if (err) |
203 | 268 |
{ |
204 |
printk(KERN_WARNING "Error %d adding enc%d\n", err, i);
|
|
269 |
printk(KERN_WARNING "Error %d creating enc%d\n", err, i);
|
|
205 | 270 |
enc_exit_module(); |
206 | 271 |
return 1; |
207 | 272 |
} |
Also available in: Unified diff