alistair23-linux/drivers/char/briq_panel.c
Arjan van de Ven 2b8693c061 [PATCH] mark struct file_operations const 3
Many struct file_operations in the kernel can be "const".  Marking them const
moves these to the .rodata section, which avoids false sharing with potential
dirty data.  In addition it'll catch accidental writes at compile time to
these shared resources.

Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-02-12 09:48:45 -08:00

271 lines
5.3 KiB
C

/*
* Drivers for the Total Impact PPC based computer "BRIQ"
* by Dr. Karsten Jeppesen
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/timer.h>
#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/prom.h>
#define BRIQ_PANEL_MINOR 156
#define BRIQ_PANEL_VFD_IOPORT 0x0390
#define BRIQ_PANEL_LED_IOPORT 0x0398
#define BRIQ_PANEL_VER "1.1 (04/20/2002)"
#define BRIQ_PANEL_MSG0 "Loading Linux"
static int vfd_is_open;
static unsigned char vfd[40];
static int vfd_cursor;
static unsigned char ledpb, led;
static void update_vfd(void)
{
int i;
/* cursor home */
outb(0x02, BRIQ_PANEL_VFD_IOPORT);
for (i=0; i<20; i++)
outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
/* cursor to next line */
outb(0xc0, BRIQ_PANEL_VFD_IOPORT);
for (i=20; i<40; i++)
outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
}
static void set_led(char state)
{
if (state == 'R')
led = 0x01;
else if (state == 'G')
led = 0x02;
else if (state == 'Y')
led = 0x03;
else if (state == 'X')
led = 0x00;
outb(led, BRIQ_PANEL_LED_IOPORT);
}
static int briq_panel_open(struct inode *ino, struct file *filep)
{
/* enforce single access */
if (vfd_is_open)
return -EBUSY;
vfd_is_open = 1;
return 0;
}
static int briq_panel_release(struct inode *ino, struct file *filep)
{
if (!vfd_is_open)
return -ENODEV;
vfd_is_open = 0;
return 0;
}
static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
unsigned short c;
unsigned char cp;
#if 0 /* Can't seek (pread) on this device */
if (ppos != &file->f_pos)
return -ESPIPE;
#endif
if (!vfd_is_open)
return -ENODEV;
c = (inb(BRIQ_PANEL_LED_IOPORT) & 0x000c) | (ledpb & 0x0003);
set_led(' ');
/* upper button released */
if ((!(ledpb & 0x0004)) && (c & 0x0004)) {
cp = ' ';
ledpb = c;
if (copy_to_user(buf, &cp, 1))
return -EFAULT;
return 1;
}
/* lower button released */
else if ((!(ledpb & 0x0008)) && (c & 0x0008)) {
cp = '\r';
ledpb = c;
if (copy_to_user(buf, &cp, 1))
return -EFAULT;
return 1;
} else {
ledpb = c;
return 0;
}
}
static void scroll_vfd( void )
{
int i;
for (i=0; i<20; i++) {
vfd[i] = vfd[i+20];
vfd[i+20] = ' ';
}
vfd_cursor = 20;
}
static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_t len,
loff_t *ppos)
{
size_t indx = len;
int i, esc = 0;
#if 0 /* Can't seek (pwrite) on this device */
if (ppos != &file->f_pos)
return -ESPIPE;
#endif
if (!vfd_is_open)
return -EBUSY;
for (;;) {
char c;
if (!indx)
break;
if (get_user(c, buf))
return -EFAULT;
if (esc) {
set_led(c);
esc = 0;
} else if (c == 27) {
esc = 1;
} else if (c == 12) {
/* do a form feed */
for (i=0; i<40; i++)
vfd[i] = ' ';
vfd_cursor = 0;
} else if (c == 10) {
if (vfd_cursor < 20)
vfd_cursor = 20;
else if (vfd_cursor < 40)
vfd_cursor = 40;
else if (vfd_cursor < 60)
vfd_cursor = 60;
if (vfd_cursor > 59)
scroll_vfd();
} else {
/* just a character */
if (vfd_cursor > 39)
scroll_vfd();
vfd[vfd_cursor++] = c;
}
indx--;
buf++;
}
update_vfd();
return len;
}
static const struct file_operations briq_panel_fops = {
.owner = THIS_MODULE,
.read = briq_panel_read,
.write = briq_panel_write,
.open = briq_panel_open,
.release = briq_panel_release,
};
static struct miscdevice briq_panel_miscdev = {
BRIQ_PANEL_MINOR,
"briq_panel",
&briq_panel_fops
};
static int __init briq_panel_init(void)
{
struct device_node *root = find_path_device("/");
const char *machine;
int i;
machine = get_property(root, "model", NULL);
if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0)
return -ENODEV;
printk(KERN_INFO
"briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n",
BRIQ_PANEL_VER);
if (!request_region(BRIQ_PANEL_VFD_IOPORT, 4, "BRIQ Front Panel"))
return -EBUSY;
if (!request_region(BRIQ_PANEL_LED_IOPORT, 2, "BRIQ Front Panel")) {
release_region(BRIQ_PANEL_VFD_IOPORT, 4);
return -EBUSY;
}
ledpb = inb(BRIQ_PANEL_LED_IOPORT) & 0x000c;
if (misc_register(&briq_panel_miscdev) < 0) {
release_region(BRIQ_PANEL_VFD_IOPORT, 4);
release_region(BRIQ_PANEL_LED_IOPORT, 2);
return -EBUSY;
}
outb(0x38, BRIQ_PANEL_VFD_IOPORT); /* Function set */
outb(0x01, BRIQ_PANEL_VFD_IOPORT); /* Clear display */
outb(0x0c, BRIQ_PANEL_VFD_IOPORT); /* Display on */
outb(0x06, BRIQ_PANEL_VFD_IOPORT); /* Entry normal */
for (i=0; i<40; i++)
vfd[i]=' ';
#ifndef MODULE
vfd[0] = 'L';
vfd[1] = 'o';
vfd[2] = 'a';
vfd[3] = 'd';
vfd[4] = 'i';
vfd[5] = 'n';
vfd[6] = 'g';
vfd[7] = ' ';
vfd[8] = '.';
vfd[9] = '.';
vfd[10] = '.';
#endif /* !MODULE */
update_vfd();
return 0;
}
static void __exit briq_panel_exit(void)
{
misc_deregister(&briq_panel_miscdev);
release_region(BRIQ_PANEL_VFD_IOPORT, 4);
release_region(BRIQ_PANEL_LED_IOPORT, 2);
}
module_init(briq_panel_init);
module_exit(briq_panel_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Karsten Jeppesen <karsten@jeppesens.com>");
MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel");