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#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");
 211