Revision 83163372

View differences:

scout_gumstix/README
1
etc/ contains various configuration files that should go into /etc/ on the
2
Gumstix. etc/hostname and etc/hosts have "scout1" in them, which should be
3
replaced with a unique name for each scout.
4

  
5
encoder/ contains the source code for a kernel module which must be built on
6
the Gumstix. It provides /dev/encN with 0 <= N < 4. Count value are signed
7
integers. Examples:
8
$ cat /dev/enc0
9
104522
10
$ echo 0 > /dev/enc0
11
$ cat /dev/enc0
12
0
scout_gumstix/encoder/Makefile
1
obj-m += encoder.o
2

  
3
all: encoder.ko
4

  
5
encoder.ko: encoder.c
6
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
7

  
8
clean:
9
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
scout_gumstix/encoder/encoder.c
1
#include <linux/init.h>
2
#include <linux/module.h>
3
#include <linux/fs.h>
4
#include <linux/cdev.h>
5
#include <linux/slab.h>
6
#include <linux/device.h>
7
#include <linux/semaphore.h>
8
#include <asm/uaccess.h>
9

  
10
MODULE_AUTHOR("Tom Mullins");
11
MODULE_LICENSE("GPL");
12

  
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
#define BUF_LEN 20
24
#define N_ENCODERS 4
25
int enc_pins[N_ENCODERS][2] = {{78, 79}, {80, 81}, {82, 83}, {84, 85}};
26
struct class *enc_class = NULL;
27
dev_t first_dev;
28

  
29
struct enc_t
30
{
31
  char buf[BUF_LEN+1];
32
  struct cdev cdev;
33
  struct semaphore sem;
34
  struct device *device;
35
  int status;
36
  enc_val_t value;
37
  dev_t dev;
38
}
39
encs[N_ENCODERS];
40

  
41
static int enc_open(struct inode *inode, struct file *file);
42
static ssize_t enc_read(struct file *file, char __user *udata, size_t count,
43
    loff_t *offset);
44
static ssize_t enc_write(struct file *file, const char __user *udata,
45
    size_t count, loff_t *offset);
46
static void enc_free(struct enc_t *enc);
47
static int enc_init(dev_t dev, struct enc_t *enc);
48

  
49
struct file_operations fops =
50
{
51
  .owner = THIS_MODULE,
52
  .open = enc_open,
53
  .read = enc_read,
54
  .write = enc_write
55
};
56

  
57
static int enc_open(struct inode *inode, struct file *file)
58
{
59
  int i = iminor(inode);
60
  if (i < 0 || i >= N_ENCODERS)
61
  {
62
    return -ENXIO;
63
  }
64
  file->private_data = &encs[i];
65
  return 0;
66
}
67

  
68
static ssize_t enc_read(struct file *file, char __user *udata, size_t count,
69
    loff_t *offset)
70
{
71
  int len;
72
  struct enc_t *enc = file->private_data;
73
  if (down_interruptible(&enc->sem))
74
  {
75
    return -ERESTARTSYS;
76
  }
77
  len = snprintf(enc->buf, BUF_LEN+1, "%ld\n", enc->value);
78
  if (*offset > len)
79
  {
80
    return 0;
81
  }
82
  len -= *offset;
83
  if (len > count)
84
  {
85
    len = count;
86
  }
87
  copy_to_user(udata, enc->buf + *offset, len);
88
  *offset += len;
89
  up(&enc->sem);
90
  return len;
91
}
92

  
93
static ssize_t enc_write(struct file *file, const char __user *udata,
94
    size_t count, loff_t *offset)
