Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.0-rc2 210 lines 4.4 kB view raw
1/* 2 * Picvue PVC160206 display driver 3 * 4 * Brian Murphy <brian.murphy@eicon.com> 5 * 6 */ 7#include <linux/bug.h> 8#include <linux/kernel.h> 9#include <linux/module.h> 10#include <linux/init.h> 11#include <linux/errno.h> 12 13#include <linux/proc_fs.h> 14#include <linux/seq_file.h> 15#include <linux/interrupt.h> 16 17#include <linux/timer.h> 18#include <linux/mutex.h> 19#include <linux/uaccess.h> 20 21#include "picvue.h" 22 23static DEFINE_MUTEX(pvc_mutex); 24static char pvc_lines[PVC_NLINES][PVC_LINELEN+1]; 25static int pvc_linedata[PVC_NLINES]; 26static char *pvc_linename[PVC_NLINES] = {"line1", "line2"}; 27#define DISPLAY_DIR_NAME "display" 28static int scroll_dir, scroll_interval; 29 30static struct timer_list timer; 31 32static void pvc_display(unsigned long data) 33{ 34 int i; 35 36 pvc_clear(); 37 for (i = 0; i < PVC_NLINES; i++) 38 pvc_write_string(pvc_lines[i], 0, i); 39} 40 41static DECLARE_TASKLET(pvc_display_tasklet, &pvc_display, 0); 42 43static int pvc_line_proc_show(struct seq_file *m, void *v) 44{ 45 int lineno = *(int *)m->private; 46 47 if (lineno < 0 || lineno >= PVC_NLINES) { 48 printk(KERN_WARNING "proc_read_line: invalid lineno %d\n", lineno); 49 return 0; 50 } 51 52 mutex_lock(&pvc_mutex); 53 seq_printf(m, "%s\n", pvc_lines[lineno]); 54 mutex_unlock(&pvc_mutex); 55 56 return 0; 57} 58 59static int pvc_line_proc_open(struct inode *inode, struct file *file) 60{ 61 return single_open(file, pvc_line_proc_show, PDE_DATA(inode)); 62} 63 64static ssize_t pvc_line_proc_write(struct file *file, const char __user *buf, 65 size_t count, loff_t *pos) 66{ 67 int lineno = *(int *)PDE_DATA(file_inode(file)); 68 char kbuf[PVC_LINELEN]; 69 size_t len; 70 71 BUG_ON(lineno < 0 || lineno >= PVC_NLINES); 72 73 len = min(count, sizeof(kbuf) - 1); 74 if (copy_from_user(kbuf, buf, len)) 75 return -EFAULT; 76 kbuf[len] = '\0'; 77 78 if (len > 0 && kbuf[len - 1] == '\n') 79 len--; 80 81 mutex_lock(&pvc_mutex); 82 strncpy(pvc_lines[lineno], kbuf, len); 83 pvc_lines[lineno][len] = '\0'; 84 mutex_unlock(&pvc_mutex); 85 86 tasklet_schedule(&pvc_display_tasklet); 87 88 return count; 89} 90 91static const struct file_operations pvc_line_proc_fops = { 92 .owner = THIS_MODULE, 93 .open = pvc_line_proc_open, 94 .read = seq_read, 95 .llseek = seq_lseek, 96 .release = single_release, 97 .write = pvc_line_proc_write, 98}; 99 100static ssize_t pvc_scroll_proc_write(struct file *file, const char __user *buf, 101 size_t count, loff_t *pos) 102{ 103 char kbuf[42]; 104 size_t len; 105 int cmd; 106 107 len = min(count, sizeof(kbuf) - 1); 108 if (copy_from_user(kbuf, buf, len)) 109 return -EFAULT; 110 kbuf[len] = '\0'; 111 112 cmd = simple_strtol(kbuf, NULL, 10); 113 114 mutex_lock(&pvc_mutex); 115 if (scroll_interval != 0) 116 del_timer(&timer); 117 118 if (cmd == 0) { 119 scroll_dir = 0; 120 scroll_interval = 0; 121 } else { 122 if (cmd < 0) { 123 scroll_dir = -1; 124 scroll_interval = -cmd; 125 } else { 126 scroll_dir = 1; 127 scroll_interval = cmd; 128 } 129 add_timer(&timer); 130 } 131 mutex_unlock(&pvc_mutex); 132 133 return count; 134} 135 136static int pvc_scroll_proc_show(struct seq_file *m, void *v) 137{ 138 mutex_lock(&pvc_mutex); 139 seq_printf(m, "%d\n", scroll_dir * scroll_interval); 140 mutex_unlock(&pvc_mutex); 141 142 return 0; 143} 144 145static int pvc_scroll_proc_open(struct inode *inode, struct file *file) 146{ 147 return single_open(file, pvc_scroll_proc_show, NULL); 148} 149 150static const struct file_operations pvc_scroll_proc_fops = { 151 .owner = THIS_MODULE, 152 .open = pvc_scroll_proc_open, 153 .read = seq_read, 154 .llseek = seq_lseek, 155 .release = single_release, 156 .write = pvc_scroll_proc_write, 157}; 158 159void pvc_proc_timerfunc(struct timer_list *unused) 160{ 161 if (scroll_dir < 0) 162 pvc_move(DISPLAY|RIGHT); 163 else if (scroll_dir > 0) 164 pvc_move(DISPLAY|LEFT); 165 166 timer.expires = jiffies + scroll_interval; 167 add_timer(&timer); 168} 169 170static void pvc_proc_cleanup(void) 171{ 172 remove_proc_subtree(DISPLAY_DIR_NAME, NULL); 173 del_timer_sync(&timer); 174} 175 176static int __init pvc_proc_init(void) 177{ 178 struct proc_dir_entry *dir, *proc_entry; 179 int i; 180 181 dir = proc_mkdir(DISPLAY_DIR_NAME, NULL); 182 if (dir == NULL) 183 goto error; 184 185 for (i = 0; i < PVC_NLINES; i++) { 186 strcpy(pvc_lines[i], ""); 187 pvc_linedata[i] = i; 188 } 189 for (i = 0; i < PVC_NLINES; i++) { 190 proc_entry = proc_create_data(pvc_linename[i], 0644, dir, 191 &pvc_line_proc_fops, &pvc_linedata[i]); 192 if (proc_entry == NULL) 193 goto error; 194 } 195 proc_entry = proc_create("scroll", 0644, dir, 196 &pvc_scroll_proc_fops); 197 if (proc_entry == NULL) 198 goto error; 199 200 timer_setup(&timer, pvc_proc_timerfunc, 0); 201 202 return 0; 203error: 204 pvc_proc_cleanup(); 205 return -ENOMEM; 206} 207 208module_init(pvc_proc_init); 209module_exit(pvc_proc_cleanup); 210MODULE_LICENSE("GPL");