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