95
{
96
  char *end;
97
  struct enc_t *enc = file->private_data;
98
  if (down_interruptible(&enc->sem))
99
  {
100
    return -ERESTARTSYS;
101
  }
102
  if (count > BUF_LEN)
103
  {
104
    count = BUF_LEN;
105
  }
106
  copy_from_user(enc->buf, udata, count);
107
  enc->buf[count] = '\0';
108
  enc->value = simple_strtol(enc->buf, &end, 10);
109
  *offset += count;
110
  up(&enc->sem);
111
  return count;
112
}
113

  
114
static int enc_init(dev_t dev, struct enc_t *enc)
115
{
116
  int err;
117

  
118
  // initialize members
119
  cdev_init(&enc->cdev, &fops);
120
  enc->cdev.owner = THIS_MODULE;
121
  enc->dev = dev;
122
  enc->status = 0;
123
  sema_init(&enc->sem, 1);
124

  
125
  // make cdev file operations accessible
126
  err = cdev_add(&enc->cdev, enc->dev, N_ENCODERS);
127
  if (err)
128
  {
129
    enc_free(enc);
130
    return err;
131
  }
132
  enc->status = 1;
133

  
134
  // make file in /dev
135
  enc->device = device_create(enc_class, NULL, enc->dev, NULL, "enc%d",
136
      MINOR(enc->dev));
137
  if (IS_ERR(enc->device))
138
  {
139
    err = PTR_ERR(enc->device);
140
    enc->device = NULL;
141
    enc_free(enc);
142
    return err;
143
  }
144
  enc->status = 2;
145

  
146
  return 0;
147
}
148

  
149
static void enc_free(struct enc_t *enc)
150
{
151
  switch (enc->status)
152
  {
153
    case 2:
154
      device_destroy(enc_class, enc->dev);
155
      enc->device = NULL;
156
    case 1:
157
      cdev_del(&enc->cdev);
158
  }
159
  enc->status = 0;
160
}
161

  
162
static void enc_exit_module(void)
163
{
164
  int i;
165
  for (i = 0; i < N_ENCODERS; i++)
166
  {
167
    enc_free(&encs[i]);
168
  }
169
  if (enc_class) {
170
    class_destroy(enc_class);
171
    enc_class = NULL;
172
  }
173
  unregister_chrdev_region(first_dev, N_ENCODERS);
174
}
175
module_exit(enc_exit_module);
176

  
177
static int __init enc_init_module(void)
178
{
179
  int i, err;
180

  
181
  // allocate character devices and get major number
182
  err = alloc_chrdev_region(&first_dev, 0, N_ENCODERS, "encoder");
183
  if (err)
184
  {
185
    printk(KERN_ALERT "Error %d in alloc_chrdev_region\n", err);
186
    return 1;
187
  }
188

  
189
  // register our device class for files in /dev
190
  enc_class = class_create(THIS_MODULE, "encoder");
191
  if (IS_ERR(enc_class))
192
  {
193
    err = PTR_ERR(enc_class);
194
    enc_class = NULL;
195
    printk(KERN_WARNING "Error %d creating device class\n", err);
196
  }
197
  else
198
  {
199
    // initialize enc structures
200
    for (i = 0; i < N_ENCODERS; i++) {
201
      err = enc_init(first_dev + i, &encs[i]);
202
      if (err)
203
      {
204
        printk(KERN_WARNING "Error %d adding enc%d\n", err, i);
205
        enc_exit_module();
206
        return 1;
207
      }
208
    }
209
  }
210

  
211
  return 0;
212
}
213
module_init(enc_init_module);
scout_gumstix/etc/fstab
1
proc /proc proc nodev,noexec,nosuid 0 0
2
/dev/mmcblk0p2 / ext3 errors=remount-ro,user_xattr,noatime,nodiratime,commit=120 0 1
scout_gumstix/etc/hostname
1
scout1
scout_gumstix/etc/hosts
1
127.0.0.1	localhost
2
127.0.1.1	scout1
3
::1		localhost ip6-localhost ip6-loopback
4
fe00::0		ip6-localnet
5
ff00::0		ip6-mcastprefix
6
ff02::1		ip6-allnodes
7
ff02::2		ip6-allrouters
8

  
scout_gumstix/etc/init/ttyO2.conf
1
# This service maintains a getty on ttyO2 from the point the system is
2
# started until it is shut down again.
3

  
4
start on stopped rc RUNLEVEL=[12345]
5

  
6
stop on runlevel [!12345]
7

  
8
respawn
9
exec /sbin/getty -8 115200 ttyO2
scout_gumstix/etc/network/interfaces
1
# interfaces(5) file used by ifup(8) and ifdown(8)
2
auto lo
3
iface lo inet loopback
4
auto usb0
5
iface usb0 inet dhcp
scout_gumstix/etc/rc.local
1
#!/bin/sh -e
2
#
3
# rc.local
4
#
5
# This script is executed at the end of each multiuser runlevel.
6
# Make sure that the script will "exit 0" on success or any other
7
# value on error.
8
#
9
# In order to enable or disable this script just change the execution
10
# bits.
11
#
12
# By default this script does nothing.
13

  
14
export_as_output() {
15
  last_dir="$PWD"
16
  cd /sys/class/gpio
17
  echo "$1" > export
18
  cd "gpio$1"
19
  echo out > direction
20
  chgrp gpio value
21
  chown g+w value # TODO necessary?
22
  cd "$last_dir"
23
}
24

  
25
# export motor driver gpio pins
26
for i in 70 71 72 73 74 75 76 77; do
27
  export_as_output $i
28
done
29

  
30
exit 0
scout_gumstix/etc/udev/rules.d/40-encoder.rules
1
SUBSYSTEM=="encoder", GROUP="gpio"

Also available in: Unified diff