linux/drivers/char/briq_panel.c
<<
>>
Prefs
   1/*
   2 * Drivers for the Total Impact PPC based computer "BRIQ"
   3 * by Dr. Karsten Jeppesen
   4 *
   5 */
   6
   7#include <linux/module.h>
   8
   9#include <linux/smp_lock.h>
  10#include <linux/types.h>
  11#include <linux/errno.h>
  12#include <linux/tty.h>
  13#include <linux/timer.h>
  14#include <linux/kernel.h>
  15#include <linux/wait.h>
  16#include <linux/string.h>
  17#include <linux/slab.h>
  18#include <linux/ioport.h>
  19#include <linux/delay.h>
  20#include <linux/miscdevice.h>
  21#include <linux/fs.h>
  22#include <linux/mm.h>
  23#include <linux/init.h>
  24
  25#include <asm/uaccess.h>
  26#include <asm/io.h>
  27#include <asm/prom.h>
  28
  29#define         BRIQ_PANEL_MINOR        156
  30#define         BRIQ_PANEL_VFD_IOPORT   0x0390
  31#define         BRIQ_PANEL_LED_IOPORT   0x0398
  32#define         BRIQ_PANEL_VER          "1.1 (04/20/2002)"
  33#define         BRIQ_PANEL_MSG0         "Loading Linux"
  34
  35static int              vfd_is_open;
  36static unsigned char    vfd[40];
  37static int              vfd_cursor;
  38static unsigned char    ledpb, led;
  39
  40static void update_vfd(void)
  41{
  42        int     i;
  43
  44        /* cursor home */
  45        outb(0x02, BRIQ_PANEL_VFD_IOPORT);
  46        for (i=0; i<20; i++)
  47                outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
  48
  49        /* cursor to next line */
  50        outb(0xc0, BRIQ_PANEL_VFD_IOPORT);
  51        for (i=20; i<40; i++)
  52                outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
  53
  54}
  55
  56static void set_led(char state)
  57{
  58        if (state == 'R')
  59                led = 0x01;
  60        else if (state == 'G')
  61                led = 0x02;
  62        else if (state == 'Y')
  63                led = 0x03;
  64        else if (state == 'X')
  65                led = 0x00;
  66        outb(led, BRIQ_PANEL_LED_IOPORT);
  67}
  68
  69static int briq_panel_open(struct inode *ino, struct file *filep)
  70{
  71        lock_kernel();
  72        /* enforce single access, vfd_is_open is protected by BKL */
  73        if (vfd_is_open) {
  74                unlock_kernel();
  75                return -EBUSY;
  76        }
  77        vfd_is_open = 1;
  78
  79        unlock_kernel();
  80        return 0;
  81}
  82
  83static int briq_panel_release(struct inode *ino, struct file *filep)
  84{
  85        if (!vfd_is_open)
  86                return -ENODEV;
  87
  88        vfd_is_open = 0;
  89
  90        return 0;
  91}
  92
  93static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count,
  94                         loff_t *ppos)
  95{
  96        unsigned short c;
  97        unsigned char cp;
  98
  99        if (!vfd_is_open)
 100                return -ENODEV;
 101
 102        c = (inb(BRIQ_PANEL_LED_IOPORT) & 0x000c) | (ledpb & 0x0003);
 103        set_led(' ');
 104        /* upper button released */
 105        if ((!(ledpb & 0x0004)) && (c & 0x0004)) {
 106                cp = ' ';
 107                ledpb = c;
 108                if (copy_to_user(buf, &cp, 1))
 109                        return -EFAULT;
 110                return 1;
 111        }
 112        /* lower button released */
 113        else if ((!(ledpb & 0x0008)) && (c & 0x0008)) {
 114                cp = '\r';
 115                ledpb = c;
 116                if (copy_to_user(buf, &cp, 1))
 117                        return -EFAULT;
 118                return 1;
 119        } else {
 120                ledpb = c;
 121                return 0;
 122        }
 123}
 124
 125static void scroll_vfd( void )
 126{
 127        int     i;
 128
 129        for (i=0; i<20; i++) {
 130                vfd[i] = vfd[i+20];
 131                vfd[i+20] = ' ';
 132        }
 133        vfd_cursor = 20;
 134}
 135
 136static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_t len,
 137                          loff_t *ppos)
 138{
 139        size_t indx = len;
 140        int i, esc = 0;
 141
 142        if (!vfd_is_open)
 143                return -EBUSY;
 144
 145        for (;;) {
 146                char c;
 147                if (!indx)
 148                        break;
 149                if (get_user(c, buf))
 150                        return -EFAULT;
 151                if (esc) {
 152                        set_led(c);
 153                        esc = 0;
 154                } else if (c == 27) {
 155                        esc = 1;
 156                } else if (c == 12) {
 157                        /* do a form feed */
 158                        for (i=0; i<40; i++)
 159                                vfd[i] = ' ';
 160                        vfd_cursor = 0;
 161                } else if (c == 10) {
 162                        if (vfd_cursor < 20)
 163                                vfd_cursor = 20;
 164                        else if (vfd_cursor < 40)
 165                                vfd_cursor = 40;
 166                        else if (vfd_cursor < 60)
 167                                vfd_cursor = 60;
 168                        if (vfd_cursor > 59)
 169                                scroll_vfd();
 170                } else {
 171                        /* just a character */
 172                        if (vfd_cursor > 39)
 173                                scroll_vfd();
 174                        vfd[vfd_cursor++] = c;
 175                }
 176                indx--;
 177                buf++;
 178        }
 179        update_vfd();
 180
 181        return len;
 182}
 183
 184static const struct file_operations briq_panel_fops = {
 185        .owner          = THIS_MODULE,
 186        .read           = briq_panel_read,
 187        .write          = briq_panel_write,
 188        .open           = briq_panel_open,
 189        .release        = briq_panel_release,
 190};
 191
 192static struct miscdevice briq_panel_miscdev = {
 193        BRIQ_PANEL_MINOR,
 194        "briq_panel",
 195        &briq_panel_fops
 196};
 197
 198static int __init briq_panel_init(void)
 199{
 200        struct device_node *root = of_find_node_by_path("/");
 201        const char *machine;
 202        int i;
 203
 204        machine = of_get_property(root, "model", NULL);
 205        if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) {
 206                of_node_put(root);
 207                return -ENODEV;
 208        }
 209        of_node_put(root);
 210
 211        printk(KERN_INFO
 212                "briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n",
 213                BRIQ_PANEL_VER);
 214
 215        if (!request_region(BRIQ_PANEL_VFD_IOPORT, 4, "BRIQ Front Panel"))
 216                return -EBUSY;
 217
 218        if (!request_region(BRIQ_PANEL_LED_IOPORT, 2, "BRIQ Front Panel")) {
 219                release_region(BRIQ_PANEL_VFD_IOPORT, 4);
 220                return -EBUSY;
 221        }
 222        ledpb = inb(BRIQ_PANEL_LED_IOPORT) & 0x000c;
 223
 224        if (misc_register(&briq_panel_miscdev) < 0) {
 225                release_region(BRIQ_PANEL_VFD_IOPORT, 4);
 226                release_region(BRIQ_PANEL_LED_IOPORT, 2);
 227                return -EBUSY;
 228        }
 229
 230        outb(0x38, BRIQ_PANEL_VFD_IOPORT);      /* Function set */
 231        outb(0x01, BRIQ_PANEL_VFD_IOPORT);      /* Clear display */
 232        outb(0x0c, BRIQ_PANEL_VFD_IOPORT);      /* Display on */
 233        outb(0x06, BRIQ_PANEL_VFD_IOPORT);      /* Entry normal */
 234        for (i=0; i<40; i++)
 235                vfd[i]=' ';
 236#ifndef MODULE
 237        vfd[0] = 'L';
 238        vfd[1] = 'o';
 239        vfd[2] = 'a';
 240        vfd[3] = 'd';
 241        vfd[4] = 'i';
 242        vfd[5] = 'n';
 243        vfd[6] = 'g';
 244        vfd[7] = ' ';
 245        vfd[8] = '.';
 246        vfd[9] = '.';
 247        vfd[10] = '.';
 248#endif /* !MODULE */
 249
 250        update_vfd();
 251
 252        return 0;
 253}
 254
 255static void __exit briq_panel_exit(void)
 256{
 257        misc_deregister(&briq_panel_miscdev);
 258        release_region(BRIQ_PANEL_VFD_IOPORT, 4);
 259        release_region(BRIQ_PANEL_LED_IOPORT, 2);
 260}
 261
 262module_init(briq_panel_init);
 263module_exit(briq_panel_exit);
 264
 265MODULE_LICENSE("GPL");
 266MODULE_AUTHOR("Karsten Jeppesen <karsten@jeppesens.com>");
 267MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel");
 268
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.