linux/arch/mips/lasat/picvue_proc.c
<<
>>
Prefs
   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 struct proc_dir_entry *pvc_display_dir;
  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(unsigned long data)
 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        int i;
 173        for (i = 0; i < PVC_NLINES; i++)
 174                remove_proc_entry(pvc_linename[i], pvc_display_dir);
 175        remove_proc_entry("scroll", pvc_display_dir);
 176        remove_proc_entry(DISPLAY_DIR_NAME, NULL);
 177
 178        del_timer_sync(&timer);
 179}
 180
 181static int __init pvc_proc_init(void)
 182{
 183        struct proc_dir_entry *proc_entry;
 184        int i;
 185
 186        pvc_display_dir = proc_mkdir(DISPLAY_DIR_NAME, NULL);
 187        if (pvc_display_dir == NULL)
 188                goto error;
 189
 190        for (i = 0; i < PVC_NLINES; i++) {
 191                strcpy(pvc_lines[i], "");
 192                pvc_linedata[i] = i;
 193        }
 194        for (i = 0; i < PVC_NLINES; i++) {
 195                proc_entry = proc_create_data(pvc_linename[i], 0644, pvc_display_dir,
 196                                        &pvc_line_proc_fops, &pvc_linedata[i]);
 197                if (proc_entry == NULL)
 198                        goto error;
 199        }
 200        proc_entry = proc_create("scroll", 0644, pvc_display_dir,
 201                                 &pvc_scroll_proc_fops);
 202        if (proc_entry == NULL)
 203                goto error;
 204
 205        init_timer(&timer);
 206        timer.function = pvc_proc_timerfunc;
 207
 208        return 0;
 209error:
 210        pvc_proc_cleanup();
 211        return -ENOMEM;
 212}
 213
 214module_init(pvc_proc_init);
 215module_exit(pvc_proc_cleanup);
 216MODULE_LICENSE("GPL");
 217