linux/drivers/macintosh/ans-lcd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * /dev/lcd driver for Apple Network Servers.
   4 */
   5
   6#include <linux/types.h>
   7#include <linux/errno.h>
   8#include <linux/kernel.h>
   9#include <linux/miscdevice.h>
  10#include <linux/fcntl.h>
  11#include <linux/module.h>
  12#include <linux/delay.h>
  13#include <linux/fs.h>
  14
  15#include <linux/uaccess.h>
  16#include <asm/sections.h>
  17#include <asm/prom.h>
  18#include <asm/io.h>
  19
  20#include "ans-lcd.h"
  21
  22#define ANSLCD_ADDR             0xf301c000
  23#define ANSLCD_CTRL_IX 0x00
  24#define ANSLCD_DATA_IX 0x10
  25
  26static unsigned long anslcd_short_delay = 80;
  27static unsigned long anslcd_long_delay = 3280;
  28static volatile unsigned char __iomem *anslcd_ptr;
  29static DEFINE_MUTEX(anslcd_mutex);
  30
  31#undef DEBUG
  32
  33static void
  34anslcd_write_byte_ctrl ( unsigned char c )
  35{
  36#ifdef DEBUG
  37        printk(KERN_DEBUG "LCD: CTRL byte: %02x\n",c);
  38#endif
  39        out_8(anslcd_ptr + ANSLCD_CTRL_IX, c);
  40        switch(c) {
  41                case 1:
  42                case 2:
  43                case 3:
  44                        udelay(anslcd_long_delay); break;
  45                default: udelay(anslcd_short_delay);
  46        }
  47}
  48
  49static void
  50anslcd_write_byte_data ( unsigned char c )
  51{
  52        out_8(anslcd_ptr + ANSLCD_DATA_IX, c);
  53        udelay(anslcd_short_delay);
  54}
  55
  56static ssize_t
  57anslcd_write( struct file * file, const char __user * buf, 
  58                                size_t count, loff_t *ppos )
  59{
  60        const char __user *p = buf;
  61        int i;
  62
  63#ifdef DEBUG
  64        printk(KERN_DEBUG "LCD: write\n");
  65#endif
  66
  67        if (!access_ok(buf, count))
  68                return -EFAULT;
  69
  70        mutex_lock(&anslcd_mutex);
  71        for ( i = *ppos; count > 0; ++i, ++p, --count ) 
  72        {
  73                char c;
  74                __get_user(c, p);
  75                anslcd_write_byte_data( c );
  76        }
  77        mutex_unlock(&anslcd_mutex);
  78        *ppos = i;
  79        return p - buf;
  80}
  81
  82static long
  83anslcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  84{
  85        char ch, __user *temp;
  86        long ret = 0;
  87
  88#ifdef DEBUG
  89        printk(KERN_DEBUG "LCD: ioctl(%d,%d)\n",cmd,arg);
  90#endif
  91
  92        mutex_lock(&anslcd_mutex);
  93
  94        switch ( cmd )
  95        {
  96        case ANSLCD_CLEAR:
  97                anslcd_write_byte_ctrl ( 0x38 );
  98                anslcd_write_byte_ctrl ( 0x0f );
  99                anslcd_write_byte_ctrl ( 0x06 );
 100                anslcd_write_byte_ctrl ( 0x01 );
 101                anslcd_write_byte_ctrl ( 0x02 );
 102                break;
 103        case ANSLCD_SENDCTRL:
 104                temp = (char __user *) arg;
 105                __get_user(ch, temp);
 106                for (; ch; temp++) { /* FIXME: This is ugly, but should work, as a \0 byte is not a valid command code */
 107                        anslcd_write_byte_ctrl ( ch );
 108                        __get_user(ch, temp);
 109                }
 110                break;
 111        case ANSLCD_SETSHORTDELAY:
 112                if (!capable(CAP_SYS_ADMIN))
 113                        ret =-EACCES;
 114                else
 115                        anslcd_short_delay=arg;
 116                break;
 117        case ANSLCD_SETLONGDELAY:
 118                if (!capable(CAP_SYS_ADMIN))
 119                        ret = -EACCES;
 120                else
 121                        anslcd_long_delay=arg;
 122                break;
 123        default:
 124                ret = -EINVAL;
 125        }
 126
 127        mutex_unlock(&anslcd_mutex);
 128        return ret;
 129}
 130
 131static int
 132anslcd_open( struct inode * inode, struct file * file )
 133{
 134        return 0;
 135}
 136
 137const struct file_operations anslcd_fops = {
 138        .write          = anslcd_write,
 139        .unlocked_ioctl = anslcd_ioctl,
 140        .open           = anslcd_open,
 141        .llseek         = default_llseek,
 142};
 143
 144static struct miscdevice anslcd_dev = {
 145        LCD_MINOR,
 146        "anslcd",
 147        &anslcd_fops
 148};
 149
 150static const char anslcd_logo[] __initconst =
 151                                "********************"  /* Line #1 */
 152                                "*      LINUX!      *"  /* Line #3 */
 153                                "*    Welcome to    *"  /* Line #2 */
 154                                "********************"; /* Line #4 */
 155
 156static int __init
 157anslcd_init(void)
 158{
 159        int a;
 160        int retval;
 161        struct device_node* node;
 162
 163        node = of_find_node_by_name(NULL, "lcd");
 164        if (!node || !of_node_name_eq(node->parent, "gc")) {
 165                of_node_put(node);
 166                return -ENODEV;
 167        }
 168        of_node_put(node);
 169
 170        anslcd_ptr = ioremap(ANSLCD_ADDR, 0x20);
 171        
 172        retval = misc_register(&anslcd_dev);
 173        if(retval < 0){
 174                printk(KERN_INFO "LCD: misc_register failed\n");
 175                iounmap(anslcd_ptr);
 176                return retval;
 177        }
 178
 179#ifdef DEBUG
 180        printk(KERN_DEBUG "LCD: init\n");
 181#endif
 182
 183        mutex_lock(&anslcd_mutex);
 184        anslcd_write_byte_ctrl ( 0x38 );
 185        anslcd_write_byte_ctrl ( 0x0c );
 186        anslcd_write_byte_ctrl ( 0x06 );
 187        anslcd_write_byte_ctrl ( 0x01 );
 188        anslcd_write_byte_ctrl ( 0x02 );
 189        for(a=0;a<80;a++) {
 190                anslcd_write_byte_data(anslcd_logo[a]);
 191        }
 192        mutex_unlock(&anslcd_mutex);
 193        return 0;
 194}
 195
 196static void __exit
 197anslcd_exit(void)
 198{
 199        misc_deregister(&anslcd_dev);
 200        iounmap(anslcd_ptr);
 201}
 202
 203module_init(anslcd_init);
 204module_exit(anslcd_exit);
 205MODULE_LICENSE("GPL v2");
 206