├── .gitignore ├── morse ├── Makefile ├── morse.h ├── morse_mod.h └── morse_mod.c ├── message ├── Makefile ├── message_mod.h └── message_mod.c └── README /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.o 3 | *.ko 4 | .*.cmd 5 | .*.cmd 6 | modules.order 7 | *.mod.c 8 | .tmp_versions 9 | Module.symvers 10 | -------------------------------------------------------------------------------- /morse/Makefile: -------------------------------------------------------------------------------- 1 | 2 | obj-m += morse_mod.o 3 | 4 | all: 5 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 6 | 7 | clean: 8 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 9 | -------------------------------------------------------------------------------- /message/Makefile: -------------------------------------------------------------------------------- 1 | 2 | obj-m += message_mod.o 3 | 4 | all: 5 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 6 | 7 | clean: 8 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 9 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | A linux kernel module for the raspberry pi that blinks in morse code the 3 | message written to it. 4 | 5 | This was a homework assignment. The message folder turns into a kernel 6 | module that look like /dev/message0. You can write a message to it and read 7 | it back out later. The morse folder turns into a module that implements 8 | a morse code. You write to /dev/morse0 and (assuming this is running on 9 | a raspberry pi, and is connected to an LED on GPIO 17) will blink out your 10 | message in morse code. 11 | -------------------------------------------------------------------------------- /morse/morse.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MORSE 3 | #define MORSE 4 | 5 | static char *morse_code[] = { 6 | ".-", // A 7 | "-...", // B 8 | "-.-.", // C 9 | "-..", // D 10 | ".", // E 11 | "..-.", // F 12 | "--.", // G 13 | "....", // H 14 | "..", // I 15 | ".---", // J 16 | "-.-", // K 17 | ".-..", // L 18 | "--", // M 19 | "-.", // N 20 | "---", // O 21 | ".--.", // P 22 | "--.-", // Q 23 | ".-.", // R 24 | "...", // S 25 | "-", // T 26 | "..-", // U 27 | "...-", // V 28 | ".--", // W 29 | "-..-", // X 30 | "-.--", // Y 31 | "--..", // Z 32 | 33 | ".----", // 1 34 | "..---", // 2 35 | "...--", // 3 36 | "....-", // 4 37 | ".....", // 5 38 | "-....", // 6 39 | "--...", // 7 40 | "---..", // 8 41 | "----.", // 9 42 | "-----", // 0 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /message/message_mod.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MESSAGE_MOD 3 | #define MESSAGE_MOD 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define DEV_NAME "message" 16 | #define AUTHOR "Michael Abed " 17 | #define DESC "A device that holds a message" 18 | #define LICENSE "GPL" 19 | 20 | MODULE_AUTHOR(AUTHOR); 21 | MODULE_DESCRIPTION(DESC); 22 | MODULE_LICENSE(LICENSE); 23 | MODULE_SUPPORTED_DEVICE(DEV_NAME); 24 | 25 | static int __init message_init(void); 26 | static void __exit message_exit(void); 27 | 28 | static short message_count = 1; 29 | module_param(message_count, short, S_IRUSR | S_IRGRP | S_IROTH); 30 | MODULE_PARM_DESC(message_count, "Number of message devices to create"); 31 | 32 | static int message_open(struct inode *inode, struct file *file); 33 | static int message_release(struct inode *inode, struct file *file); 34 | static ssize_t message_read(struct file *filp, char *buffer, size_t len, loff_t *off); 35 | static ssize_t message_write(struct file *filp, const char *buffer, size_t length, loff_t *off); 36 | 37 | 38 | static struct file_operations message_ops = { 39 | .owner = THIS_MODULE, 40 | .read = message_read, 41 | .write = message_write, 42 | .open = message_open, 43 | .release = message_release 44 | }; 45 | 46 | static int major; 47 | static dev_t device; 48 | static struct class *dev_class; 49 | 50 | struct message { 51 | char buffer[32]; 52 | struct cdev dev; 53 | int minor; 54 | int open; 55 | int pos; 56 | int len; 57 | int valid; 58 | //struct list_head list; 59 | }; 60 | 61 | union min_data { 62 | void *pt; 63 | int minor; 64 | }; 65 | 66 | typedef union min_data min_data; 67 | 68 | static struct message *new_message(int minor); 69 | 70 | static struct message** message_list; 71 | 72 | #endif 73 | 74 | -------------------------------------------------------------------------------- /morse/morse_mod.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MORSE_MOD 3 | #define MORSE_MOD 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include "morse.h" 18 | 19 | #define DEV_NAME "morse" 20 | #define AUTHOR "Michael Abed " 21 | #define DESC "A morse code blinker" 22 | #define LICENSE "GPL" 23 | 24 | #define PIN 17 25 | 26 | MODULE_AUTHOR(AUTHOR); 27 | MODULE_DESCRIPTION(DESC); 28 | MODULE_LICENSE(LICENSE); 29 | MODULE_SUPPORTED_DEVICE(DEV_NAME); 30 | 31 | static int __init message_init(void); 32 | static void __exit message_exit(void); 33 | 34 | // We're hard coding this to 1 for this module 35 | static short message_count = 1; 36 | //module_param(message_count, short, S_IRUSR | S_IRGRP | S_IROTH); 37 | //MODULE_PARM_DESC(message_count, "Number of message devices to create"); 38 | 39 | static int message_open(struct inode *inode, struct file *file); 40 | static int message_release(struct inode *inode, struct file *file); 41 | static ssize_t message_read(struct file *filp, char *buffer, size_t len, loff_t *off); 42 | static ssize_t message_write(struct file *filp, const char *buffer, size_t length, loff_t *off); 43 | 44 | 45 | static struct file_operations message_ops = { 46 | .owner = THIS_MODULE, 47 | .read = message_read, 48 | .write = message_write, 49 | .open = message_open, 50 | .release = message_release 51 | }; 52 | 53 | static int major; 54 | static dev_t device; 55 | static struct class *dev_class; 56 | 57 | struct message { 58 | char buffer[32]; 59 | struct cdev dev; 60 | int minor; 61 | int open; 62 | int pos; 63 | int len; 64 | int valid; 65 | //struct list_head list; 66 | }; 67 | 68 | struct morse_display { 69 | struct message *msg; 70 | int msg_pos; 71 | int l_pos; 72 | int done; 73 | int state; 74 | }; 75 | 76 | union min_data { 77 | void *pt; 78 | int minor; 79 | }; 80 | 81 | typedef union min_data min_data; 82 | 83 | static struct timer_list timer; 84 | 85 | static struct message *new_message(int minor); 86 | static struct message** message_list; 87 | static struct morse_display morse; 88 | 89 | static void step_display(unsigned long arg); 90 | 91 | static void start_morse(int msg_idx); 92 | static char* morse_char(char x); 93 | 94 | #endif 95 | 96 | -------------------------------------------------------------------------------- /message/message_mod.c: -------------------------------------------------------------------------------- 1 | 2 | #include "message_mod.h" 3 | 4 | module_init(message_init); 5 | module_exit(message_exit); 6 | 7 | static int __init message_init(void) 8 | { 9 | int err, i; 10 | struct message *msg; 11 | dev_t devno; 12 | dev_class = class_create(THIS_MODULE, "message_mod"); 13 | alloc_chrdev_region(&device, 0, message_count, DEV_NAME); 14 | major = MAJOR(device); 15 | 16 | message_list = kcalloc(sizeof(struct message*), message_count, GFP_KERNEL); 17 | for (i = 0; i < message_count; i++) { 18 | devno = MKDEV(major, i); 19 | msg = new_message(i); 20 | message_list[i] = msg; 21 | 22 | err = cdev_add(&msg->dev, devno, 1); 23 | if (err) 24 | printk(KERN_NOTICE"Error %d adding message%d", err, i); 25 | device_create(dev_class, NULL, devno, NULL, "message%d", i); 26 | } 27 | 28 | printk(KERN_INFO"Loaded module: message\n"); 29 | return 0; 30 | } 31 | 32 | static void __exit message_exit(void) 33 | { 34 | int i; 35 | dev_t devno; 36 | for (i = 0; i < message_count; i++) { 37 | devno = MKDEV(major, i); 38 | device_destroy(dev_class, message_list[i]->dev.dev); 39 | cdev_del(&message_list[i]->dev); 40 | kfree(message_list[i]); 41 | } 42 | kfree(message_list); 43 | class_destroy(dev_class); 44 | unregister_chrdev_region(device, message_count); 45 | printk(KERN_INFO "Unloaded module: message\n"); 46 | } 47 | 48 | static struct message* new_message(int minor) 49 | { 50 | struct message *msg = kmalloc(sizeof(struct message), GFP_KERNEL); 51 | int i; 52 | 53 | for (i = 0; i < 32; i++) 54 | msg->buffer[i] = 0; 55 | cdev_init(&msg->dev, &message_ops); 56 | msg->dev.owner = THIS_MODULE; 57 | msg->minor = minor; 58 | msg->open = 0; 59 | msg->pos = 0; 60 | msg->len = 0; 61 | msg->valid = 0; 62 | return msg; 63 | } 64 | 65 | static int message_open(struct inode *inode, struct file *filp) 66 | { 67 | int minor = MINOR(inode->i_rdev); 68 | struct message *msg = message_list[minor]; 69 | 70 | min_data min; 71 | min.minor = minor; 72 | 73 | if (msg->open) 74 | return -EINVAL; 75 | 76 | msg->open++; 77 | msg->pos = 0; 78 | filp->private_data = min.pt; 79 | return 0; 80 | } 81 | 82 | static int message_release(struct inode *inode, struct file *filp) 83 | { 84 | struct message *msg = message_list[((min_data)filp->private_data).minor]; 85 | if (msg != NULL) { 86 | msg->pos = 0; 87 | msg->open--; 88 | } 89 | return 0; 90 | } 91 | 92 | static ssize_t message_read(struct file *filp, char *buffer, size_t len, loff_t *off) 93 | { 94 | int to_copy, left; 95 | struct message *msg = message_list[((min_data)filp->private_data).minor]; 96 | 97 | if (!msg->valid) 98 | return -EINVAL; 99 | 100 | if (msg->pos >= msg->len) 101 | return 0; 102 | 103 | to_copy = len > msg->len ? msg->len : len; 104 | left = copy_to_user(buffer, msg->buffer+msg->pos, to_copy); 105 | if (left) // we didn't finish copying 106 | return -EINVAL; 107 | 108 | msg->pos += to_copy; 109 | return to_copy; 110 | } 111 | 112 | static ssize_t message_write(struct file *filp, const char *buff, size_t len, loff_t *off) 113 | { 114 | int to_copy; 115 | struct message *msg = message_list[((min_data)filp->private_data).minor]; 116 | 117 | if (msg->valid) { 118 | msg->valid = 0; 119 | } 120 | 121 | to_copy = len > 31 ? 31 : len; 122 | copy_from_user(msg->buffer, buff, to_copy); 123 | 124 | msg->len = to_copy; 125 | msg->buffer[len+1] = '\0'; 126 | 127 | msg->valid = 1; 128 | return len; 129 | } 130 | 131 | -------------------------------------------------------------------------------- /morse/morse_mod.c: -------------------------------------------------------------------------------- 1 | 2 | #include "morse_mod.h" 3 | 4 | module_init(message_init); 5 | module_exit(message_exit); 6 | 7 | static int __init message_init(void) 8 | { 9 | int err, i, g; 10 | struct message *msg; 11 | dev_t devno; 12 | dev_class = class_create(THIS_MODULE, "morse_mod"); 13 | alloc_chrdev_region(&device, 0, message_count, DEV_NAME); 14 | major = MAJOR(device); 15 | 16 | g = gpio_request(PIN, "morse"); 17 | if (g != 0) { 18 | return -EINVAL; 19 | } 20 | gpio_direction_output(PIN, 0); 21 | 22 | message_list = kcalloc(sizeof(struct message*), message_count, GFP_KERNEL); 23 | for (i = 0; i < message_count; i++) { 24 | devno = MKDEV(major, i); 25 | msg = new_message(i); 26 | message_list[i] = msg; 27 | 28 | err = cdev_add(&msg->dev, devno, 1); 29 | if (err) { 30 | printk(KERN_NOTICE"Error %d adding message%d", err, i); 31 | return -EINVAL; 32 | } 33 | device_create(dev_class, NULL, devno, NULL, "morse%d", i); 34 | } 35 | 36 | printk(KERN_INFO"Loaded module: morse_mod\n"); 37 | return 0; 38 | } 39 | 40 | static void __exit message_exit(void) 41 | { 42 | int i; 43 | dev_t devno; 44 | for (i = 0; i < message_count; i++) { 45 | devno = MKDEV(major, i); 46 | device_destroy(dev_class, message_list[i]->dev.dev); 47 | cdev_del(&message_list[i]->dev); 48 | kfree(message_list[i]); 49 | } 50 | kfree(message_list); 51 | class_destroy(dev_class); 52 | unregister_chrdev_region(device, message_count); 53 | gpio_free(PIN); 54 | printk(KERN_INFO "Unloaded module: morse_mod\n"); 55 | } 56 | 57 | static char* morse_char(char x) { 58 | if (x >= 'a' && x <= 'z') { // Convert to uppercase 59 | x -= ('a' - 'A'); 60 | } 61 | 62 | // If it's not a letter a number 63 | if (!((x >= '0' && x <= '9') || (x >= 'A' && x <= 'Z'))) { 64 | return NULL; // non coded will be treated as a space 65 | } else { 66 | // If it's a number, calculate position 67 | if (x >= '0' && x <= '9') { 68 | return morse_code[x-'0'+26]; 69 | } else { // Or look up digit 70 | return morse_code[x-'A']; 71 | } 72 | } 73 | } 74 | 75 | static struct message* new_message(int minor) 76 | { 77 | struct message *msg = kmalloc(sizeof(struct message), GFP_KERNEL); 78 | int i; 79 | 80 | for (i = 0; i < 32; i++) 81 | msg->buffer[i] = 0; 82 | cdev_init(&msg->dev, &message_ops); 83 | msg->dev.owner = THIS_MODULE; 84 | msg->minor = minor; 85 | msg->open = 0; 86 | msg->pos = 0; 87 | msg->len = 0; 88 | msg->valid = 0; 89 | return msg; 90 | } 91 | 92 | static void step_display(unsigned long arg) 93 | { 94 | unsigned long delay; 95 | const unsigned int time_unit = HZ/2; // Half a second 96 | char *code = morse_char(morse.msg->buffer[morse.msg_pos]); 97 | 98 | if (morse.state == 0 && code != NULL) { 99 | 100 | gpio_set_value(PIN, 1); 101 | 102 | morse.state = 1; 103 | if (code[morse.l_pos] == '-') 104 | delay = 3 * time_unit; 105 | else 106 | delay = 1 * time_unit; 107 | 108 | } else if (code == NULL) { 109 | gpio_set_value(PIN, 0); 110 | 111 | morse.state = 0; 112 | morse.msg_pos++; 113 | morse.l_pos = 0; 114 | delay = 7 * time_unit; 115 | 116 | if (morse.msg_pos >= morse.msg->len) 117 | morse.done = 1; 118 | 119 | } else { 120 | gpio_set_value(PIN, 0); 121 | 122 | morse.state = 0; 123 | morse.l_pos++; 124 | 125 | // If we've finished this letter 126 | if (code[morse.l_pos] == '\0') { 127 | morse.l_pos = 0; 128 | morse.msg_pos++; 129 | delay = 3 * time_unit; 130 | } else { 131 | delay = 1 * time_unit; 132 | } 133 | 134 | // If we've finished the messaeg 135 | if (morse.msg_pos >= morse.msg->len) 136 | morse.done = 1; 137 | } 138 | 139 | // Rebuild timer to display next 140 | del_timer(&timer); 141 | if (!morse.done) { 142 | init_timer(&timer); 143 | timer.expires = jiffies + delay; 144 | timer.data = 0; 145 | timer.function = step_display; 146 | add_timer(&timer); 147 | } else { 148 | morse.msg->open--; 149 | } 150 | } 151 | 152 | static void start_morse(int msg_idx) 153 | { 154 | // Re-initialize our display struct 155 | morse.msg = message_list[msg_idx]; 156 | morse.msg->open++; 157 | morse.msg_pos = 0; 158 | morse.l_pos = 0; 159 | morse.done = 0; 160 | morse.state = 0; 161 | 162 | init_timer(&timer); 163 | timer.expires = jiffies + (HZ/2); 164 | timer.data = 0; 165 | timer.function = step_display; 166 | add_timer(&timer); 167 | } 168 | 169 | static int message_open(struct inode *inode, struct file *filp) 170 | { 171 | int minor = MINOR(inode->i_rdev); 172 | struct message *msg = message_list[minor]; 173 | 174 | min_data min; 175 | min.minor = minor; 176 | 177 | if (msg->open) 178 | return -EBUSY; 179 | 180 | msg->open++; 181 | msg->pos = 0; 182 | filp->private_data = min.pt; 183 | return 0; 184 | } 185 | 186 | static int message_release(struct inode *inode, struct file *filp) 187 | { 188 | struct message *msg = message_list[((min_data)filp->private_data).minor]; 189 | if (msg != NULL) { 190 | msg->pos = 0; 191 | msg->open--; 192 | } 193 | return 0; 194 | } 195 | 196 | static ssize_t message_read(struct file *filp, char *buffer, size_t len, loff_t *off) 197 | { 198 | int to_copy, left; 199 | struct message *msg = message_list[((min_data)filp->private_data).minor]; 200 | 201 | if (!msg->valid) 202 | return -EINVAL; 203 | 204 | if (msg->pos >= msg->len) 205 | return 0; 206 | 207 | to_copy = len > msg->len ? msg->len : len; 208 | left = copy_to_user(buffer, msg->buffer+msg->pos, to_copy); 209 | if (left) // we didn't finish copying 210 | return -EINVAL; 211 | 212 | msg->pos += to_copy; 213 | return to_copy; 214 | } 215 | 216 | static ssize_t message_write(struct file *filp, const char *buff, size_t len, loff_t *off) 217 | { 218 | int to_copy; 219 | int left; 220 | struct message *msg = message_list[((min_data)filp->private_data).minor]; 221 | 222 | if (msg->valid) { 223 | msg->valid = 0; 224 | } 225 | 226 | to_copy = len > 31 ? 31 : len; 227 | left = copy_from_user(msg->buffer, buff, to_copy); 228 | if (left != 0) 229 | return -EINVAL; 230 | 231 | msg->len = to_copy; 232 | msg->buffer[len+1] = '\0'; 233 | 234 | if (to_copy == 0) 235 | msg->buffer[0] = '\0'; 236 | 237 | msg->valid = 1; 238 | 239 | start_morse(((min_data)filp->private_data).minor); 240 | return len; 241 | } 242 | 243 | --------------------------------------------------------------------------------