2 * Picvue PVC160206 display driver
4 * Brian Murphy <brian.murphy@eicon.com>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/errno.h>
13 #include <linux/proc_fs.h>
14 #include <linux/seq_file.h>
15 #include <linux/interrupt.h>
17 #include <linux/timer.h>
18 #include <linux/mutex.h>
19 #include <linux/uaccess.h>
23 static DEFINE_MUTEX(pvc_mutex
);
24 static char pvc_lines
[PVC_NLINES
][PVC_LINELEN
+1];
25 static int pvc_linedata
[PVC_NLINES
];
26 static char *pvc_linename
[PVC_NLINES
] = {"line1", "line2"};
27 #define DISPLAY_DIR_NAME "display"
28 static int scroll_dir
, scroll_interval
;
30 static struct timer_list timer
;
32 static void pvc_display(unsigned long data
)
37 for (i
= 0; i
< PVC_NLINES
; i
++)
38 pvc_write_string(pvc_lines
[i
], 0, i
);
41 static DECLARE_TASKLET(pvc_display_tasklet
, &pvc_display
, 0);
43 static int pvc_line_proc_show(struct seq_file
*m
, void *v
)
45 int lineno
= *(int *)m
->private;
47 if (lineno
< 0 || lineno
>= PVC_NLINES
) {
48 printk(KERN_WARNING
"proc_read_line: invalid lineno %d\n", lineno
);
52 mutex_lock(&pvc_mutex
);
53 seq_printf(m
, "%s\n", pvc_lines
[lineno
]);
54 mutex_unlock(&pvc_mutex
);
59 static int pvc_line_proc_open(struct inode
*inode
, struct file
*file
)
61 return single_open(file
, pvc_line_proc_show
, PDE_DATA(inode
));
64 static ssize_t
pvc_line_proc_write(struct file
*file
, const char __user
*buf
,
65 size_t count
, loff_t
*pos
)
67 int lineno
= *(int *)PDE_DATA(file_inode(file
));
68 char kbuf
[PVC_LINELEN
];
71 BUG_ON(lineno
< 0 || lineno
>= PVC_NLINES
);
73 len
= min(count
, sizeof(kbuf
) - 1);
74 if (copy_from_user(kbuf
, buf
, len
))
78 if (len
> 0 && kbuf
[len
- 1] == '\n')
81 mutex_lock(&pvc_mutex
);
82 strncpy(pvc_lines
[lineno
], kbuf
, len
);
83 pvc_lines
[lineno
][len
] = '\0';
84 mutex_unlock(&pvc_mutex
);
86 tasklet_schedule(&pvc_display_tasklet
);
91 static const struct file_operations pvc_line_proc_fops
= {
93 .open
= pvc_line_proc_open
,
96 .release
= single_release
,
97 .write
= pvc_line_proc_write
,
100 static ssize_t
pvc_scroll_proc_write(struct file
*file
, const char __user
*buf
,
101 size_t count
, loff_t
*pos
)
107 len
= min(count
, sizeof(kbuf
) - 1);
108 if (copy_from_user(kbuf
, buf
, len
))
112 cmd
= simple_strtol(kbuf
, NULL
, 10);
114 mutex_lock(&pvc_mutex
);
115 if (scroll_interval
!= 0)
124 scroll_interval
= -cmd
;
127 scroll_interval
= cmd
;
131 mutex_unlock(&pvc_mutex
);
136 static int pvc_scroll_proc_show(struct seq_file
*m
, void *v
)
138 mutex_lock(&pvc_mutex
);
139 seq_printf(m
, "%d\n", scroll_dir
* scroll_interval
);
140 mutex_unlock(&pvc_mutex
);
145 static int pvc_scroll_proc_open(struct inode
*inode
, struct file
*file
)
147 return single_open(file
, pvc_scroll_proc_show
, NULL
);
150 static const struct file_operations pvc_scroll_proc_fops
= {
151 .owner
= THIS_MODULE
,
152 .open
= pvc_scroll_proc_open
,
155 .release
= single_release
,
156 .write
= pvc_scroll_proc_write
,
159 void pvc_proc_timerfunc(struct timer_list
*unused
)
162 pvc_move(DISPLAY
|RIGHT
);
163 else if (scroll_dir
> 0)
164 pvc_move(DISPLAY
|LEFT
);
166 timer
.expires
= jiffies
+ scroll_interval
;
170 static void pvc_proc_cleanup(void)
172 remove_proc_subtree(DISPLAY_DIR_NAME
, NULL
);
173 del_timer_sync(&timer
);
176 static int __init
pvc_proc_init(void)
178 struct proc_dir_entry
*dir
, *proc_entry
;
181 dir
= proc_mkdir(DISPLAY_DIR_NAME
, NULL
);
185 for (i
= 0; i
< PVC_NLINES
; i
++) {
186 strcpy(pvc_lines
[i
], "");
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
)
195 proc_entry
= proc_create("scroll", 0644, dir
,
196 &pvc_scroll_proc_fops
);
197 if (proc_entry
== NULL
)
200 timer_setup(&timer
, pvc_proc_timerfunc
, 0);
208 module_init(pvc_proc_init
);
209 module_exit(pvc_proc_cleanup
);
210 MODULE_LICENSE("GPL");