diff --git a/doc/design b/doc/design index 35b33d98..c9278e7b 100644 --- a/doc/design +++ b/doc/design @@ -7,6 +7,8 @@ Document version 1.0, 19981101. 1.1, 19981111. 1.2, 19981118. +--> Never, ever change the driver struct with this technique! + Object oriented approach ======================== @@ -168,7 +170,7 @@ included in kernels around 1.2.120!). A driver -------- -struct sensor_driver { +struct i2c_driver { char name[32]; int id; unsigned int flags; diff --git a/kernel/Module.mk b/kernel/Module.mk index 9a4e96bb..a70b8304 100644 --- a/kernel/Module.mk +++ b/kernel/Module.mk @@ -22,7 +22,7 @@ MODULE_DIR := src # Regrettably, even 'simply expanded variables' will not put their currently # defined value verbatim into the command-list of rules... -SRCTARGETS := $(MODULE_DIR)/smbus.o $(MODULE_DIR)/piix4.o +SRCTARGETS := $(MODULE_DIR)/smbus.o $(MODULE_DIR)/piix4.o $(MODULE_DIR)/isa.o # Include all dependency files INCLUDEFILES += $(SRCTARGETS:.o=.d) diff --git a/kernel/busses/i2c-isa.c b/kernel/busses/i2c-isa.c new file mode 100644 index 00000000..8ea0b52c --- /dev/null +++ b/kernel/busses/i2c-isa.c @@ -0,0 +1,191 @@ +/* + isa.c - A Linux module for reading sensor data. + Copyright (c) 1998 Frodo Looijaard + + 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. +*/ + +/* This implements an i2c algorithm/adapter for ISA bus. Not that this is + on first sight very useful; almost no functionality is preserved. + Except that it makes writing drivers for chips which can be on both + the SMBus and the ISA bus very much easier. See lm78.c for an example + of this. */ + +#include +#include + +#include "i2c.h" +#ifdef SPINLOCK +#include +#else +#include +#endif + +#include "version.h" +#include "isa.h" + +static int isa_master_xfer (struct isa_adapter *adap, + struct i2c_msg msgs[], int num); +static int isa_slave_send (struct isa_adapter *adap, char *data, int len); +static int isa_slave_recv (struct isa_adapter *adap, char *data, int len); +static int isa_algo_control (struct isa_adapter *adap, unsigned int cmd, + unsigned long arg); +static int isa_client_register (struct isa_client *client); +static int isa_client_unregister (struct isa_client *client); + +static int isa_init(void); +static int isa_cleanup(void); + +#ifdef MODULE +extern int init_module(void); +extern int cleanup_module(void); +#endif /* MODULE */ + +/* This is the actual algorithm we define */ +static struct isa_algorithm isa_algorithm = { + /* name */ "ISA bus adapter", + /* id */ ALGO_ISA, + /* master_xfer */ &isa_master_xfer, + /* slave_send */ &isa_slave_send, + /* slave_rcv */ &isa_slave_recv, + /* algo_control */ &isa_algo_control, + /* client_register */ &isa_client_register, + /* client_unregister*/&isa_client_unregister +}; + +/* There can only be one... */ +static struct isa_adapter isa_adapter; + +/* Used in isa_init/cleanup */ +static int isa_initialized; + +/* Algorithm master_xfer call-back implementation. Can't do that... */ +int isa_master_xfer (struct isa_adapter *adap, struct i2c_msg msgs[], + int num) +{ + printk("isa_master_xfer called for adapter `%s' " + "(no i2c level access possible!)\n", + adap->name); + return 0; +} + +/* Algorithm slave_send call-back implementation. Can't do that... */ +int isa_slave_send (struct isa_adapter *adap, char *data, int len) +{ + printk("isa_slave_send called for adapter `%s' " + "(no i2c level access possible!)\n", + adap->name); + return 0; +} + +/* Algorithm slave_recv call-back implementation. Can't do that... */ +int isa_slave_recv (struct isa_adapter *adap, char *data, int len) +{ + printk("isa_slave_recv called for adapter `%s' " + "(no i2c level access possible!)\n", + adap->name); + return 0; +} + +/* Here we can put additional calls to modify the workings of the algorithm. + But right now, there is no need for that. */ +int isa_algo_control (struct isa_adapter *adap, unsigned int cmd, + unsigned long arg) +{ + return 0; +} + +/* Ehm... This is called when a client is registered to an adapter. We could + do all kinds of neat stuff here like, ehm - returning success? */ +int isa_client_register (struct isa_client *client) +{ + return 0; +} + +int isa_client_unregister (struct isa_client *client) +{ + return 0; +} + +int isa_init(void) +{ + int res; + printk("isa.o version %s (%s)\n",LM_VERSION,LM_DATE); +#ifdef DEBUG + if (isa_initialized) { + printk("isa.o: Oops, isa_init called a second time!\n"); + return -EBUSY; + } +#endif + isa_initialized = 0; + if ((res = isa_add_algorithm(&isa_algorithm))) { + printk("isa.o: Algorithm registration failed, module isa.o not inserted\n"); + isa_cleanup(); + return res; + } + isa_initialized++; + strcpy(isa_adapter.name,"ISA main adapter"); + isa_adapter.id = ALGO_ISA | ISA_MAIN; + isa_adapter.algo = &isa_algorithm; + if ((res = isa_add_adapter(&isa_adapter))) { + printk("isa.o: Adapter registration failed, " + "module isa.o is not inserted\n"); + isa_cleanup(); + return res; + } + isa_initialized++; + printk("isa.o: ISA bus access for i2c modules initialized\n"); + return 0; +} + +int isa_cleanup(void) +{ + int res; + if (isa_initialized >= 2) + { + if ((res = isa_del_adapter(&isa_adapter))) { + printk("isa.o: isa_del_adapter failed, module not removed\n"); + return res; + } else + isa_initialized--; + } + if (isa_initialized >= 1) + { + if ((res = isa_del_algorithm(&isa_algorithm))) { + printk("isa.o: isa_del_algorithm failed, module not removed\n"); + return res; + } else + isa_initialized--; + } + return 0; +} + +#ifdef MODULE + +MODULE_AUTHOR("Frodo Looijaard "); +MODULE_DESCRIPTION("ISA bus access through i2c"); + +int init_module(void) +{ + return isa_init(); +} + +int cleanup_module(void) +{ + return isa_cleanup(); +} + +#endif /* MODULE */ + diff --git a/kernel/include/i2c-isa.h b/kernel/include/i2c-isa.h new file mode 100644 index 00000000..d5ad471d --- /dev/null +++ b/kernel/include/i2c-isa.h @@ -0,0 +1,153 @@ +/* + isa.h - A Linux module for reading sensor data. + Copyright (c) 1998 Frodo Looijaard + + 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. +*/ + +#ifndef SENSORS_SENSOR_H +#define SENSORS_SENSOR_H + +/* This file must interface with Simon Vogl's i2c driver. Version 19981006 is + OK, earlier versions are not; later versions will probably give problems + too. +*/ +#ifdef I2C +#include "i2c/i2c.h" +#else /* def I2C */ +#include +#endif /* def I2C */ + +#include + +/* SPINLOCK is defined in i2c.h. */ +#ifdef SPINLOCK +#include +#else +#include +#endif + +#include "isa.h" + +/* Note that this driver is *not* built upon smbus.c, but is parallel to it. + We do not need SMBus facilities if we are on the ISA bus, after all */ + +/* Declarations, to keep the compiler happy */ +struct isa_driver; +struct isa_client; +struct isa_algorithm; +struct isa_adapter; + +/* A driver tells us how we should handle a specific kind of chip. + A specific instance of such a chip is called a client. + This structure is essentially the same as i2c_driver. */ +struct isa_driver { + char name[32]; + int id; + unsigned int flags; + int (* attach_adapter) (struct isa_adapter *); + int (* detach_client) (struct isa_client *); + int (* command) (struct isa_client *, unsigned int cmd, void *arg); + void (* inc_use) (struct isa_client *); + void (* dec_use) (struct isa_client *); +}; + +/* A client is a specifc instance of a chip: for each detected chip, there will + be a client. Its operation is controlled by a driver. + This structure is an extension of i2c_client. */ +struct isa_client { + char name[32]; + int id; + unsigned int flags; + unsigned char addr; + struct isa_adapter *adapter; + struct isa_driver *driver; + void *data; + + /* Here ended i2c_client */ + unsigned int full_address; +}; + +/* An algorithm describes how a certain class of busses can be accessed. + A specific instance of sucj a bus is called an adapter. + This structure is essentially the same as i2c_adapter. */ +struct isa_algorithm { + char name[32]; + unsigned int id; + int (* master_xfer) (struct isa_adapter *adap, struct i2c_msg msgs[], + int num); + int (* slave_send) (struct isa_adapter *,char *, int); + int (* slave_recv) (struct isa_adapter *,char *, int); + int (* algo_control) (struct isa_adapter *, unsigned int, unsigned long); + int (* client_register) (struct isa_client *); + int (* client_unregister) (struct isa_client *); +}; + +/* An adapter is a specifc instance of a bus: for each detected bus, there will + be an adapter. Its operation is controlled by an algorithm. + SPINLOCK must be the same as declared in i2c.h. + This structure is essentially the same as i2c_algorithm. */ +struct isa_adapter { + char name[32]; + unsigned int id; + struct isa_algorithm *algo; + void *data; +#ifdef SPINLOCK + spinlock_t lock; + unsigned long lockflags; +#else + struct semaphore lock; +#endif + unsigned int flags; + struct isa_client *clients[I2C_CLIENT_MAX]; + int client_count; + int timeout; + int retries; +}; + +/* We need to mark ISA algorithms in the algorithm structure. */ +#define ALGO_ISA 0x50000 + +/* ISA Adapter ids */ +#define ISA_MAIN 1 + +/* Detect whether we are on the isa bus. If this returns true, all i2c + access will fail! */ +#define i2c_is_isa_client(clientptr) \ + ((clientptr)->adapter->algo->id == ALGO_ISA) + +/* Next: define ISA variants of registering. */ +#define isa_add_algorithm(algoptr) \ + i2c_add_algorithm((struct i2c_algorithm *) (algoptr)) +#define isa_del_algorithm(algoptr) \ + i2c_del_algorithm((struct i2c_algorithm *) (algoptr)) + +#define isa_add_adapter(adapptr) \ + i2c_add_adapter((struct i2c_adapter *) (adapptr)) +#define isa_del_adapter(adapptr) \ + i2c_del_adapter((struct i2c_adapter *) (adapptr)) + +#define isa_add_driver(driverptr) \ + i2c_add_driver((struct i2c_driver *) (driverptr)) +#define isa_del_driver(driverptr) \ + i2c_add_driver((struct i2c_driver *) (driverptr)) + +#define isa_attach_client(clientptr) \ + i2c_attach_client((struct i2c_client *) (clientptr)) +#define isa_detach_client(clientptr) \ + i2c_detach_client((struct i2c_client *) (clientptr)) + + +#endif /* ndef SENSORS_ISA_H */ diff --git a/kernel/include/isa.h b/kernel/include/isa.h new file mode 100644 index 00000000..d5ad471d --- /dev/null +++ b/kernel/include/isa.h @@ -0,0 +1,153 @@ +/* + isa.h - A Linux module for reading sensor data. + Copyright (c) 1998 Frodo Looijaard + + 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. +*/ + +#ifndef SENSORS_SENSOR_H +#define SENSORS_SENSOR_H + +/* This file must interface with Simon Vogl's i2c driver. Version 19981006 is + OK, earlier versions are not; later versions will probably give problems + too. +*/ +#ifdef I2C +#include "i2c/i2c.h" +#else /* def I2C */ +#include +#endif /* def I2C */ + +#include + +/* SPINLOCK is defined in i2c.h. */ +#ifdef SPINLOCK +#include +#else +#include +#endif + +#include "isa.h" + +/* Note that this driver is *not* built upon smbus.c, but is parallel to it. + We do not need SMBus facilities if we are on the ISA bus, after all */ + +/* Declarations, to keep the compiler happy */ +struct isa_driver; +struct isa_client; +struct isa_algorithm; +struct isa_adapter; + +/* A driver tells us how we should handle a specific kind of chip. + A specific instance of such a chip is called a client. + This structure is essentially the same as i2c_driver. */ +struct isa_driver { + char name[32]; + int id; + unsigned int flags; + int (* attach_adapter) (struct isa_adapter *); + int (* detach_client) (struct isa_client *); + int (* command) (struct isa_client *, unsigned int cmd, void *arg); + void (* inc_use) (struct isa_client *); + void (* dec_use) (struct isa_client *); +}; + +/* A client is a specifc instance of a chip: for each detected chip, there will + be a client. Its operation is controlled by a driver. + This structure is an extension of i2c_client. */ +struct isa_client { + char name[32]; + int id; + unsigned int flags; + unsigned char addr; + struct isa_adapter *adapter; + struct isa_driver *driver; + void *data; + + /* Here ended i2c_client */ + unsigned int full_address; +}; + +/* An algorithm describes how a certain class of busses can be accessed. + A specific instance of sucj a bus is called an adapter. + This structure is essentially the same as i2c_adapter. */ +struct isa_algorithm { + char name[32]; + unsigned int id; + int (* master_xfer) (struct isa_adapter *adap, struct i2c_msg msgs[], + int num); + int (* slave_send) (struct isa_adapter *,char *, int); + int (* slave_recv) (struct isa_adapter *,char *, int); + int (* algo_control) (struct isa_adapter *, unsigned int, unsigned long); + int (* client_register) (struct isa_client *); + int (* client_unregister) (struct isa_client *); +}; + +/* An adapter is a specifc instance of a bus: for each detected bus, there will + be an adapter. Its operation is controlled by an algorithm. + SPINLOCK must be the same as declared in i2c.h. + This structure is essentially the same as i2c_algorithm. */ +struct isa_adapter { + char name[32]; + unsigned int id; + struct isa_algorithm *algo; + void *data; +#ifdef SPINLOCK + spinlock_t lock; + unsigned long lockflags; +#else + struct semaphore lock; +#endif + unsigned int flags; + struct isa_client *clients[I2C_CLIENT_MAX]; + int client_count; + int timeout; + int retries; +}; + +/* We need to mark ISA algorithms in the algorithm structure. */ +#define ALGO_ISA 0x50000 + +/* ISA Adapter ids */ +#define ISA_MAIN 1 + +/* Detect whether we are on the isa bus. If this returns true, all i2c + access will fail! */ +#define i2c_is_isa_client(clientptr) \ + ((clientptr)->adapter->algo->id == ALGO_ISA) + +/* Next: define ISA variants of registering. */ +#define isa_add_algorithm(algoptr) \ + i2c_add_algorithm((struct i2c_algorithm *) (algoptr)) +#define isa_del_algorithm(algoptr) \ + i2c_del_algorithm((struct i2c_algorithm *) (algoptr)) + +#define isa_add_adapter(adapptr) \ + i2c_add_adapter((struct i2c_adapter *) (adapptr)) +#define isa_del_adapter(adapptr) \ + i2c_del_adapter((struct i2c_adapter *) (adapptr)) + +#define isa_add_driver(driverptr) \ + i2c_add_driver((struct i2c_driver *) (driverptr)) +#define isa_del_driver(driverptr) \ + i2c_add_driver((struct i2c_driver *) (driverptr)) + +#define isa_attach_client(clientptr) \ + i2c_attach_client((struct i2c_client *) (clientptr)) +#define isa_detach_client(clientptr) \ + i2c_detach_client((struct i2c_client *) (clientptr)) + + +#endif /* ndef SENSORS_ISA_H */ diff --git a/kernel/include/smbus.h b/kernel/include/smbus.h index 9aa49b13..68a27d02 100644 --- a/kernel/include/smbus.h +++ b/kernel/include/smbus.h @@ -124,6 +124,13 @@ struct smbus_adapter { /* SMBus Adapter ids */ #define SMBUS_PIIX4 1 +/* Detect whether we are on an SMBus-only bus. Note that if this returns + false, you can still use the smbus access routines, as these emulate + the SMBus on I2C. Unless they are undefined on your algorithm, of + course. */ +#define i2c_is_smbus_client(clientptr) \ + ((clientptr)->adapter->algo->id == ALGO_SMBUS) + /* This union is used within smbus_access routines */ union smbus_data { u8 byte; @@ -255,18 +262,28 @@ extern inline int smbus_write_block_data(struct smbus_adapter * adapter, return smbus_access(adapter,addr,SMBUS_WRITE,command,SMBUS_BLOCK_DATA,&data); } + /* Next: define SMBus variants of registering. */ -extern int smbus_add_algorithm(struct smbus_algorithm *algorithm); -extern int smbus_del_algorithm(struct smbus_algorithm *algorithm); -extern int smbus_add_adapter(struct smbus_adapter *adapter); -extern int smbus_del_adapter(struct smbus_adapter *adapter); +#define smbus_add_algorithm(algoptr) \ + i2c_add_algorithm((struct i2c_algorithm *) (algoptr)) +#define smbus_del_algorithm(algoptr) \ + i2c_del_algorithm((struct i2c_algorithm *) (algoptr)) -extern int smbus_add_driver(struct smbus_driver *driver); -extern int smbus_del_driver(struct smbus_driver *driver); +#define smbus_add_adapter(adapptr) \ + i2c_add_adapter((struct i2c_adapter *) (adapptr)) +#define smbus_del_adapter(adapptr) \ + i2c_del_adapter((struct i2c_adapter *) (adapptr)) -extern int smbus_attach_client(struct smbus_client *client); -extern int smbus_detach_client(struct smbus_client *client); +#define smbus_add_driver(driverptr) \ + i2c_add_driver((struct i2c_driver *) (driverptr)) +#define smbus_del_driver(driverptr) \ + i2c_add_driver((struct i2c_driver *) (driverptr)) + +#define smbus_attach_client(clientptr) \ + i2c_attach_client((struct i2c_client *) (clientptr)) +#define smbus_detach_client(clientptr) \ + i2c_detach_client((struct i2c_client *) (clientptr)) #endif /* ndef SENSORS_SMBUS_H */ diff --git a/kernel/smbus.c b/kernel/smbus.c index cb31e616..9b66e448 100644 --- a/kernel/smbus.c +++ b/kernel/smbus.c @@ -20,6 +20,7 @@ #include #include +#include "i2c.h" #ifdef SPINLOCK #include #else @@ -156,49 +157,6 @@ int smbus_client_unregister (struct smbus_client *client) return 0; } -/* Next: define SMBus variants of registering. Very boring. To make it possible - to change these definitions in the future without recompiling all modules, - we do not define them as inline. */ -int smbus_add_algorithm(struct smbus_algorithm *algorithm) -{ - return i2c_add_algorithm( (struct i2c_algorithm *) algorithm); -} - -int smbus_del_algorithm(struct smbus_algorithm *algorithm) -{ - return i2c_del_algorithm( (struct i2c_algorithm *) algorithm); -} - -int smbus_add_adapter(struct smbus_adapter *adapter) -{ - return i2c_add_adapter( (struct i2c_adapter *) adapter); -} - -int smbus_del_adapter(struct smbus_adapter *adapter) -{ - return i2c_del_adapter( (struct i2c_adapter *) adapter); -} - -int smbus_add_driver(struct smbus_driver *driver) -{ - return i2c_add_driver( (struct i2c_driver *) driver); -} - -int smbus_del_driver(struct smbus_driver *driver) -{ - return i2c_del_driver( (struct i2c_driver *) driver); -} - -int smbus_attach_client(struct smbus_client *client) -{ - return i2c_attach_client( (struct i2c_client *) client); -} - -int smbus_detach_client(struct smbus_client *client) -{ - return i2c_detach_client( (struct i2c_client *) client); -} - int smbus_init(void) { int res; diff --git a/src/Module.mk b/src/Module.mk index 9a4e96bb..a70b8304 100644 --- a/src/Module.mk +++ b/src/Module.mk @@ -22,7 +22,7 @@ MODULE_DIR := src # Regrettably, even 'simply expanded variables' will not put their currently # defined value verbatim into the command-list of rules... -SRCTARGETS := $(MODULE_DIR)/smbus.o $(MODULE_DIR)/piix4.o +SRCTARGETS := $(MODULE_DIR)/smbus.o $(MODULE_DIR)/piix4.o $(MODULE_DIR)/isa.o # Include all dependency files INCLUDEFILES += $(SRCTARGETS:.o=.d) diff --git a/src/isa.c b/src/isa.c new file mode 100644 index 00000000..8ea0b52c --- /dev/null +++ b/src/isa.c @@ -0,0 +1,191 @@ +/* + isa.c - A Linux module for reading sensor data. + Copyright (c) 1998 Frodo Looijaard + + 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. +*/ + +/* This implements an i2c algorithm/adapter for ISA bus. Not that this is + on first sight very useful; almost no functionality is preserved. + Except that it makes writing drivers for chips which can be on both + the SMBus and the ISA bus very much easier. See lm78.c for an example + of this. */ + +#include +#include + +#include "i2c.h" +#ifdef SPINLOCK +#include +#else +#include +#endif + +#include "version.h" +#include "isa.h" + +static int isa_master_xfer (struct isa_adapter *adap, + struct i2c_msg msgs[], int num); +static int isa_slave_send (struct isa_adapter *adap, char *data, int len); +static int isa_slave_recv (struct isa_adapter *adap, char *data, int len); +static int isa_algo_control (struct isa_adapter *adap, unsigned int cmd, + unsigned long arg); +static int isa_client_register (struct isa_client *client); +static int isa_client_unregister (struct isa_client *client); + +static int isa_init(void); +static int isa_cleanup(void); + +#ifdef MODULE +extern int init_module(void); +extern int cleanup_module(void); +#endif /* MODULE */ + +/* This is the actual algorithm we define */ +static struct isa_algorithm isa_algorithm = { + /* name */ "ISA bus adapter", + /* id */ ALGO_ISA, + /* master_xfer */ &isa_master_xfer, + /* slave_send */ &isa_slave_send, + /* slave_rcv */ &isa_slave_recv, + /* algo_control */ &isa_algo_control, + /* client_register */ &isa_client_register, + /* client_unregister*/&isa_client_unregister +}; + +/* There can only be one... */ +static struct isa_adapter isa_adapter; + +/* Used in isa_init/cleanup */ +static int isa_initialized; + +/* Algorithm master_xfer call-back implementation. Can't do that... */ +int isa_master_xfer (struct isa_adapter *adap, struct i2c_msg msgs[], + int num) +{ + printk("isa_master_xfer called for adapter `%s' " + "(no i2c level access possible!)\n", + adap->name); + return 0; +} + +/* Algorithm slave_send call-back implementation. Can't do that... */ +int isa_slave_send (struct isa_adapter *adap, char *data, int len) +{ + printk("isa_slave_send called for adapter `%s' " + "(no i2c level access possible!)\n", + adap->name); + return 0; +} + +/* Algorithm slave_recv call-back implementation. Can't do that... */ +int isa_slave_recv (struct isa_adapter *adap, char *data, int len) +{ + printk("isa_slave_recv called for adapter `%s' " + "(no i2c level access possible!)\n", + adap->name); + return 0; +} + +/* Here we can put additional calls to modify the workings of the algorithm. + But right now, there is no need for that. */ +int isa_algo_control (struct isa_adapter *adap, unsigned int cmd, + unsigned long arg) +{ + return 0; +} + +/* Ehm... This is called when a client is registered to an adapter. We could + do all kinds of neat stuff here like, ehm - returning success? */ +int isa_client_register (struct isa_client *client) +{ + return 0; +} + +int isa_client_unregister (struct isa_client *client) +{ + return 0; +} + +int isa_init(void) +{ + int res; + printk("isa.o version %s (%s)\n",LM_VERSION,LM_DATE); +#ifdef DEBUG + if (isa_initialized) { + printk("isa.o: Oops, isa_init called a second time!\n"); + return -EBUSY; + } +#endif + isa_initialized = 0; + if ((res = isa_add_algorithm(&isa_algorithm))) { + printk("isa.o: Algorithm registration failed, module isa.o not inserted\n"); + isa_cleanup(); + return res; + } + isa_initialized++; + strcpy(isa_adapter.name,"ISA main adapter"); + isa_adapter.id = ALGO_ISA | ISA_MAIN; + isa_adapter.algo = &isa_algorithm; + if ((res = isa_add_adapter(&isa_adapter))) { + printk("isa.o: Adapter registration failed, " + "module isa.o is not inserted\n"); + isa_cleanup(); + return res; + } + isa_initialized++; + printk("isa.o: ISA bus access for i2c modules initialized\n"); + return 0; +} + +int isa_cleanup(void) +{ + int res; + if (isa_initialized >= 2) + { + if ((res = isa_del_adapter(&isa_adapter))) { + printk("isa.o: isa_del_adapter failed, module not removed\n"); + return res; + } else + isa_initialized--; + } + if (isa_initialized >= 1) + { + if ((res = isa_del_algorithm(&isa_algorithm))) { + printk("isa.o: isa_del_algorithm failed, module not removed\n"); + return res; + } else + isa_initialized--; + } + return 0; +} + +#ifdef MODULE + +MODULE_AUTHOR("Frodo Looijaard "); +MODULE_DESCRIPTION("ISA bus access through i2c"); + +int init_module(void) +{ + return isa_init(); +} + +int cleanup_module(void) +{ + return isa_cleanup(); +} + +#endif /* MODULE */ + diff --git a/src/isa.h b/src/isa.h new file mode 100644 index 00000000..d5ad471d --- /dev/null +++ b/src/isa.h @@ -0,0 +1,153 @@ +/* + isa.h - A Linux module for reading sensor data. + Copyright (c) 1998 Frodo Looijaard + + 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. +*/ + +#ifndef SENSORS_SENSOR_H +#define SENSORS_SENSOR_H + +/* This file must interface with Simon Vogl's i2c driver. Version 19981006 is + OK, earlier versions are not; later versions will probably give problems + too. +*/ +#ifdef I2C +#include "i2c/i2c.h" +#else /* def I2C */ +#include +#endif /* def I2C */ + +#include + +/* SPINLOCK is defined in i2c.h. */ +#ifdef SPINLOCK +#include +#else +#include +#endif + +#include "isa.h" + +/* Note that this driver is *not* built upon smbus.c, but is parallel to it. + We do not need SMBus facilities if we are on the ISA bus, after all */ + +/* Declarations, to keep the compiler happy */ +struct isa_driver; +struct isa_client; +struct isa_algorithm; +struct isa_adapter; + +/* A driver tells us how we should handle a specific kind of chip. + A specific instance of such a chip is called a client. + This structure is essentially the same as i2c_driver. */ +struct isa_driver { + char name[32]; + int id; + unsigned int flags; + int (* attach_adapter) (struct isa_adapter *); + int (* detach_client) (struct isa_client *); + int (* command) (struct isa_client *, unsigned int cmd, void *arg); + void (* inc_use) (struct isa_client *); + void (* dec_use) (struct isa_client *); +}; + +/* A client is a specifc instance of a chip: for each detected chip, there will + be a client. Its operation is controlled by a driver. + This structure is an extension of i2c_client. */ +struct isa_client { + char name[32]; + int id; + unsigned int flags; + unsigned char addr; + struct isa_adapter *adapter; + struct isa_driver *driver; + void *data; + + /* Here ended i2c_client */ + unsigned int full_address; +}; + +/* An algorithm describes how a certain class of busses can be accessed. + A specific instance of sucj a bus is called an adapter. + This structure is essentially the same as i2c_adapter. */ +struct isa_algorithm { + char name[32]; + unsigned int id; + int (* master_xfer) (struct isa_adapter *adap, struct i2c_msg msgs[], + int num); + int (* slave_send) (struct isa_adapter *,char *, int); + int (* slave_recv) (struct isa_adapter *,char *, int); + int (* algo_control) (struct isa_adapter *, unsigned int, unsigned long); + int (* client_register) (struct isa_client *); + int (* client_unregister) (struct isa_client *); +}; + +/* An adapter is a specifc instance of a bus: for each detected bus, there will + be an adapter. Its operation is controlled by an algorithm. + SPINLOCK must be the same as declared in i2c.h. + This structure is essentially the same as i2c_algorithm. */ +struct isa_adapter { + char name[32]; + unsigned int id; + struct isa_algorithm *algo; + void *data; +#ifdef SPINLOCK + spinlock_t lock; + unsigned long lockflags; +#else + struct semaphore lock; +#endif + unsigned int flags; + struct isa_client *clients[I2C_CLIENT_MAX]; + int client_count; + int timeout; + int retries; +}; + +/* We need to mark ISA algorithms in the algorithm structure. */ +#define ALGO_ISA 0x50000 + +/* ISA Adapter ids */ +#define ISA_MAIN 1 + +/* Detect whether we are on the isa bus. If this returns true, all i2c + access will fail! */ +#define i2c_is_isa_client(clientptr) \ + ((clientptr)->adapter->algo->id == ALGO_ISA) + +/* Next: define ISA variants of registering. */ +#define isa_add_algorithm(algoptr) \ + i2c_add_algorithm((struct i2c_algorithm *) (algoptr)) +#define isa_del_algorithm(algoptr) \ + i2c_del_algorithm((struct i2c_algorithm *) (algoptr)) + +#define isa_add_adapter(adapptr) \ + i2c_add_adapter((struct i2c_adapter *) (adapptr)) +#define isa_del_adapter(adapptr) \ + i2c_del_adapter((struct i2c_adapter *) (adapptr)) + +#define isa_add_driver(driverptr) \ + i2c_add_driver((struct i2c_driver *) (driverptr)) +#define isa_del_driver(driverptr) \ + i2c_add_driver((struct i2c_driver *) (driverptr)) + +#define isa_attach_client(clientptr) \ + i2c_attach_client((struct i2c_client *) (clientptr)) +#define isa_detach_client(clientptr) \ + i2c_detach_client((struct i2c_client *) (clientptr)) + + +#endif /* ndef SENSORS_ISA_H */ diff --git a/src/smbus.c b/src/smbus.c index cb31e616..9b66e448 100644 --- a/src/smbus.c +++ b/src/smbus.c @@ -20,6 +20,7 @@ #include #include +#include "i2c.h" #ifdef SPINLOCK #include #else @@ -156,49 +157,6 @@ int smbus_client_unregister (struct smbus_client *client) return 0; } -/* Next: define SMBus variants of registering. Very boring. To make it possible - to change these definitions in the future without recompiling all modules, - we do not define them as inline. */ -int smbus_add_algorithm(struct smbus_algorithm *algorithm) -{ - return i2c_add_algorithm( (struct i2c_algorithm *) algorithm); -} - -int smbus_del_algorithm(struct smbus_algorithm *algorithm) -{ - return i2c_del_algorithm( (struct i2c_algorithm *) algorithm); -} - -int smbus_add_adapter(struct smbus_adapter *adapter) -{ - return i2c_add_adapter( (struct i2c_adapter *) adapter); -} - -int smbus_del_adapter(struct smbus_adapter *adapter) -{ - return i2c_del_adapter( (struct i2c_adapter *) adapter); -} - -int smbus_add_driver(struct smbus_driver *driver) -{ - return i2c_add_driver( (struct i2c_driver *) driver); -} - -int smbus_del_driver(struct smbus_driver *driver) -{ - return i2c_del_driver( (struct i2c_driver *) driver); -} - -int smbus_attach_client(struct smbus_client *client) -{ - return i2c_attach_client( (struct i2c_client *) client); -} - -int smbus_detach_client(struct smbus_client *client) -{ - return i2c_detach_client( (struct i2c_client *) client); -} - int smbus_init(void) { int res; diff --git a/src/smbus.h b/src/smbus.h index 9aa49b13..68a27d02 100644 --- a/src/smbus.h +++ b/src/smbus.h @@ -124,6 +124,13 @@ struct smbus_adapter { /* SMBus Adapter ids */ #define SMBUS_PIIX4 1 +/* Detect whether we are on an SMBus-only bus. Note that if this returns + false, you can still use the smbus access routines, as these emulate + the SMBus on I2C. Unless they are undefined on your algorithm, of + course. */ +#define i2c_is_smbus_client(clientptr) \ + ((clientptr)->adapter->algo->id == ALGO_SMBUS) + /* This union is used within smbus_access routines */ union smbus_data { u8 byte; @@ -255,18 +262,28 @@ extern inline int smbus_write_block_data(struct smbus_adapter * adapter, return smbus_access(adapter,addr,SMBUS_WRITE,command,SMBUS_BLOCK_DATA,&data); } + /* Next: define SMBus variants of registering. */ -extern int smbus_add_algorithm(struct smbus_algorithm *algorithm); -extern int smbus_del_algorithm(struct smbus_algorithm *algorithm); -extern int smbus_add_adapter(struct smbus_adapter *adapter); -extern int smbus_del_adapter(struct smbus_adapter *adapter); +#define smbus_add_algorithm(algoptr) \ + i2c_add_algorithm((struct i2c_algorithm *) (algoptr)) +#define smbus_del_algorithm(algoptr) \ + i2c_del_algorithm((struct i2c_algorithm *) (algoptr)) -extern int smbus_add_driver(struct smbus_driver *driver); -extern int smbus_del_driver(struct smbus_driver *driver); +#define smbus_add_adapter(adapptr) \ + i2c_add_adapter((struct i2c_adapter *) (adapptr)) +#define smbus_del_adapter(adapptr) \ + i2c_del_adapter((struct i2c_adapter *) (adapptr)) -extern int smbus_attach_client(struct smbus_client *client); -extern int smbus_detach_client(struct smbus_client *client); +#define smbus_add_driver(driverptr) \ + i2c_add_driver((struct i2c_driver *) (driverptr)) +#define smbus_del_driver(driverptr) \ + i2c_add_driver((struct i2c_driver *) (driverptr)) + +#define smbus_attach_client(clientptr) \ + i2c_attach_client((struct i2c_client *) (clientptr)) +#define smbus_detach_client(clientptr) \ + i2c_detach_client((struct i2c_client *) (clientptr)) #endif /* ndef SENSORS_SMBUS_H */ diff --git a/version.h b/version.h index 64a5df4a..0c7e1b29 100644 --- a/version.h +++ b/version.h @@ -1,2 +1,2 @@ -#define LM_DATE "19981103" -#define LM_VERSION "2.0.0pre0" +#define LM_DATE "19981122" +#define LM_VERSION "2.0.0pre1"