/* pp_buttons.c * Copyright 2002 Bjorn Bringert */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #ifdef CONFIG_MODVERSIONS #include #endif #include #include #include #include #include "sysdep.h" #include "pp_buttons.h" #define PPB_DRIVER_NAME "ppb" #define PPB PPB_DRIVER_NAME ": " #define BIT_A 0x20 #define BIT_B 0x40 #define BIT_C 0x80 #define BIT_D 0x10 EXPORT_NO_SYMBOLS; /* * Type declarations */ struct buttons { struct parport * port; struct pardevice * dev; }; /* * Static variables */ static struct buttons ppbs[MAX_PPBS] = { [0 ... MAX_PPBS-1] = { NULL, NULL} }; static int major = DEFAULT_PPB_MAJOR; static char * port[MAX_PPBS] = { PPB_DEFAULT_PORT, [1 ... MAX_PPBS-1] = "none" }; /* * Module info and parameters */ MODULE_LICENSE ("GPL"); MODULE_DESCRIPTION ("Parallel port button driver"); MODULE_AUTHOR ("Bjorn Bringert "); MODULE_PARM (major, "i"); MODULE_PARM_DESC (major, "Major number for the driver"); MODULE_PARM (port, "1-" __MODULE_STRING(MAX_DISPLAYS) "l"); MODULE_PARM_DESC (port, "port=none|parportN[,none|parportM]..., ports to use"); /* * Hardware stuff */ static int register_hardware (void) { struct parport * p; int i, ppbs_set_up = 0; for (p = parport_enumerate(); p != NULL; p = p->next) { for (i = 0; i < MAX_PPBS; i++) { if (strcmp(port[i], "none") == 0) { /* do nothing */ } else if (strcmp(port[i], p->name) == 0) { ppbs[i].port = p; ppbs[i].dev = parport_register_device(ppbs[i].port, PPB_DRIVER_NAME, NULL, NULL, NULL, 0, &ppbs[i]); if (!ppbs[i].dev) { printk(KERN_ERR PPB "parport_register_device(%s, ...) failed\n", ppbs[i].port->name); return -EIO; } printk(KERN_INFO PPB "buttons set up on %s\n", ppbs[i].port->name); } ppbs_set_up++; } } return ppbs_set_up; } static void unregister_hardware (void) { int i; for (i = 0; i < MAX_PPBS; i++) { if (ppbs[i].dev != NULL) { parport_unregister_device(ppbs[i].dev); } } } static int read_buttons (struct buttons * b) { unsigned char data; int result; result = parport_claim(b->dev); if (result < 0) { printk(KERN_ERR PPB "could not claim %s\n", b->port->name); return result; } /* gets !C B A D x x x x */ data = parport_read_status(b->port); parport_release(b->dev); /* make it C B A D x x x x */ data ^= BIT_C; /* make it x x x x D C B A */ data = (!(data & BIT_D)) << 3 \ | (!(data & BIT_C)) << 2 \ | (!(data & BIT_B)) << 1 \ | (!(data & BIT_A)); return data; } /* * Character device stuff */ static int ppb_open (struct inode * inode, struct file * filp) { struct buttons * b; int minor; minor = MINOR(inode->i_rdev); if (minor >= MAX_PPBS) { printk(KERN_ERR PPB "LCD: only %d button sets, tried to open %d\n", MAX_PPBS, minor); return -ENODEV; } b = &ppbs[minor]; if (b->dev == NULL) { printk(KERN_ERR PPB "button set %d not set up\n", minor); return -ENODEV; } filp->private_data = b; MOD_INC_USE_COUNT; return 0; } static int ppb_release (struct inode * inode, struct file * filp) { MOD_DEC_USE_COUNT; return 0; } static ssize_t ppb_read (struct file * filp, char * buf, size_t length, loff_t * offp) { struct buttons * b = filp->private_data; int result; result = read_buttons(b); if (result < 0) { return result; } put_user((unsigned char)result, buf); return 1; } struct file_operations ppb_fops = { open: ppb_open, release: ppb_release, read: ppb_read, }; /* * Module init and cleanup */ int init_module(void) { int result; SET_MODULE_OWNER(&ppb_fops); printk(KERN_INFO PPB "driver loading...\n"); result = register_chrdev(major, PPB_DRIVER_NAME, &ppb_fops); if (result < 0) { printk(KERN_ERR PPB "could not register major number %d\n", major); return result; } result = register_hardware(); if (result < 0) { printk(KERN_ERR PPB "could not initialize displays\n"); unregister_chrdev(major, PPB_DRIVER_NAME); return result; } printk(KERN_INFO PPB "driver loaded with major number %d\n", major); return 0; } void cleanup_module(void) { int result; unregister_hardware(); result = unregister_chrdev(major, PPB_DRIVER_NAME); if (result < 0) { printk(KERN_ERR PPB "could not unregister major number %d\n", major); } }