/* ------------------------------------------------------------------------- */ /* i2c-mcselec.c i2c-hw access for MCS Electronics style adapter */ /* ------------------------------------------------------------------------- */ /* Copyright (C) 1995-2000 Simon G. Vogl Copyright (C) 2004 Sebastian Zagrodzki 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ------------------------------------------------------------------------- */ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ /* $Id: i2c-elv.c,v 1.17 2001/07/29 02:44:25 mds Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_BASE 0x378 static int base=0; static unsigned char PortData = 0; static unsigned char PortStatus = 0; static unsigned char PortCtl = 0; /* ----- global defines ----------------------------------------------- */ #define DEB(x) /* should be reasonable open, close &c. */ #define DEB2(x) /* low level debugging - very slow */ #define DEBE(x) x /* error messages */ #define DEBINIT(x) x /* detection status messages */ /* --- Convenience defines for the parallel port: */ #define BASE (unsigned int)(data) #define DATA BASE /* Centronics data port */ #define STAT (BASE+1) /* Centronics status port */ #define CTRL (BASE+2) /* Centronics control port */ /* ----- local functions ---------------------------------------------- */ static void bit_mcselec_setscl(void *data, int state) { if (state) { PortCtl |= 0x08; } else { PortCtl &= 0xf7; } outb_p(PortCtl, CTRL); } static void bit_mcselec_setsda(void *data, int state) { if (state) { PortData &= 0x7f; } else { PortData |= 0x80; } outb(PortData, DATA); } static int bit_mcselec_getscl(void *data) { return (inb_p(STAT) & 0x08); } static int bit_mcselec_getsda(void *data) { return (inb_p(STAT) & 0x80); } static int bit_mcselec_init(void) { if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) { return -ENODEV; } else { /* test for adapter */ bit_mcselec_setscl((void*)base, 1); udelay(400); if (!bit_mcselec_getscl((void*)base)) { /* SCL should be high */ DEBINIT(printk(KERN_DEBUG "i2c-mcselec.o: SCL (Error) was low after SCL (Select) set high.\n")); return -ENODEV; } else { bit_mcselec_setscl((void*)base, 0); /* SCL to low */ udelay(400); if (bit_mcselec_getscl((void*)base)) { bit_mcselec_setscl((void*)base, 1); DEBINIT(printk(KERN_DEBUG "i2c-mcselec.o: SCL (Error) was high after SCL (Select) set low.\n")); return -ENODEV; } } request_region(base,(base == 0x3bc)? 3 : 8, "i2c (MCS Electronics adapter)"); PortData = 0; PortStatus = 0; PortCtl = 0; bit_mcselec_setsda((void*)base,1); bit_mcselec_setscl((void*)base,1); } return 0; } static void __exit bit_mcselec_exit(void) { release_region( base , (base == 0x3bc)? 3 : 8 ); } static int bit_mcselec_reg(struct i2c_client *client) { return 0; } static int bit_mcselec_unreg(struct i2c_client *client) { return 0; } static void bit_mcselec_inc_use(struct i2c_adapter *adap) { #ifdef MODULE MOD_INC_USE_COUNT; #endif } static void bit_mcselec_dec_use(struct i2c_adapter *adap) { #ifdef MODULE MOD_DEC_USE_COUNT; #endif } /* ------------------------------------------------------------------------ * Encapsulate the above functions in the correct operations structure. * This is only done when more than one hardware adapter is supported. */ static struct i2c_algo_bit_data bit_mcselec_data = { NULL, bit_mcselec_setsda, bit_mcselec_setscl, bit_mcselec_getsda, bit_mcselec_getscl, 40, 40, 50, /* waits, timeout */ }; static struct i2c_adapter bit_mcselec_ops = { "MCS Electronics parport adapter", I2C_HW_B_MCSELEC, NULL, &bit_mcselec_data, bit_mcselec_inc_use, bit_mcselec_dec_use, bit_mcselec_reg, bit_mcselec_unreg, }; int __init i2c_bitmcselec_init(void) { printk(KERN_INFO "i2c-mcselec.o: i2c MCS Electronics parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); if (base==0) { /* probe some values */ base=DEFAULT_BASE; bit_mcselec_data.data=(void*)DEFAULT_BASE; if (bit_mcselec_init()==0) { if(i2c_bit_add_bus(&bit_mcselec_ops) < 0) return -ENODEV; } else { return -ENODEV; } } else { bit_mcselec_ops.data=(void*)base; if (bit_mcselec_init()==0) { if(i2c_bit_add_bus(&bit_mcselec_ops) < 0) return -ENODEV; } else { return -ENODEV; } } printk(KERN_DEBUG "i2c-mcselec.o: found device at %#x.\n",base); return 0; } EXPORT_NO_SYMBOLS; #ifdef MODULE MODULE_AUTHOR("Sebastian Zagrodzki "); MODULE_DESCRIPTION("I2C-Bus adapter routines for MCS Electronics parallel port adapter"); MODULE_LICENSE("GPL"); MODULE_PARM(base, "i"); int init_module(void) { return i2c_bitmcselec_init(); } void cleanup_module(void) { i2c_bit_del_bus(&bit_mcselec_ops); bit_mcselec_exit(); } #endif