From 72425223659251589e7013ebbec337a037b449d7 Mon Sep 17 00:00:00 2001 From: Mike Crute Date: Sat, 8 Feb 2020 21:06:12 +0000 Subject: Initial import --- Makefile | 7 ++ pix_driver.c | 258 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ relay_control.c | 95 +++++++++++++++++++++ 3 files changed, 360 insertions(+) create mode 100644 Makefile create mode 100644 pix_driver.c create mode 100644 relay_control.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..152671c --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +obj-m := relay_control.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/pix_driver.c b/pix_driver.c new file mode 100644 index 0000000..10d3d21 --- /dev/null +++ b/pix_driver.c @@ -0,0 +1,258 @@ +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +/* GPIO */ + +#define A1 17 // 0 +#define A2 18 // 1 +#define A3 27 // 2 +#define OE 22 // 3 +#define LE 23 // 4 +#define SDI 24 // 5 +#define CLK 25 // 6 + +#define LINES 8 +#define PER_LINE 12 + +static u8 pix_screen[LINES][PER_LINE] = { + { + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + }, + { + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + }, + { + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + }, + { + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + }, + { + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + }, + { + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + }, + { + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + }, + { + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + 0b00000000,0b00000000,0b00000000,0b00000000, + }, +}; + +void pix_line(u8 row){ + gpio_set_value(A1, !(row & 0b00000001)); + gpio_set_value(A2, !(row & 0b00000010)); + gpio_set_value(A3, !(row & 0b00000100)); +} + +void pix_dot(int x, int y, int r, int g, int b) { + uint8_t l,p,t; + + if(y % 2){ + x = (x + 16); + } + y = (y / 2) - ((y / 2) % 1); + + l = x / 8; + p = 7 - x % 8; + t = pix_screen[y][l]; + + //printf("line:%i, l:%i, p:%i, t:%i\n", y,l,p,t); + + if(r) { + t |= 1 << p; + }else{ + t &= ~(1 << p); + } + pix_screen[y][l] = t; + + l = x / 8 + 4; + p = 7 - x % 8; + t = pix_screen[y][l]; + if(g) { + t |= 1 << p; + }else{ + t &= ~(1 << p); + } + pix_screen[y][l] = t; + + l = x / 8 + 8; + p = 7 - x % 8; + t = pix_screen[y][l]; + if(b) { + t |= 1 << p; + }else{ + t &= ~(1 << p); + } + pix_screen[y][l] = t; +} + +void pix_gpio_init(void){ + printk(KERN_INFO "PIX: starting gpio..."); + gpio_request(A1, "A1"); + gpio_request(A2, "A2"); + gpio_request(A3, "A3"); + + gpio_request(OE, "OE"); + gpio_request(LE, "LE"); + gpio_request(SDI, "SDI"); + gpio_request(CLK, "CLK"); + + gpio_direction_output(A1, 0); + gpio_direction_output(A2, 0); + gpio_direction_output(A3, 0); + + gpio_direction_output(OE, 1); + gpio_direction_output(LE, 0); + gpio_direction_output(SDI, 0); + gpio_direction_output(CLK, 0); + printk(KERN_INFO "PIX: starting gpio done."); +} + +void pix_gpio_exit(void){ + printk(KERN_INFO "PIX: stopping gpio..."); + gpio_free(A1); + gpio_free(A2); + gpio_free(A3); + + gpio_free(OE); + gpio_free(LE); + gpio_free(SDI); + gpio_free(CLK); + printk(KERN_INFO "PIX: stopping gpio done."); +} + + + +/* SYSFS */ + +static struct kobject *pix_kobject; + +static ssize_t set_pix(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, size_t count) { + u8 x = 0; + u8 y = 0; + u8 r = 0; + u8 g = 0; + u8 b = 0; + sscanf(buff, "%hhd %hhd %hhd %hhd %hhd", &x, &y, &r, &g, &b); + + pix_dot(x,y,r,g,b); + // printk(KERN_INFO "PIX: %d %d %d %d %d", x,y,r,g,b); + + return count; +} + +static struct kobj_attribute pix_attribute =__ATTR(dot, (S_IWUSR | S_IRUGO), NULL, set_pix); + +void pix_sysfs_init(void){ + printk(KERN_INFO "PIX: starting sysfs..."); + pix_kobject = kobject_create_and_add("pix", NULL); + if (sysfs_create_file(pix_kobject, &pix_attribute.attr)) { + pr_debug("failed to create pix sysfs!\n"); + } + printk(KERN_INFO "PIX: starting sysfs done."); +} + +void pix_sysfs_exit(void){ + printk(KERN_INFO "PIX: stopping sysfs..."); + kobject_put(pix_kobject); + printk(KERN_INFO "PIX: stopping sysfs done."); +} + + +/* THREAD */ + +#define THREAD_PRIORITY 45 +#define THREAD_NAME "pix" + +struct task_struct *task; + +int pix_thread(void *data){ + u8 line, pos, bit; + struct task_struct *TSK; + struct sched_param PARAM = { .sched_priority = MAX_RT_PRIO - 50 }; + //struct sched_param PARAM = { .sched_priority = DEFAULT_PRIO }; + TSK = current; + + PARAM.sched_priority = THREAD_PRIORITY; + sched_setscheduler(TSK, SCHED_FIFO, &PARAM); + + while(1) { + for(line = 0; line < LINES; line++) { + pix_line(line); + for(pos = 0; pos < PER_LINE; pos++) { + for (bit = 0; bit < 8; bit++) { + gpio_set_value(SDI, !!(pix_screen[line][pos] & (1 << (7 - bit)))); + gpio_set_value(CLK, 1); + gpio_set_value(CLK, 0); + } + } + gpio_set_value(LE, 1); + gpio_set_value(LE, 0); + gpio_set_value(OE, 0); + usleep_range(2000, 2000); + gpio_set_value(OE, 1); + } + if (kthread_should_stop()) break; + } + return 0; +} + +void pix_thread_init(void){ + printk(KERN_INFO "PIX: starting thread..."); + task = kthread_run(pix_thread, NULL, THREAD_NAME); + printk(KERN_INFO "PIX: starting thread done."); +} + +void pix_thread_exit(void){ + printk(KERN_INFO "PIX: stopping thread..."); + kthread_stop(task); + printk(KERN_INFO "PIX: stopping thread done."); +} + +/* MODULE */ + +static int __init pix_init(void){ + printk(KERN_INFO "PIX: staring..."); + pix_gpio_init(); + pix_thread_init(); + pix_sysfs_init(); + printk(KERN_INFO "PIX: staring done."); + return 0; +} + +static void __exit pix_exit(void){ + printk(KERN_INFO "PIX: stopping..."); + pix_sysfs_exit(); + pix_thread_exit(); + pix_gpio_exit(); + printk(KERN_INFO "PIX: stopping done."); +} + +module_init(pix_init); +module_exit(pix_exit); + + diff --git a/relay_control.c b/relay_control.c new file mode 100644 index 0000000..7b0e59c --- /dev/null +++ b/relay_control.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +#define RELAY_K1 18 +#define RELAY_K2 23 +#define RELAY_K3 24 +#define RELAY_K4 25 + +#define NO_OFF 0 +#define NO_ON 1 + +static struct kobject *relay_kobject; + +static ssize_t set_relay(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, size_t count) { + int relay = 0; + u8 v = 0; + sscanf(buff, "%hhd", &v); + + if (strcmp(attr->attr.name, "relay1") == 0) { + relay = RELAY_K1; + } else if (strcmp(attr->attr.name, "relay2") == 0) { + relay = RELAY_K2; + } else if (strcmp(attr->attr.name, "relay3") == 0) { + relay = RELAY_K3; + } else if (strcmp(attr->attr.name, "relay4") == 0) { + relay = RELAY_K4; + } + + gpio_set_value(relay, (v == 0) ? NO_OFF : NO_ON); + return count; +} + +static ssize_t get_relay(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { + int relay = 0; + if (strcmp(attr->attr.name, "relay1") == 0) { + relay = RELAY_K1; + } else if (strcmp(attr->attr.name, "relay2") == 0) { + relay = RELAY_K2; + } else if (strcmp(attr->attr.name, "relay3") == 0) { + relay = RELAY_K3; + } else if (strcmp(attr->attr.name, "relay4") == 0) { + relay = RELAY_K4; + } + return sprintf(buff, "%d", gpio_get_value(relay)); +} + +static struct kobj_attribute relay1_attribute = __ATTR(relay1, (S_IWUSR | S_IRUGO), get_relay, set_relay); +static struct kobj_attribute relay2_attribute = __ATTR(relay2, (S_IWUSR | S_IRUGO), get_relay, set_relay); +static struct kobj_attribute relay3_attribute = __ATTR(relay3, (S_IWUSR | S_IRUGO), get_relay, set_relay); +static struct kobj_attribute relay4_attribute = __ATTR(relay4, (S_IWUSR | S_IRUGO), get_relay, set_relay); + +static int __init relay_init(void) { + gpio_request(RELAY_K1, "RELAY_K1"); + gpio_request(RELAY_K2, "RELAY_K2"); + gpio_request(RELAY_K3, "RELAY_K3"); + gpio_request(RELAY_K4, "RELAY_K4"); + + gpio_direction_output(RELAY_K1, NO_ON); + gpio_direction_output(RELAY_K2, NO_ON); + gpio_direction_output(RELAY_K3, NO_ON); + gpio_direction_output(RELAY_K4, NO_ON); + + relay_kobject = kobject_create_and_add("relay", NULL); + + if (sysfs_create_file(relay_kobject, &relay1_attribute.attr)) { + pr_debug("failed to create relay1 sysfs!\n"); + } + if (sysfs_create_file(relay_kobject, &relay2_attribute.attr)) { + pr_debug("failed to create relay2 sysfs!\n"); + } + if (sysfs_create_file(relay_kobject, &relay3_attribute.attr)) { + pr_debug("failed to create relay3 sysfs!\n"); + } + if (sysfs_create_file(relay_kobject, &relay4_attribute.attr)) { + pr_debug("failed to create relay4 sysfs!\n"); + } + + return 0; +} + +static void __exit relay_exit(void) { + kobject_put(relay_kobject); + + gpio_free(RELAY_K1); + gpio_free(RELAY_K2); + gpio_free(RELAY_K3); + gpio_free(RELAY_K4); +} + +module_init(relay_init); +module_exit(relay_exit); -- cgit v1.2.3