Revision f024710b scout_gumstix/encoder/encoder.c

View differences:

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