Project

General

Profile

Revision f024710b

IDf024710be92a87d10ad8c50d0784a7e1f3f4a5fe
Parent 32b36ecc
Child f58d377f

Added by Thomas Mullins over 11 years ago

Added actual reads from hardware to encoder.ko

Not yet tested on Gumstix (especially since I don't think we have the
encoders yet).

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