diff --git a/README.directories b/README.directories
new file mode 100644
index 00000000..0654fad0
--- /dev/null
+++ b/README.directories
@@ -0,0 +1,14 @@
+The directories within this package:
+
+* CVS
+ The CVS directories. Do not touch these!
+* archive
+ Packages from other sources. Currently, it contains Simon Vogl's i2c code
+ (mod-????????.tar.gz).
+* doc
+ Documentation about the modules within this package
+* i2c
+ Simon Vogl's i2c module, including any necessary patches, excluding any
+ files which are removed by 'make clean'.
+* src
+ Our own code.
diff --git a/archive/mod-19981006.tar.gz b/archive/mod-19981006.tar.gz
new file mode 100644
index 00000000..33152d7f
Binary files /dev/null and b/archive/mod-19981006.tar.gz differ
diff --git a/doc/design b/doc/design
new file mode 100644
index 00000000..89f2cd3d
--- /dev/null
+++ b/doc/design
@@ -0,0 +1,497 @@
+This is a design for version 2 of our smbus and lm_sensors module. This
+document is Copyright (c) 1998 by Frodo Looijaard. You may freely copy and
+distribute it, as long as you recognize me as the author, and mark any
+changes you make as being your own, and distribute this notice with it.
+
+Document version 1.0, 19981101.
+
+
+Object oriented approach
+========================
+
+The i2c module structs contain callback functions and data fields. In the
+i2c module, these structures are only referenced by pointers. This makes
+is easy to extend these structs to contain additional information or
+callback functions. For those familiar with object oriented languages,
+you can see the smbus structures as an object extension of the i2c
+structures, and the sensors structures are an extenstion of the smbus
+structures.
+
+To make this clearer, I will show in an example how this is done. Note
+that I have simplified some things here, so this example does not
+correspond to an actual struct found in one of the modules.
+
+In the i2c module, you can find a struct somewhat like this:
+
+struct i2c_adapter {
+ char name[32];
+ int (*detach_client) (struct i2c_client *);
+ struct i2c_adapter *next;
+}
+
+We have a plain data field (name), a call-back function which needs one
+parameter (a pointer to a i2c_client struct), and a data field which is
+a pointer to the next adapater.
+
+Now we want to extend this structure. We need another data field,
+containing a number of flags. We will call this new structure smbus_adapter.
+A few other things change too:
+
+struct smbus_adapter {
+ char name[32];
+ int (*detach_client) (struct smbus_client *);
+ struct smbus_adapter *next;
+ unsigned int flags;
+}
+
+So we copy all existing fields. The next field still points to the next
+adapter - but it is now of type smbus_adapter, not i2c_adapter. And the
+call-back function takes now a parameter of type pointer to smbus_client.
+And there is a new data field, called flags.
+
+Now examine this function definition:
+
+int fully_detach_i2c_client (struct i2c_client * client)
+{
+ res = 0;
+ struct i2c_adapter *current_adapter = first_adapter; /* a global var. */
+ while (current_adapter) {
+ res |= (current_adapter -> detach_client) (client);
+ current_adapter = current_adapter -> next;
+ }
+ return res;
+}
+
+This function detaches a client from all adapters. Nice. But now comes the
+Big Trick(tm): we can still use this function for smbus_adapters!
+
+int fully_detach_smbus_client (struct smbus_client * client)
+{
+ return fully_detach_i2c_client( (struct i2c_client *) client);
+}
+
+All we needed here was a simple typecast. Datapointers remain datapointers,
+so this can safely be done. And because we use call-back functions, the
+actual function called to detach a client from a single adapter might
+be the same, or different, depending on what function was put in
+client->detach_client!
+
+It gets even better. The i2c module stores internally all registered
+adapters. But it stores pointers to the i2c_adapter struct, not the
+structs themselves! So there is an array:
+
+#define I2C_ADAPTER_MAX 32
+struct i2c_adapter *adapters[I2C_ADAPTER_MAX];
+/* this is an array of pointers to structs, not vice versa! */
+
+So, an element of this array might in fact point to a smbus_adapter, instead
+of an i2c_adapter! If you know this for sure, you might use a typecast and
+access the additional fields. In the meantime, the i2c internal
+administration remains valid.
+
+We have to thank Simon Vogl and Gerd Knorr for the way they implemented
+their i2c module. Any other way would have made this approach impossible,
+and basing anything upon their module much more difficult.
+
+
+Module overview
+===============
+
+All in all, lots of modules will be stacked on each other. Too bad, but
+that is the only way to cleanly implement everything. Note that in a
+specific situation, only a few modules may need to be loaded. sensor.o,
+for example, does not depend on smbus.o (in the sense that you can load
+sensor.o without loading smbus.o). A specific bus driver, though, will
+depend on many of them.
+
+Generally:
+ sensor.o depends on nothing
+ smbus.o depends on nothing
+ i2c.o depends on nothing.
+
+ isa.o depends only on sensor.o
+ A non-i2c SMBus bus driver depends only on smbus.o
+ A i2c bus driver depends only on i2c.o
+
+ A sensor chip driver depends at least on sensor.o, and possibly on smbus.o
+ A SMBus chip driver depends only on smbus.o
+ A I2C chip driver depends only on i2c.o
+
+
+sensor.o
+Main sensors handling
+Unites SMBus adapters and ISA adapters.
+
+ isa.o
+ Implements the ISA adapter driver for sensor.o. This may prove to be so
+ closely integrated that it can better be made part of sensor.o
+
+
+smbus.o
+Main SMBus handling
+Unites I2C adapters and SMBus hosts (like the PIIX4)
+
+ piix4.o
+ SMBus adapter driver for the PIIX4 SMBus host.
+
+ ????.o
+ Adapter driver for another SMBus host
+
+
+i2c.o
+Main i2c handling
+
+ ????.o
+ I2C adapter driver
+ Implementing a class of I2C busses
+
+
+A chip driver (typically defined in its own module) can be hooked on all
+these levels:
+ * If it is a sensor chip, it should be hooked to sensor.o
+ * An SMBus chip should be hooked to smbus.o
+ * An I2C chip should be hooked to i2c.o
+It can be difficult to decide whether a specific chip should be hoooked to
+smbus.o or i2c.o. A good deciding question is, 'could it be connected to
+a PIIX4?'
+
+
+Module i2c.o
+============
+
+This is Simon Vogl's i2c module (this one is different from the i2c module
+included in kernels around 1.2.120!).
+
+A driver
+--------
+
+struct sensor_driver {
+ char name[32];
+ int id;
+ unsigned int flags;
+ int (* attach_adapter) (struct i2c_adapter *);
+ int (* detach_client) (struct i2c_client *);
+ int (* command) (struct i2c_client *, unsigned int cmd, void *arg);
+ void (* inc_use) (struct i2c_client *);
+ void (* dec_use) (struct i2c_client *);
+}
+
+A driver tells us how we should handle a specific type of i2c chip. An
+instance of such a chip is called a 'client'. An example would be the LM75
+module: it would contain only one driver, which tells us how to handle the
+LM75; but each detected LM75 would be a separate client (which would be
+dynamically allocated).
+
+
+A description of the above struct:
+ name: The name of this driver
+ id: A unique driver identifier
+ flags: Flags to set certain kinds of behaviour (not used right now)
+ attach_adapter: A call-back function which is called if a new adapter (bus)
+ is found. This allows us to do our detection stuff on the new adapter,
+ and register new clients.
+ detach_client: A call-back function which is called if a specific client
+ which uses this driver should be disallocated. If a specific sensor module
+ is removed, for instance, this function would be called for each registered
+ client.
+ command: A generic call-back function to communicate in a driver-dependent
+ way with a specific client. This should only be seldom needed.
+ inc_use: Can be called to add one to an internal 'use' counter. This can be
+ used to control when it is safe to remove this module, for example.
+
+
+A client
+--------
+
+struct i2c_client {
+ char name[32];
+ int id;
+ unsigned int flags;
+ unsigned char addr;
+ struct i2c_adapter *adapter;
+ struct i2c_driver *driver;
+ void *data;
+}
+
+A client is a specific sensor chip. Its operation is controlled by a driver
+(which describes a type of sensor chip), and it is connected to an adapter
+(a bus).
+
+A description of the above struct:
+ name: The name of this client
+ id: A unique client id
+ flags: Flags to set certain kinds of behaviour (not very important)
+ addr: The client address. 10-bit addresses are a bit of a kludge right now.
+ adapter: A pointer to the adapter this client is on.
+ driver: A pointer to the driver this client uses.
+ data: Additional, client-dependent data
+
+
+An algorithm
+------------
+
+struct i2c_algorithm {
+ char name[32];
+ unsigned int id;
+ int (* master_xfer) (struct i2c_adapter *adap, struct i2c_msg msgs[],
+ int num);
+ int (* slave_send) (struct i2c_adapter *,char *, int);
+ int (* slave_recv) (struct i2c_adapter *,char *, int);
+ int (* algo_control) (struct i2c_adapter *, unsigned int, unsigned long);
+ int (* client_register) (struct i2c_client *);
+ int (* client_unregister) (struct i2c_client *);
+}
+
+An algorithm describes how a certain class of i2c busses can be accessed.
+
+A description of the above struct:
+ name: The name of this algorithm
+ id: A unique algorithm id
+ master_xfer: Transfer a bunch of messages through a specific i2c bus.
+ slave_send: Send a message as if we are a slave device
+ slave_recv: Receive a message as if we are a slave device
+ client_register: Register a new client
+ client_unregister: Unregister a client
+
+
+An adapter
+----------
+
+struct i2c_adapter {
+ char name[32];
+ unsigned int id;
+ struct i2c_algorithm *algo;
+ void *data;
+#ifdef SPINLOCK
+ spinlock_t lock;
+ unsigned long lockflags;
+#else
+ struct semaphore lock;
+#endif
+ unsigned int flags;
+ struct i2c_client *clients[I2C_CLIENT_MAX];
+ int client_count;
+ int timeout;
+ int retries;
+}
+
+An adapter is a specific i2c bus. How to access it is defined in the
+algorithm associated with it.
+
+A description of the above struct:
+ name: The name of this adapter
+ id: A unique adapter id
+ algo: The algorithm through which this bus must be accessed
+ data: Adapter specific data
+ lock, lockflags: To lock out simultaneous adapter access
+ flags: Modifiers for adapter operation
+ clients: All currently connected clients
+ client_count: The number of currently connected clients
+ timeout, retries: Internal variables (unimportant here).
+
+
+Access functions
+----------------
+
+All these functions are defined extern.
+
+int i2c_master_send(struct i2c_client *,const char *, int);
+int i2c_master_recv(struct i2c_client *,char *, int);
+int i2c_transfer(struct i2c_adapter *,struct i2c_msg [], int num);
+
+These function respectively send one message to a client, receive one message
+from a client, or transmit a bunch of messages. struct i2c_msg contains
+an i2c address to communicate with, and can both read from and write to this
+address.
+
+
+int i2c_slave_send(struct i2c_client *, char *, int);
+int i2c_slave_recv(struct i2c_client *, char *, int);
+
+Communicate with another master as if the normal master is a common slave
+device.
+
+
+There are several other functions, to register things for example, that
+are less important to us.
+
+
+Module smbus.o
+==============
+
+This module offers support for SMBus operation. An SMBus adapter can either
+accept SMBus commands (like the PIIX4), or be in fact an I2C driver. In
+the last case, all SMBus commands will be expressed through I2C primitives.
+This means that any I2C adapter driver will automatically be a SMBus
+driver.
+
+At this point, it should be noted that there can only be one System
+Management Bus in a given system (is this really true, by the way?). This
+means there must be some way of selecting which of the many possible adapters
+is in fact *the* SMBus. For now, I will ignore this problem. Later on,
+we can add a hook somewhere in the i2c module to help us decide this.
+
+
+A driver, client and adapter
+-------------------
+
+We will not need to extend i2c_driver, i2c_client or i2c_adapter. This means
+that struct smbus_driver is exactly the same as struct i2c_driver, and
+struct smbus_client is the same as struct i2c_client, and smbus_adapter is
+the same as struct i2c_adapter. We *will* define the smbus_* variants, and
+use them within this module, so it should be easy to extend them after all.
+
+Note that at this moment, 10 bit SMBus addresses seem to be only
+partially supported by the i2c module. We will ignore this issue for
+now.
+
+
+An algorithm
+------------
+
+struct smbus_algorithm {
+ char name[32];
+ unsigned int id;
+ int (* master_xfer) (struct smbus_adapter *adap, struct smbus_msg msgs[],
+ int num);
+ int (* slave_send) (struct smbus_adapter *,char *, int);
+ int (* slave_recv) (struct smbus_adapter *,char *, int);
+ int (* algo_control) (struct smbus_adapter *, unsigned int, unsigned long);
+ int (* client_register) (struct smbus_client *);
+ int (* client_unregister) (struct smbus_client *);
+
+ int (* smbus_access) (struct smbus_adapter *, __u8 addr, char read_write,
+ __u8 command, int size, union smbus_data * data);
+}
+
+
+A description of the above struct:
+ smbus_access: A function to access the SMBus. If the algorithm describes
+ a i2c bus, it will use master_xfer to simulate this operation. In
+ case of a PIIX4, master_xfer, slave_send and slave_recv will not be
+ implemented.
+
+
+Access functions
+----------------
+
+All these functions are defined extern.
+
+The i2c access function should not be used within SMBus chip drivers, as
+they might not be defined (for the PIIX4, for example). Instead, use the
+following general access function, or one of the easier functions based
+on it:
+
+int smbus_access (struct smbus_adapter *, __u8 addr, char read_write,
+ __u8 command, int size, union smbus_data * data);
+
+There will be specific SMBus registration functions too, like the i2c
+ones.
+
+
+Module sensors.o
+================
+
+This module acts as a coordinations point between specific sensor modules
+(which each support a certain kind of sensor). We need this module to unite
+SMBus access and ISA access.
+
+
+A driver or adapter
+-------------------
+
+We will not need to extend smbus_driver or smbus_adapter. This means that
+struct sensor_driver is exactly the same as struct smbus_driver, and struct
+sensor_adapter is the same as struct smbus_adapter. We *will* define the
+sensor_* variants, and use them within this module, so it should be easy to
+extend them after all.
+
+Note that a driver can be for a chip on either the ISA bus or the
+I2C/SMBus. If a specific chip can be on both, you must check variable
+client->adapter->algorithm->on_isa to determine which bus you need to access.
+
+
+A client
+--------
+
+struct sensor_client {
+ char name[32];
+ int id;
+ unsigned int flags;
+ unsigned char addr;
+ struct sensor_adapter *adapter;
+ struct sensor_driver *driver;
+ void *data;
+
+ unsigned int full_address;
+}
+
+A client is a specific sensor chip. Its operation is controlled by a driver
+(which describes a type of sensor chip), and it is connected to an adapter
+(a bus, either a I2C/SMBus or the ISA bus).
+
+A description of the above struct:
+ full_address: The full client address. ISA addresses and 10-bit SMBus
+ addresses do not fit in the i2c-compatible addr field, so we needed
+ a new field.
+
+
+
+An algorithm
+------------
+
+struct sensor_algorithm {
+ char name[32];
+ unsigned int id;
+ int (* master_xfer) (struct sensor_adapter *adap, struct smbus_msg msgs[],
+ int num);
+ int (* slave_send) (struct sensor_adapter *,char *, int);
+ int (* slave_recv) (struct sensor_adapter *,char *, int);
+ int (* algo_control) (struct sensor_adapter *, unsigned int, unsigned long);
+ int (* client_register) (struct sensor_client *);
+ int (* client_unregister) (struct sensor_client *);
+
+ int (* smbus_access) (struct sensor_adapter *, __u8 addr, char read_write,
+ __u8 command, int size, union smbus_data * data);
+ int isa_bus;
+}
+
+A description of the above struct:
+ isa_bus: 0 if this structure describes SMBus access, 1 if it describes
+ ISA access.
+
+In case of the ISA bus, the master_xfer, slave_send, slave_recv and
+smbus_access hooks will be NULL, because these functions make no sense.
+It is regrettably not easy to create an access abstraction in which both
+ISA bus access and SMBus access are united. See below for examples how
+you can solve this problem.
+
+
+Access functions
+----------------
+
+All these functions are defined extern.
+
+The most imporant additional access function:
+
+ int is_on_isa (struct sensor_client *);
+
+This function tells us whether a specific client is connected to the ISA
+bus or to the SMBus. This is important, because it determines whether we
+can use the SMBus access routines.
+
+As an example, I will here implement our old LM78 access function:
+
+u8 lm78_read_value(struct sensor_client *client, u8 register)
+{
+ if (is_on_isa(client)) {
+ /* Ignore the check for LM78_BUSY to keep things simple here; the best
+ place to put this semaphore struct would be in client->data */
+ outb_p(register,client->address + LM78_ADDR_REG_OFFSET);
+ return inb_p(client->address + LM78_DATA_REG_OFFSET);
+ } else
+ return smbus_read_byte_data(client,register);
+ /* This is a standard function based on smbus_access */
+}
+
+
diff --git a/doc/useful_addresses.html b/doc/useful_addresses.html
new file mode 100644
index 00000000..ec85655f
--- /dev/null
+++ b/doc/useful_addresses.html
@@ -0,0 +1,60 @@
+
+
+
+I²C, SMBus and hardware monitoring references
+
+
+I²C, SMBus and hardware monitoring references
+This document contains all kinds of useful references to I²C and SMBus
+documents and implementations, and to hardware sensors documentation and
+implementations. Please report any other references you have found!
+
+- I²C
+
+
- SMBus
+
+
- Hardware monitoring chips
+
+
- Hardware monitoring implementations
+
+
+
+
diff --git a/i2c/Makefile b/i2c/Makefile
new file mode 100644
index 00000000..ed1a7663
--- /dev/null
+++ b/i2c/Makefile
@@ -0,0 +1,40 @@
+#################################################
+# config
+KERNEL_LOCATION=/usr/src/linux
+CURRENT=$(shell uname -r)
+
+#################################################
+# some magic for using linux kernel settings
+# when compiling module(s)
+
+MOD_SUB_DIRS = drivers
+#MX_OBJS = i2c-core.o algo-bit.o i2c-dev.o bit-lp.o bit-velle.o algo-pcf.o
+MX_OBJS = i2c-core.o algo-bit.o i2c-dev.o
+
+M_OBJS = bit-lp.o bit-velle.o bit-mb.o
+EXTRA_CFLAGS = -Wno-unused
+
+here:
+ DIR=`pwd`; (cd $(KERNEL_LOCATION); make SUBDIRS=$$DIR modules)
+
+install:
+ su -c "cp -v $(M_OBJS) $(MX_OBJS) /lib/modules/$(CURRENT)/misc"
+
+clean:
+ -rm -f $(M_OBJS) $(MX_OBJS) .*.o.flags *~
+
+up:
+ insmod i2c-core.o i2c_debug=0
+ insmod algo-bit.o bit_test=1 i2c_debug=1
+ insmod bit-lp.o base=0x278
+ insmod i2c-dev.o
+ insmod drivers/eeprom.o test=1
+
+down:
+ -rmmod eeprom
+ -rmmod i2c-dev
+ -rmmod bit-lp
+ -rmmod algo-bit
+ -rmmod i2c-core
+
+include $(KERNEL_LOCATION)/Rules.make
diff --git a/i2c/README b/i2c/README
new file mode 100644
index 00000000..b87e646a
--- /dev/null
+++ b/i2c/README
@@ -0,0 +1,22 @@
+Okay, a new version is born...
+There are still many files from the old version lying around that
+need to be ported - anyone have spare time ?
+
+Currently, the following modules are running in the new mode:
+ i2c.c - main admin module & common interface
+ i2c-dev.c - character device interface for the bus
+ algo-bit.c - Algorithms for bit banging
+ bit-lp.c - hw part for parallel port adapter, Philips interface
+ bit-velle.c - hw part for parallel port adapter, Vellemann K9000
+ bit-mb - VIA Chipset motherboards' SMBus -> see README.bitmb
+
+The other modules, esp. algo-pcf.c still need to be converted. For the
+hw specific mods, this should be relatively easy & quick.
+
+A simple driver example is in drivers -- a piece of code to access EEPROMs.
+
+Simon (simon@tk.uni-linz.ac.at)
+
+For more detailed documentation have a look at
+http://www.tk.uni-linz.ac.at/~simon/private/i2c
+
diff --git a/i2c/README.bitmb b/i2c/README.bitmb
new file mode 100644
index 00000000..d739e86b
--- /dev/null
+++ b/i2c/README.bitmb
@@ -0,0 +1,36 @@
+
+ README for bit-mb.c and hw-monitor.c
+ September 23, 1998. Kyösti Mälkki
+
+ The questions you would probably want to ask
+ about bit-mb and hw-monitor, here are the answers.
+
+What are bit-mb.c and hw-monitor.c?
+
+ Both are new modules for Simon G. Vogl's i2c-driver for Linux:
+
+ Bit-mb gives you access to motherboard's SMBus (or i2c -bus).
+ You should have VIA VT82C586B South Bridge, and this is verified on
+ module-load. On some motherboards, you must enable USB -support in BIOS-setup
+ to make it active, check this with pciutils or in /proc/pci.
+ NOTE: Accessing wrong registers on PCI-chipset is likely to lock your
+ computer. If your hardware goes BOOOMMM, don't blame me.
+
+ Hw-monitor is an i2c-driver for GL518SM (by Genesys Logic) chip, used in my
+ cpu fan (FAN78, EISCA-compatible). This gives you /proc/temperature to show
+ your cpu temperature. It is not tested with FAN79 (GL520SM), I will get the
+ datasheet for that in a few days.
+
+
+Problems?
+
+ This is not near alpha-level, but it works with my FIC-VA503+.
+ There is no quarantee your motherboard manufacturer has used the VIA
+ recommended pins for i2c-lines... With my FIC, they have.
+
+ For error reports, turn i2c-debugging on. Check Simon's sourcecode
+ files for how to do that.
+
+ Please report any success or failure with possible logfiles to me:
+
+ Kyösti Mälkki kmalkki@cc.hut.fi
diff --git a/i2c/algo-bit.c b/i2c/algo-bit.c
new file mode 100644
index 00000000..bea9d109
--- /dev/null
+++ b/i2c/algo-bit.c
@@ -0,0 +1,665 @@
+/* ------------------------------------------------------------------------- */
+/* adap-bit.c i2c driver algorithms for bit-shift adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-97 Simon G. Vogl
+
+ 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. */
+/* ------------------------------------------------------------------------- */
+static char alg_rcsid[] = "$Id: algo-bit.c,v 1.7 1998/09/28 06:45:38 i2c Exp i2c $";
+
+#include
+#include
+#include
+#include
+#include
+
+
+#if LINUX_VERSION_CODE >= 0x020100
+# include
+#else
+# include
+#endif
+
+
+#include
+#include
+#include
+
+#include "i2c.h"
+#include "algo-bit.h"
+
+/* ----- global defines ----------------------------------------------- */
+#define DEB(x) if (i2c_debug>=1) x;
+#define DEB2(x) if (i2c_debug>=2) x;
+#define DEBSTAT(x) if (i2c_debug>=3) x; /* print several statistical values*/
+#define DEBPROTO(x) if (i2c_debug>=9) x;
+ /* debug the protocol by showing transferred bits */
+
+/* debugging - slow down transfer to have a look at the data .. */
+/* I use this with two leds&resistors, each one connected to sda,scl */
+/* respectively. This makes sure that the algorithm works. Some chips */
+/* might not like this, as they have an internal timeout of some mils */
+/*
+#if LINUX_VERSION_CODE >= 0x02016e
+#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
+ if (need_resched) schedule();
+#else
+#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
+ if (need_resched) schedule();
+#endif
+*/
+
+
+/* ----- global variables --------------------------------------------- */
+
+#ifdef SLO_IO
+ int jif;
+#endif
+
+/* module parameters:
+ */
+int i2c_debug=1;
+int bit_test=0; /* see if the line-setting functions work */
+int bit_scan=0; /* have a look at what's hanging 'round */
+
+/*
+ * This array contains the hw-specific functions for
+ * each port (hardware) type.
+ */
+struct bit_adapter *bit_adaps[BIT_ADAP_MAX];
+int adap_count;
+struct i2c_adapter *i2c_adaps[BIT_ADAP_MAX];
+
+/* --- setting states on the bus with the right timing: --------------- */
+
+#define setsda(adap,val) adap->setsda(adap->data, val)
+#define setscl(adap,val) adap->setscl(adap->data, val)
+#define getsda(adap) adap->getsda(adap->data)
+#define getscl(adap) adap->getscl(adap->data)
+
+inline void sdalo(struct bit_adapter *adap)
+{
+ setsda(adap,0);
+ udelay(adap->udelay);
+}
+
+inline void sdahi(struct bit_adapter *adap)
+{
+ setsda(adap,1);
+ udelay(adap->udelay);
+}
+
+inline void scllo(struct bit_adapter *adap)
+{
+ setscl(adap,0);
+ udelay(adap->udelay);
+#ifdef SLO_IO
+ SLO_IO
+#endif
+}
+
+/*
+ * Raise scl line, and do checking for delays. This is necessary for slower
+ * devices.
+ */
+inline int sclhi(struct bit_adapter *adap)
+{
+ int start=jiffies;
+
+ setscl(adap,1);
+
+ udelay(adap->udelay);
+ if (adap->getscl == NULL )
+ return 0;
+ while (! getscl(adap) ) {
+ /* the hw knows how to read the clock line,
+ * so we wait until it actually gets high.
+ * This is safer as some chips may hold it low
+ * while they are processing data internally.
+ */
+ setscl(adap,1);
+ if (start+adap->timeout <= jiffies) {
+ return -ETIMEDOUT;
+ }
+#if LINUX_VERSION_CODE >= 0x02016e
+ if (current->need_resched)
+ schedule();
+#else
+ if (need_resched)
+ schedule();
+#endif
+ }
+ DEBSTAT(printk("needed %ld jiffies\n", jiffies-start));
+#ifdef SLO_IO
+ SLO_IO
+#endif
+ return 0;
+}
+
+
+/* --- other auxiliary functions -------------------------------------- */
+void i2c_start(struct bit_adapter *adap)
+{
+ /* assert: scl, sda are high */
+ DEBPROTO(printk("S "));
+ sdalo(adap);
+ scllo(adap);
+}
+
+void i2c_repstart(struct bit_adapter *adap)
+{
+ /* scl, sda may not be high */
+ DEBPROTO(printk(" Sr "));
+ setsda(adap,1);
+ setscl(adap,1);
+ udelay(adap->udelay);
+
+ sdalo(adap);
+ scllo(adap);
+}
+
+
+void i2c_stop(struct bit_adapter *adap)
+{
+ DEBPROTO(printk("P\n"));
+ /* assert: scl is low */
+ sdalo(adap);
+ sclhi(adap);
+ sdahi(adap);
+}
+
+/* send a byte without start cond., look for arbitration,
+ check ackn. from slave */
+/* return 1 if ok */
+int i2c_outb(struct bit_adapter *adap, char c)
+{
+ int i;
+ int sb;
+ int ack;
+
+ /* assert: scl is low */
+ DEB2(printk(" i2c_outb:%2.2X\n",c&0xff));
+ for ( i=7 ; i>=0 ; i-- ) {
+ sb = c & ( 1 << i );
+ setsda(adap,sb);
+ udelay(adap->udelay);
+ DEBPROTO(printk("%d",sb!=0));
+ if (sclhi(adap)<0) { /* timed out */
+ sdahi(adap); /* we don't want to block the net */
+ return -ETIMEDOUT;
+ };
+ /* do arbitration here:
+ * if ( sb && ! getsda(adap) ) -> ouch! Get out of here.
+ */
+ setscl( adap, 0 );
+ udelay(adap->udelay);
+ }
+ sdahi(adap);
+ if (sclhi(adap)<0){ /* timeout */
+ return -ETIMEDOUT;
+ };
+ /* read ack: SDA should be pulled down by slave */
+ ack=getsda(adap); /* ack: sda is pulled low ->success. */
+ DEB2(printk(" i2c_outb: getsda() = 0x%2.2x\n", ~ack ));
+
+ DEBPROTO( printk("[%2.2x]",c&0xff) );
+ DEBPROTO(if (0==ack) printk(" A "); else printk(" NA ") );
+ scllo(adap);
+ return 0==ack; /* return 1 if device acked */
+ /* assert: scl is low (sda undef) */
+}
+
+
+
+int i2c_inb(struct bit_adapter *adap)
+{
+ /* read byte via i2c port, without start/stop sequence */
+ /* acknowledge is sent in i2c_read. */
+ int i;
+ char indata;
+
+ /* assert: scl is low */
+ DEB2(printk("i2c_inb.\n"));
+
+ sdahi(adap);
+ indata=0;
+ for (i=0;i<8;i++) {
+ if (sclhi(adap)<0) { /* timeout */
+ return -ETIMEDOUT;
+ };
+ indata *= 2;
+ if ( getsda(adap) )
+ indata |= 0x01;
+ scllo(adap);
+ }
+ /* assert: scl is low */
+ DEBPROTO(printk(" %2.2x", indata & 0xff));
+ return (int) (indata & 0xff);
+}
+
+/*
+ * Sanity check for the adapter hardware - check the reaction of
+ * the bus lines only if it seems to be idle.
+ */
+int test_bus(struct bit_adapter *adap) {
+ int scl,sda;
+ sda=getsda(adap);
+ if (adap->getscl==NULL) {
+ printk("i2c(bit): Warning: Adapter can't read from clock line - skipping test.\n");
+ return 0;
+ }
+ scl=getscl(adap);
+ printk("i2c(bit): Adapter: %s scl: %d sda: %d -- testing...\n",
+ adap->name,getscl(adap),getsda(adap));
+ if (!scl || !sda ) {
+ printk("i2c(bit): %s seems to be busy.\n",adap->name);
+ goto bailout;
+ }
+ sdalo(adap);
+ printk("i2c(bit):1 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 != getsda(adap) ) {
+ printk("i2c(bit): %s SDA stuck high!\n",adap->name);
+ sdahi(adap);
+ goto bailout;
+ }
+ if ( 0 == getscl(adap) ) {
+ printk("i2c(bit): %s SCL unexpected low while pulling SDA low!\n",
+ adap->name);
+ goto bailout;
+ }
+ sdahi(adap);
+ printk("i2c(bit):2 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 == getsda(adap) ) {
+ printk("i2c(bit): %s SDA stuck low!\n",adap->name);
+ sdahi(adap);
+ goto bailout;
+ }
+ if ( 0 == getscl(adap) ) {
+ printk("i2c(bit): %s SCL unexpected low while SDA high!\n",adap->name);
+ goto bailout;
+ }
+ scllo(adap);
+ printk("i2c(bit):3 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 != getscl(adap) ) {
+ printk("i2c(bit): %s SCL stuck high!\n",adap->name);
+ sclhi(adap);
+ goto bailout;
+ }
+ if ( 0 == getsda(adap) ) {
+ printk("i2c(bit): %s SDA unexpected low while pulling SCL low!\n",
+ adap->name);
+ goto bailout;
+ }
+ sclhi(adap);
+ printk("i2c(bit):4 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 == getscl(adap) ) {
+ printk("i2c(bit): %s SCL stuck low!\n",adap->name);
+ sclhi(adap);
+ goto bailout;
+ }
+ if ( 0 == getsda(adap) ) {
+ printk("i2c(bit): %s SDA unexpected low while SCL high!\n",
+ adap->name);
+ goto bailout;
+ }
+ printk("i2c(bit): %s passed test.\n",adap->name);
+ return 0;
+bailout:
+ sdahi(adap);
+ sclhi(adap);
+ return -ENODEV;
+}
+
+/* ----- Utility functions
+ */
+
+inline int try_address(struct bit_adapter *adap,
+ unsigned char addr, int retries)
+{
+ int i,ret = -1;
+ for (i=0;iudelay*/);
+ i2c_start(adap);
+ udelay(adap->udelay);
+ }
+ DEB2(if (i) printk("i2c(bit): needed %d retries for %d\n",i,addr));
+ return ret;
+}
+
+int sendbytes(struct bit_adapter *adap,const char *buf, int count)
+{
+ char c;
+ const char *temp = buf;
+ int retval;
+ int wrcount=0;
+
+ while (count > 0) {
+ c = *temp;
+ DEB2(printk("i2c(bit): %s i2c_write: writing %2.2X\n",
+ adap->name, c&0xff));
+ retval = i2c_outb(adap,c);
+ if (retval>0) {
+ count--;
+ temp++;
+ wrcount++;
+ } else { /* arbitration or no acknowledge */
+ printk("i2c(bit): %s i2c_write: error - bailout.\n",
+ adap->name);
+ i2c_stop(adap);
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+#if 0
+ /* from asm/delay.h */
+ __delay(adap->mdelay * (loops_per_sec / 1000) );
+#endif
+ }
+ return wrcount;
+}
+
+inline int readbytes(struct bit_adapter *adap,char *buf,int count)
+{
+ char *temp = buf;
+ int inval;
+ int rdcount=0; /* counts bytes read */
+
+ while (count > 0) {
+ inval = i2c_inb(adap);
+/*printk("%#02x ",inval);
+if ( ! (count % 16) )
+printk("\n");
+*/
+ if (inval>=0) {
+ *temp = inval;
+ rdcount++;
+ } else { /* read timed out */
+ printk("i2c(bit): i2c_read: i2c_inb timed out.\n");
+ break;
+ }
+
+ if ( count > 1 ) { /* send ack */
+ sdalo(adap);
+ DEBPROTO(printk(" Am "));
+ } else {
+ sdahi(adap); /* neg. ack on last byte */
+ DEBPROTO(printk(" NAm "));
+ }
+ if (sclhi(adap)<0) { /* timeout */
+ sdahi(adap);
+ printk("i2c(bit): i2c_read: Timeout at ack\n");
+ return -ETIMEDOUT;
+ };
+ scllo(adap);
+ sdahi(adap);
+ temp++;
+ count--;
+ }
+ return rdcount;
+}
+
+inline int bit_doAddress(struct bit_adapter *adap, struct i2c_msg *msg,
+ int retries)
+{
+ unsigned short flags = msg->flags;
+ unsigned char addr;
+ int ret;
+ if ( (flags & I2C_M_TEN) ) {
+ /* a ten bit address */
+ addr = 0xf0 | ( flags & I2C_M_TENMASK );
+ DEB2(printk("addr0: %d\n",addr));
+ /* try extended address code...*/
+ ret = try_address(adap, addr, retries);
+ if (ret!=1) {
+ printk("died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ /* the remaining 8 bit address */
+ ret = i2c_outb(adap,msg->addr);
+ if (ret != 1) {
+ printk("died at 2nd address code.\n");
+ return -EREMOTEIO;
+ }
+ if ( flags & I2C_M_RD ) {
+ i2c_repstart(adap);
+ /* okay, now switch into reading mode */
+ addr |= 0x01;
+ ret = try_address(adap, addr, retries);
+ if (ret!=1) {
+ printk("died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ }
+ } else { /* normal 7bit address */
+ addr = ( msg->addr << 1 );
+ if (flags & I2C_M_RD )
+ addr |= 1;
+ ret = try_address(adap, addr, retries);
+ if (ret!=1) {
+ return -EREMOTEIO;
+ }
+ }
+ return 0;
+}
+
+int bit_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg msgs[], int num)
+{
+ struct bit_adapter *adap = (struct bit_adapter*)adapter->data;
+ struct i2c_msg *pmsg;
+ int i,ret;
+
+ i2c_start(adap);
+ for (i=0;iretries);
+ if (ret != 0) {
+ DEB2(printk("i2c(bit): NAK from device adr %#2x msg #%d\n"
+ ,msgs[i].addr,i));
+ return -EREMOTEIO;
+ }
+ if (pmsg->flags & I2C_M_RD ) {
+ /* read bytes into buffer*/
+ ret = readbytes(adap,pmsg->buf,pmsg->len);
+ DEB2(printk("i2c(bit): read %d bytes.\n",ret));
+ } else {
+ /* write bytes from buffer */
+ ret = sendbytes(adap,pmsg->buf,pmsg->len);
+ DEB2(printk("i2c(bit): wrote %d bytes.\n",ret));
+ }
+ if (iadapter;
+ struct bit_adapter *adap = (struct bit_adapter*)adapter->data;
+
+ if (adap->client_register != NULL)
+ return adap->client_register(client);
+ return 0;
+}
+
+int client_unregister(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct bit_adapter *adap = (struct bit_adapter*)adapter->data;
+
+ if (adap->client_unregister != NULL)
+ return adap->client_unregister(client);
+ return 0;
+}
+
+/* -----exported algorithm data: ------------------------------------- */
+
+struct i2c_algorithm bit_algo = {
+ "Bit-shift algorithm",
+ ALGO_BIT,
+ bit_xfer,
+#if 0
+ bit_send, /* master_xmit */
+ bit_recv, /* master_recv */
+ bit_comb, /* master_comb */
+#endif
+ NULL, /* slave_xmit */
+ NULL, /* slave_recv */
+ algo_control, /* ioctl */
+ client_register,
+ client_unregister,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_bit_add_bus(struct bit_adapter *adap)
+{
+ int i,ack;
+ struct i2c_adapter *i2c_adap;
+
+ for (i = 0; i < BIT_ADAP_MAX; i++)
+ if (NULL == bit_adaps[i])
+ break;
+ if (BIT_ADAP_MAX == i)
+ return -ENOMEM;
+
+ if (bit_test) {
+ int ret = test_bus(adap);
+ if (ret<0)
+ return -ENODEV;
+ }
+ i2c_adap = kmalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (i2c_adap == NULL)
+ return -ENOMEM;
+
+ bit_adaps[i] = adap;
+ adap_count++;
+ DEB2(printk("i2c(bit): hw routines for %s registered.\n",adap->name));
+
+ /* register new adapter to i2c module... */
+
+ memset(i2c_adap,0,sizeof(struct i2c_adapter));
+ strcpy(i2c_adap->name,adap->name);
+ i2c_adap->id = bit_algo.id | adap->id;
+ i2c_adap->algo = &bit_algo;
+ i2c_adap->data = adap;
+ i2c_adap->timeout = 100; /* default values, should */
+ i2c_adap->retries = 3; /* be replaced by defines */
+ i2c_adaps[i] = i2c_adap;
+ i2c_add_adapter(i2c_adap);
+
+ /* scan bus */
+ if (bit_scan) {
+ printk(KERN_INFO " i2c(bit): scanning bus %s.\n", adap->name);
+ for (i = 0x00; i < 0xff; i+=2) {
+ i2c_start(adap);
+ ack = i2c_outb(adap,i);
+ i2c_stop(adap);
+ if (ack>0) {
+ printk("(%02x)",i>>1);
+ } else
+ printk(".");
+ }
+ printk("\n");
+ }
+ return 0;
+}
+
+
+int i2c_bit_del_bus(struct bit_adapter *adap)
+{
+ int i;
+
+ for (i = 0; i < BIT_ADAP_MAX; i++)
+ if ( adap == bit_adaps[i])
+ break;
+ if ( BIT_ADAP_MAX == i) {
+ printk(KERN_WARNING " i2c(bit): could not unregister bus: %s\n",
+ adap->name);
+ return -ENODEV;
+ }
+
+ bit_adaps[i] = NULL;
+ i2c_del_adapter(i2c_adaps[i]);
+ kfree(i2c_adaps[i]);
+ i2c_adaps[i] = NULL;
+ adap_count--;
+ DEB2(printk("i2c(bit): adapter unregistered: %s\n",adap->name));
+
+ return 0;
+}
+
+int algo_bit_init (void)
+{
+ int i;
+
+ for (i=0;i");
+MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
+
+MODULE_PARM(bit_test, "i");
+MODULE_PARM(bit_scan, "i");
+MODULE_PARM(i2c_debug,"i");
+
+MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
+MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
+MODULE_PARM_DESC(i2c_debug,"debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol");
+
+
+EXPORT_SYMBOL(i2c_bit_add_bus);
+EXPORT_SYMBOL(i2c_bit_del_bus);
+
+
+int init_module(void)
+{
+ return algo_bit_init();
+}
+
+void cleanup_module(void)
+{
+ i2c_del_algorithm(&bit_algo);
+}
+#endif
+
+
+
+
+
+
+
+
+
+
diff --git a/i2c/algo-bit.h b/i2c/algo-bit.h
new file mode 100644
index 00000000..f37ce492
--- /dev/null
+++ b/i2c/algo-bit.h
@@ -0,0 +1,38 @@
+#ifndef ALGO_BIT_H
+#define AGLO_BIT_H 1
+
+/* --- Defines for bit-adapters --------------------------------------- */
+#include "i2c.h"
+/*
+ * This struct contains the hw-dependent functions of bit-style adapters to
+ * manipulate the line states, and to init any hw-specific features. This is
+ * only used if you have more than one hw-type of adapter running.
+ */
+struct bit_adapter {
+ char name[32]; /* give it a nice name */
+ unsigned int id; /* not used yet, maybe later */
+ void *data; /* private data for lolevel routines */
+ void (*setsda) (void *data, int state);
+ void (*setscl) (void *data, int state);
+ int (*getsda) (void *data);
+ int (*getscl) (void *data);
+
+ /* administrative calls */
+ int (*client_register)(struct i2c_client *);
+ int (*client_unregister)(struct i2c_client *);
+
+ /* local settings */
+ int udelay;
+ int mdelay;
+ int timeout;
+
+};
+
+extern struct bit_adapter *bit_adaps[];
+
+#define BIT_ADAP_MAX 16
+
+int i2c_bit_add_bus(struct bit_adapter *);
+int i2c_bit_del_bus(struct bit_adapter *);
+
+#endif /* ALGO_BIT_H */
diff --git a/i2c/bit-elv.c b/i2c/bit-elv.c
new file mode 100644
index 00000000..ea6af0ba
--- /dev/null
+++ b/i2c/bit-elv.c
@@ -0,0 +1,146 @@
+/* ------------------------------------------------------------------------- */
+/* bit-elv.c i2c-hw access for philips style parallel port adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-97 Simon G. Vogl
+
+ 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. */
+/* ------------------------------------------------------------------------- */
+static char rcsid[] = "$Id: bit-elv.c,v 1.1 1998/09/05 18:20:09 i2c Exp $";
+/*
+ * $Log: bit-elv.c,v $
+ * Revision 1.1 1998/09/05 18:20:09 i2c
+ * Initial revision
+ *
+ * Revision 1.3 1998/01/20 10:01:29 i2c
+ * *** empty log message ***
+ *
+ * Revision 1.2 1997/06/15 14:21:37 i2c
+ * *** empty log message ***
+ *
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include "i2c.h"
+#include "i2c-priv.h"
+
+
+/* ----- 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 */
+/* ----- local functions ---------------------------------------------- */
+#if (BITADAPS) == 1
+#define Local inline
+#define bit_elv_getscl getscl
+#define bit_elv_setscl setscl
+#define bit_elv_getsda getsda
+#define bit_elv_setsda setsda
+#define bit_elv_bit_init bit_init
+#define bit_elv_bit_exit bit_exit
+#else
+#define Local static
+#endif
+
+#define portData(minor) ((char)((int)i2c_table[minor].minor_data))
+
+Local void bit_elv_setscl(int minor, int state)
+{
+ if (state) {
+ portData(minor)&=0xfe;
+ } else {
+ portData(minor)|=1;
+ }
+ outb(portData(minor), DATA);
+}
+
+Local void bit_elv_setsda(int minor, int state)
+{
+ if (state) {
+ portData(minor)&=0xfd;
+ } else {
+ portData(minor)|=2;
+ }
+ outb(portData(minor), DATA);
+}
+
+Local int bit_elv_getscl(int minor)
+{
+ return ( 0 == ( (inb_p(STAT)) & 0x08 ) );
+}
+
+Local int bit_elv_getsda(int minor)
+{
+ return ( 0 == ( (inb_p(STAT)) & 0x40 ) );
+}
+
+Local int bit_elv_bit_init(int minor)
+{
+ if (check_region(i2c_table[minor].base,
+ (i2c_table[minor].base == 0x3bc)? 3 : 8) < 0 ) {
+ return -ENODEV;
+ } else {
+ /* test for ELV adap. */
+ if (inb(STAT) & 0x80) { /* BUSY should be high */
+ DEBINIT(printk("i2c ELV: Busy was low.\n"));
+ return -ENODEV;
+ } else {
+ outb(0x04,CTRL); /* SLCT auf low */
+ udelay(40);
+ if ( inb(STAT) && 0x10 ) {
+ outb(0x0c,CTRL);
+ DEBINIT(printk("i2c ELV: Select was high.\n"));
+ return -ENODEV;
+ }
+ }
+ request_region(i2c_table[minor].base,
+ (i2c_table[minor].base == 0x3bc)? 3 : 8,
+ "i2c (ELV adapter)");
+ portData(minor) = 0;
+ outb(0,DATA);
+ }
+ DEBINIT(printk("i2c%d: scl: %d sda %d \n",minor,
+ bit_elv_getscl(minor),bit_elv_getsda(minor)) );
+ return 0;
+}
+
+Local void bit_elv_bit_exit(int minor)
+{
+ outb(0,DATA);
+ outb(0x0c,CTRL);
+ release_region( i2c_table[minor].base ,
+ (i2c_table[minor].base == 0x3bc)? 3 : 8 );
+}
+
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+#if (BITADAPS) > 1
+struct i2c_bit_opns bit_elv_ops = {
+ bit_elv_setscl,
+ bit_elv_setsda,
+ bit_elv_getscl,
+ bit_elv_getsda,
+ bit_elv_bit_init,
+ bit_elv_bit_exit
+};
+#endif
diff --git a/i2c/bit-lp.c b/i2c/bit-lp.c
new file mode 100644
index 00000000..55c438a5
--- /dev/null
+++ b/i2c/bit-lp.c
@@ -0,0 +1,188 @@
+/* ------------------------------------------------------------------------- */
+/* bit-lp.c i2c-hw access for philips style parallel port adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-97 Simon G. Vogl
+
+ 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. */
+/* ------------------------------------------------------------------------- */
+static char rcsid[] = "$Id: bit-lp.c,v 1.5 1998/09/28 06:45:38 i2c Exp i2c $";
+/* ------------------------------------------------------------------------- */
+
+#include
+#include
+#include
+#include
+
+#include "i2c.h"
+#include "algo-bit.h"
+
+#define DEFAULT_BASE 0x378
+int base=0;
+
+/* Note: all we need to know is the base address of the parallel port, so
+ * instead of having a dedicated struct to store this value, we store this
+ * int in the pointer field (=bit_lp_ops.data) itself.
+ */
+
+/* Note2: as the hw that implements the i2c bus on the parallel port is
+ * incompatible with other epp stuff etc., we access the port exclusively
+ * and don't cooperate with parport functions.
+ */
+
+/* ----- 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 */
+
+/* ----- printer port defines ------------------------------------------*/
+ /* Pin Port Inverted name */
+#define I2C_ON 0x20 /* 12 status N paper */
+ /* ... only for phil. not used */
+#define I2C_SDA 0x80 /* 9 data N data7 */
+#define I2C_SCL 0x08 /* 17 ctrl N dsel */
+
+#define I2C_SDAIN 0x80 /* 11 stat Y busy */
+#define I2C_SCLIN 0x08 /* 15 stat Y enable */
+
+#define I2C_DMASK 0x7f
+#define I2C_CMASK 0xf7
+
+/* --- 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 ---------------------------------------------- */
+
+void bit_lp_setscl(void *data, int state)
+{
+ /*be cautious about state of the control register -
+ touch only the one bit needed*/
+ if (state) {
+ outb(inb(CTRL)|I2C_SCL, CTRL);
+ } else {
+ outb(inb(CTRL)&I2C_CMASK, CTRL);
+ }
+}
+
+void bit_lp_setsda(void *data, int state)
+{
+ if (state) {
+ outb(I2C_DMASK , DATA);
+ } else {
+ outb(I2C_SDA , DATA);
+ }
+}
+
+int bit_lp_getscl(void *data)
+{
+ return ( 0 != ( (inb(STAT)) & I2C_SCLIN ) );
+}
+
+int bit_lp_getsda(void *data)
+{
+ return ( 0 != ( (inb(STAT)) & I2C_SDAIN ) );
+}
+
+int bit_lp_init(void)
+{
+ if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) {
+ return -ENODEV;
+ } else {
+ request_region(base,(base == 0x3bc)? 3 : 8,
+ "i2c (parallel port adapter)");
+ /* reset hardware to sane state */
+ bit_lp_setsda((void*)base,1);
+ bit_lp_setscl((void*)base,1);
+ }
+ return 0;
+}
+
+void bit_lp_exit(void)
+{
+ release_region( base , (base == 0x3bc)? 3 : 8 );
+}
+
+int bit_lp_reg(struct i2c_client *client)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+int bit_lp_unreg(struct i2c_client *client)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+struct bit_adapter bit_lp_ops = {
+ "Philips Parallel port adapter",
+ HW_B_LP,
+ NULL,
+ bit_lp_setsda,
+ bit_lp_setscl,
+ bit_lp_getsda,
+ bit_lp_getscl,
+ bit_lp_reg,
+ bit_lp_unreg,
+ 80, 80, 100, /* waits, timeout */
+};
+
+#ifdef MODULE
+MODULE_AUTHOR("Simon G. Vogl ");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for Philips parallel port adapter");
+
+MODULE_PARM(base, "i");
+
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (base==0) {
+ /* probe some values */
+ base=DEFAULT_BASE;
+ bit_lp_ops.data=(void*)DEFAULT_BASE;
+ if (bit_lp_init()==0) {
+ i2c_bit_add_bus(&bit_lp_ops);
+ } else {
+ return -ENODEV;
+ }
+ } else {
+ bit_lp_ops.data=(void*)base;
+ if (bit_lp_init()==0) {
+ i2c_bit_add_bus(&bit_lp_ops);
+ } else {
+ return -ENODEV;
+ }
+ }
+ printk("bit_lp: found device at %#x.\n",base);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ i2c_bit_del_bus(&bit_lp_ops);
+ bit_lp_exit();
+}
+
+#endif
+
+
+
diff --git a/i2c/bit-mb.c b/i2c/bit-mb.c
new file mode 100644
index 00000000..4f3371b7
--- /dev/null
+++ b/i2c/bit-mb.c
@@ -0,0 +1,163 @@
+/*
+ Motherboard SMBus (or i2c) Support for VIA VT82C586B South Bridge
+ Based on bit-lp.c by Simon Vogl
+
+ Copyright (c) 1998 Kyösti Mälkki
+
+ 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.
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+#include "i2c.h"
+#include "algo-bit.h"
+
+/* Power management registers */
+#define PM_IO_BASE pm_io_base
+#define PM_IO_BASE_REGISTER 0x48
+#define I2C_DIR (PM_IO_BASE+0x40)
+#define I2C_OUT (PM_IO_BASE+0x42)
+#define I2C_IN (PM_IO_BASE+0x44)
+#define I2C_SCL 0x02
+#define I2C_SDA 0x04
+
+/* io-region reservation */
+#define IOSPACE 0x06
+#define IOTEXT "Via VT82C586B i2c"
+
+/* ----- 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 */
+
+/* ----- local functions ---------------------------------------------- */
+
+u32 pm_io_base;
+
+static void bit_mb_setscl(void *data, int state)
+{
+ outb(state ? inb(I2C_OUT)|I2C_SCL : inb(I2C_OUT)&~I2C_SCL, I2C_OUT);
+}
+
+static void bit_mb_setsda(void *data, int state)
+{
+ outb(state ? inb(I2C_OUT)|I2C_SDA : inb(I2C_OUT)&~I2C_SDA, I2C_OUT);
+}
+
+static int bit_mb_getscl(void *data)
+{
+ return (0 != (inb(I2C_IN) & I2C_SCL) );
+}
+
+static int bit_mb_getsda(void *data)
+{
+ return (0 != (inb(I2C_IN) & I2C_SDA) );
+}
+
+static int bit_mb_reg(struct i2c_client *client)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int bit_mb_unreg(struct i2c_client *client)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+struct bit_adapter bit_mb_ops = {
+ "VT82C586B i2c",
+ HW_B_MB,
+ NULL,
+ bit_mb_setsda,
+ bit_mb_setscl,
+ bit_mb_getsda,
+ bit_mb_getscl,
+ bit_mb_reg,
+ bit_mb_unreg,
+ 10, 10, 100, /*waits, timeout */
+};
+
+u32 pm_io_base=0;
+
+static int bit_mb_init(void)
+{
+ if (check_region(I2C_DIR, IOSPACE) < 0 ) {
+ return -ENODEV;
+ } else {
+ request_region(I2C_DIR, IOSPACE, IOTEXT);
+
+ /* Set lines to output and make them high */
+ outb(inb(I2C_DIR) | I2C_SCL | I2C_SDA, I2C_DIR);
+ bit_mb_setsda(NULL, 1);
+ bit_mb_setscl(NULL, 1);
+ }
+ return 0;
+}
+
+static void bit_mb_exit(void)
+{
+ release_region(I2C_DIR, IOSPACE);
+}
+
+static u32 find_i2c(void)
+{
+ struct pci_dev *s_bridge;
+ u32 val;
+
+ if (! pci_present())
+ return(0);
+
+ s_bridge = pci_find_device(
+ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, NULL);
+ if (! s_bridge) return 0;
+
+ if ( PCIBIOS_SUCCESSFUL !=
+ pci_read_config_dword(s_bridge, PM_IO_BASE_REGISTER, &val) )
+ return 0;
+
+ return (val & (0xff<<8));
+}
+
+#ifdef MODULE
+MODULE_AUTHOR("Kyosti Malkki ");
+MODULE_DESCRIPTION("SMBus for VT82C586");
+
+int init_module(void)
+{
+ pm_io_base = find_i2c();
+ if (pm_io_base == 0) return -ENODEV;
+ if (bit_mb_init()==0) {
+ i2c_bit_add_bus(&bit_mb_ops);
+ } else {
+ return -ENODEV;
+ }
+ printk("Using i2c bus on motherboard\n");
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ i2c_bit_del_bus(&bit_mb_ops);
+ bit_mb_exit();
+}
+#endif
diff --git a/i2c/bit-velle.c b/i2c/bit-velle.c
new file mode 100644
index 00000000..ffababcb
--- /dev/null
+++ b/i2c/bit-velle.c
@@ -0,0 +1,195 @@
+/* ------------------------------------------------------------------------- */
+/* bit-velle.c i2c-hw access for Velleman K9000 adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-96 Simon G. Vogl
+
+ 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. */
+/* ------------------------------------------------------------------------- */
+static char rcsid[] = "$Id: bit-velle.c,v 1.3 1998/09/15 18:50:04 i2c Exp $";
+/*
+ * $Log: bit-velle.c,v $
+ * Revision 1.3 1998/09/15 18:50:04 i2c
+ * *** empty log message ***
+ *
+ * Revision 1.2 1998/09/13 16:54:55 i2c
+ * *** empty log message ***
+ *
+ * Revision 1.1 1998/07/29 08:09:35 i2c
+ * Initial revision
+ *
+ * Revision 1.1 1998/01/20 10:01:29 i2c
+ * Initial revision
+ *
+ * Revision 1.1 1996/11/17 11:00:03 i2c
+ * Initial revision
+ *
+ *
+ */
+
+#include
+#include
+#include
+#include /* for 2.0 kernels to get NULL */
+#include /* for 2.0 kernels to get ENODEV */
+#include
+
+#include "i2c.h"
+#include "algo-bit.h"
+
+/* ----- 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 */
+
+ /* Pin Port Inverted name */
+#define I2C_SDA 0x02 /* ctrl bit 1 (inv) */
+#define I2C_SCL 0x08 /* ctrl bit 3 (inv) */
+
+#define I2C_SDAIN 0x10 /* stat bit 4 */
+#define I2C_SCLIN 0x08 /* ctrl bit 3 (inv) (reads own output) */
+
+#define I2C_DMASK 0xfd
+#define I2C_CMASK 0xf7
+
+
+/* --- 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 */
+
+#define DEFAULT_BASE 0x378
+int base=0;
+
+/* ----- local functions --------------------------------------------------- */
+
+void bit_velle_setscl(void *data, int state)
+{
+ if (state) {
+ outb(inb(CTRL) & I2C_CMASK, CTRL);
+ } else {
+ outb(inb(CTRL) | I2C_SCL, CTRL);
+ }
+
+}
+
+void bit_velle_setsda(void *data, int state)
+{
+ if (state) {
+ outb(inb(CTRL) & I2C_DMASK , CTRL);
+ } else {
+ outb(inb(CTRL) | I2C_SDA, CTRL);
+ }
+
+}
+
+int bit_velle_getscl(void *data)
+{
+ return ( 0 == ( (inb(CTRL)) & I2C_SCLIN ) );
+}
+
+int bit_velle_getsda(void *data)
+{
+ return ( 0 != ( (inb(STAT)) & I2C_SDAIN ) );
+}
+
+int bit_velle_init(void)
+{
+ if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) {
+ DEBE(printk("i2c_init: Port %#x already in use.\n", base));
+ return -ENODEV;
+ } else {
+ request_region(base, (base == 0x3bc)? 3 : 8,
+ "i2c (Vellemann adapter)");
+ bit_velle_setsda((void*)base,1);
+ bit_velle_setscl((void*)base,1);
+ }
+ return 0;
+}
+
+void bit_velle_exit(void)
+{
+ release_region( base , (base == 0x3bc)? 3 : 8 );
+}
+
+
+int bit_velle_reg(struct i2c_client *client)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+int bit_velle_unreg(struct i2c_client *client)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+struct bit_adapter bit_velle_ops = {
+ "Philips Parallel port adapter",
+ HW_B_LP,
+ NULL,
+ bit_velle_setsda,
+ bit_velle_setscl,
+ bit_velle_getsda,
+ bit_velle_getscl,
+ bit_velle_reg,
+ bit_velle_unreg,
+ 10, 10, 100, /* waits, timeout */
+};
+
+#ifdef MODULE
+MODULE_AUTHOR("Simon G. Vogl ");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for Velleman K9000 adapter");
+
+MODULE_PARM(base, "i");
+
+int init_module(void)
+{
+ if (base==0) {
+ /* probe some values */
+ base=DEFAULT_BASE;
+ bit_velle_ops.data=(void*)DEFAULT_BASE;
+ if (bit_velle_init()==0) {
+ i2c_bit_add_bus(&bit_velle_ops);
+ } else {
+ return -ENODEV;
+ }
+ } else {
+ bit_velle_ops.data=(void*)base;
+ if (bit_velle_init()==0) {
+ i2c_bit_add_bus(&bit_velle_ops);
+ } else {
+ return -ENODEV;
+ }
+ }
+ printk("bit_velle: found device at %#x.\n",base);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ i2c_bit_del_bus(&bit_velle_ops);
+ bit_velle_exit();
+}
+
+#endif
+
+
+
diff --git a/i2c/detect/Makefile b/i2c/detect/Makefile
new file mode 100644
index 00000000..8c3e33c3
--- /dev/null
+++ b/i2c/detect/Makefile
@@ -0,0 +1,32 @@
+# $Id: Makefile,v 1.1 1996/12/04 20:40:10 i2c Exp $
+# $Log: Makefile,v $
+# Revision 1.1 1996/12/04 20:40:10 i2c
+# Initial revision
+#
+#
+
+
+I2C_HOME = ..
+
+#----------------------------------------------------------------------------
+I2C_OPT = -DVERIFY_HEADERS -DSLOW_STARTER
+KERNEL_OPT = -D__KERNEL__ -DKERNEL -DLINUX -DMODULE
+WARNINGS = -Wall -Wstrict-prototypes
+COMPILE = -pipe -fomit-frame-pointer -m486 -O2 \
+ -I$(I2C_HOME) -I.
+DEBUG =
+
+SRCS = i2c_main.c alg-illeg.c $(HW_SRCS)
+INCLUDES = i2c_priv.h
+OBJS = $(SRCS:.c=.o)
+HDRS = i2c_priv.h
+MOD = i2c
+
+CFLAGS = $(DEBUG) $(WARNINGS) $(COMPILE) $(I2C_OPT) $(KERNEL_OPT)
+SFLAGS = -fverbose-asm $(WARNINGS) $(COMPILE) $(PRT_OPT) $(KERNEL_OPT)
+
+all: detect
+
+clean:
+ -rm -f detect
+
diff --git a/i2c/detect/detect.c b/i2c/detect/detect.c
new file mode 100644
index 00000000..d3863058
--- /dev/null
+++ b/i2c/detect/detect.c
@@ -0,0 +1,68 @@
+/* ------------------------------------------------------------------------- */
+/* detect -- look who's there. Gets address acks from all devices on the bus.*/
+/* It should not change any values in the peripherals. */
+/* ------------------------------------------------------------------------- */
+static char *rcsid="$Id: detect.c,v 2.2 1996/11/17 22:03:06 i2c Exp $";
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "i2c.h"
+
+#define Write(a,b,c) err(1,write(a,b,c))
+#define Read(a,b,c) err(0,read(a,b,c))
+
+void err(int wr, int d){
+ if (d==-1){
+ printf("%s error: %s !\n",(wr)?"Write":"Read",strerror(errno));
+ }
+}
+#define ERR(x) printf("return value: %d\n", (x) );
+
+int main(int argc, char *argv[]){
+ int i,f;
+ char b[40],c;
+ char *device = "/dev/i2c0";
+
+ /* parse options */
+ opterr=1;
+ while ( (c=getopt(argc,argv,"hH?d:")) != -1) {
+ switch (c){
+ case 'd':
+ if (optarg)
+ device = optarg;
+ break;
+ case 'h':
+ case 'H':
+ case '?':
+ default:
+ printf("%s tries to detect devices on the i2c-bus. Usage:\n",argv[0]);
+ printf("-d device device to use\n");
+ return 0;
+ }
+ }
+ f=open(device,O_RDWR);
+ if (f<0){
+ perror("detect");
+ exit(1);
+ }
+ ERR( ioctl(f,I2C_UDELAY,10) );
+ ERR( ioctl(f,I2C_MDELAY,0) );
+// ERR( ioctl(f,I2C_RETRIES,3) );
+
+ for (i=0;i<128;i++){
+ ioctl(f,I2C_SLAVE,i);
+ if (0>read (f,b,0) ) {
+ putchar('.');
+ } else {
+ printf("\n%d worked! \n",i);
+ }
+ usleep(100);
+ fflush(stdout);
+ }
+ putchar('\n');
+ return close(f);
+}
diff --git a/i2c/drivers/Makefile b/i2c/drivers/Makefile
new file mode 100644
index 00000000..f074ca3e
--- /dev/null
+++ b/i2c/drivers/Makefile
@@ -0,0 +1,23 @@
+#################################################
+# config
+KERNEL_LOCATION=/usr/src/linux
+CURRENT=$(shell uname -r)
+
+#################################################
+# some magic for using linux kernel settings
+# when compiling module(s)
+
+M_OBJS = eeprom.o hw-monitor.c
+MX_OBJS =
+EXTRA_CFLAGS = -DVERIFY_HEADERS -DSLOW_STARTER -I..
+
+here:
+ DIR=`pwd`; (cd $(KERNEL_LOCATION); make SUBDIRS=$$DIR modules)
+
+install:
+ su -c "cp -v $(M_OBJS) $(MX_OBJS) /lib/modules/$(CURRENT)/misc"
+
+clean:
+ -rm -f $(M_OBJS) $(MX_OBJS) .*.o.flags *~
+
+include $(KERNEL_LOCATION)/Rules.make
diff --git a/i2c/drivers/eeprom.c b/i2c/drivers/eeprom.c
new file mode 100644
index 00000000..2b037817
--- /dev/null
+++ b/i2c/drivers/eeprom.c
@@ -0,0 +1,172 @@
+/* experimental eeprom driver
+ */
+#include
+#include
+#include
+#include
+
+#include "i2c.h" /* +++ simon */
+#include "algo-bit.h"
+
+
+int test=0;
+/*
+ * Read the configuration EEPROM
+ */
+#define EEPROM_ADDR 0x50
+
+#define EEPROM_FROM 0x50
+#define EEPROM_TO 0x58 /*exclusive.*/
+
+#define MEMSIZE 128 /* default eeprom memory size */
+/* i2c_client identifies a single device that is connected to an
+ * i2c bus.
+ */
+struct i2c_driver eepromDriver;
+
+struct {
+ int size; /* eeprom memory size*/
+ unsigned int flags;
+ unsigned char *memory;
+} eepromData;
+
+struct i2c_client eepromTmpl = {
+ "Winnov EEPROM",
+ 0,
+ 0,
+ EEPROM_ADDR,
+ NULL, /* the adapter we sit on */
+ &eepromDriver, /* and our access routines */
+ NULL, /* for the clients */
+};
+
+
+int eeprom_attach(struct i2c_adapter *adap)
+{
+ struct i2c_client *eeprom;
+ unsigned char buf[256];
+ struct i2c_msg msgs[] = {
+ {EEPROM_ADDR, 0, 1, "\0", },
+ {EEPROM_ADDR, I2C_M_RD, 256, buf, },
+ };
+ __u8 c=0;
+ int i;
+ int ret=0;
+
+ printk("wnv-eeprom: Trying to attach to adapter %s \n",adap->name);
+ printk("Looking for EEPROMs\n");
+ eepromTmpl.adapter = adap;
+ for (i=EEPROM_FROM;iname);
+
+ kfree(client);
+
+ return 0;
+}
+
+#define LOAD_EEPROM 1
+#if 0
+#define SET_SIZE 0xee01 /* set memory size */
+#define GET_SIZE 0xee02 /* get memory size */
+#define GET_MEM 0xee03 /* load data from eeprom & pass memory pointer */
+#define SET_MEM 0xee04 /* dump memory to eeprom */
+#define OPT
+#endif
+int eeprom_command(struct i2c_client *client,unsigned int cmd, void *arg)
+{
+ switch(cmd) {
+ case LOAD_EEPROM: {
+#if 0
+ __u8 c=0;
+ int i, ret,d;
+ i2c_master_send(client,(unsigned char*)&c,1);
+ i2c_master_recv(client, (char*)&c,1);
+ i2c_master_send(client,(unsigned char*)&c,1);
+ ret = i2c_master_recv(client, (char*)& ,
+ sizeof(struct EEPROM));
+ if (ret != sizeof(struct EEPROM)) {
+ err_msg("wnv-eeprom: could only read %d bytes!\n"
+ ,ret);
+ return -1;
+ }
+ for (d=0,i=0;ieeprom))[i];
+ }
+ if ((__u8)d != 0xff) {
+ err_msg("wnv-eeprom: Checksum error in configuration EEPROM\n");
+ return -1;
+ }
+ info_msg("wnv-eeprom: Identified: %s\n", dev->eeprom.szProduct);
+#endif
+ } break;
+ default:
+ printk("eeprom: unknown command %x!\n",cmd);
+ }
+ return 0;
+}
+
+struct i2c_driver eepromDriver = {
+ "Videum EEPROM",
+ -1,
+ DF_NOTIFY,
+ eeprom_attach,
+ eeprom_detach,
+ eeprom_command,
+};
+
+#ifdef MODULE
+MODULE_PARM(test,"i");
+
+/*EXPORT_NO_SYMBOLS;*/
+
+int init_module(void)
+{
+ /* register drivers to the i2c bus admin. system.
+ * These get notified upon attachment of adapters &
+ * in turn create new clients that are connected to
+ * these adapters...
+ */
+ i2c_add_driver(&eepromDriver);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ i2c_del_driver(&eepromDriver);
+}
+#endif /* MODULE*/
diff --git a/i2c/eeprom/Makefile b/i2c/eeprom/Makefile
new file mode 100644
index 00000000..3d724608
--- /dev/null
+++ b/i2c/eeprom/Makefile
@@ -0,0 +1,41 @@
+# $Id: Makefile,v 1.1 1996/07/23 20:31:56 i2c Exp $
+# $Log: Makefile,v $
+# Revision 1.1 1996/07/23 20:31:56 i2c
+# Initial revision
+#
+
+I2C_HOME = ..
+
+#----------------------------------------------------------------------------
+I2C_OPT = -DVERIFY_HEADERS -DSLOW_STARTER
+WARNINGS = -Wall -Wstrict-prototypes
+COMPILE = -pipe -fomit-frame-pointer -m486 -O2 \
+ -I$(I2C_HOME) -I.
+DEBUG =
+
+SRCS = i2c_main.c adap-illeg.c adap-phil.c adap-lppcf.c adap-isapcf.c \
+# adap-lpbit.c
+OBJS = $(SRCS:.c=.o)
+HDRS = i2c_priv.h
+MAIN = eeprom
+
+CFLAGS = $(DEBUG) $(WARNINGS) $(COMPILE) $(I2C_OPT) $(KERNEL_OPT)
+SFLAGS = -fverbose-asm $(WARNINGS) $(COMPILE) $(PRT_OPT) $(KERNEL_OPT)
+
+all: $(MAIN)
+
+install: $(MAIN)
+ -@mkdir $(I2C_HOME)/bin
+ cp $(MAIN) $(I2C_HOME)/bin
+
+clean:
+ -rm -f a.out $(OBJS) $(MAIN) core .depend detect
+
+dep depend .depend: $(HDRS) $(SRCS)
+ gcc $(CFLAGS) $(SRCS) -M >.depend
+#
+# include dependency files if they exist
+#
+#ifeq (.depend,$(wildcard .depend))
+#include .depend
+#endif
diff --git a/i2c/eeprom/README b/i2c/eeprom/README
new file mode 100644
index 00000000..dac71e61
--- /dev/null
+++ b/i2c/eeprom/README
@@ -0,0 +1,4 @@
+This is a simple demo program that prints out the
+first 256 bytes of an EEPROM memory. Adittionally,
+you can write a test pattern to the chip.
+With -[aA] the chip address may be specified.
diff --git a/i2c/eeprom/a b/i2c/eeprom/a
new file mode 100644
index 00000000..6b3aa0b0
--- /dev/null
+++ b/i2c/eeprom/a
@@ -0,0 +1,16 @@
+0000 bd 06 04 00 00 00 00 00 00 00 00 00 07 00 00 00 ................
+0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+0020 00 00 00 00 00 00 00 00 00 30 36 00 00 00 00 00 .........06.....
+0030 00 00 00 00 00 00 00 00 00 56 69 64 65 75 6d 41 .........VideumA
+0040 56 20 2d 20 50 6c 75 67 20 61 6e 64 20 50 6c 61 V...Plug.and.Pla
+0050 79 00 00 00 00 00 00 57 69 6e 6e 6f 76 00 00 00 y......Winnov...
+0060 00 00 00 00 00 00 00 00 00 00 00 34 35 58 45 37 ...........45XE7
+0070 33 30 30 34 38 30 32 30 00 00 00 00 00 00 00 6d 30048020.......m
+0080 bd 06 04 00 00 00 00 00 00 00 00 00 07 00 00 00 ................
+0090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00a0 00 00 00 00 00 00 00 00 00 30 36 00 00 00 00 00 .........06.....
+00b0 00 00 00 00 00 00 00 00 00 56 69 64 65 75 6d 41 .........VideumA
+00c0 56 20 2d 20 50 6c 75 67 20 61 6e 64 20 50 6c 61 V...Plug.and.Pla
+00d0 79 00 00 00 00 00 00 57 69 6e 6e 6f 76 00 00 00 y......Winnov...
+00e0 00 00 00 00 00 00 00 00 00 00 00 34 35 58 45 37 ...........45XE7
+00f0 33 30 30 34 38 30 32 30 00 00 00 00 00 00 00 6d 30048020.......m
diff --git a/i2c/eeprom/b b/i2c/eeprom/b
new file mode 100644
index 00000000..6b3aa0b0
--- /dev/null
+++ b/i2c/eeprom/b
@@ -0,0 +1,16 @@
+0000 bd 06 04 00 00 00 00 00 00 00 00 00 07 00 00 00 ................
+0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+0020 00 00 00 00 00 00 00 00 00 30 36 00 00 00 00 00 .........06.....
+0030 00 00 00 00 00 00 00 00 00 56 69 64 65 75 6d 41 .........VideumA
+0040 56 20 2d 20 50 6c 75 67 20 61 6e 64 20 50 6c 61 V...Plug.and.Pla
+0050 79 00 00 00 00 00 00 57 69 6e 6e 6f 76 00 00 00 y......Winnov...
+0060 00 00 00 00 00 00 00 00 00 00 00 34 35 58 45 37 ...........45XE7
+0070 33 30 30 34 38 30 32 30 00 00 00 00 00 00 00 6d 30048020.......m
+0080 bd 06 04 00 00 00 00 00 00 00 00 00 07 00 00 00 ................
+0090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00a0 00 00 00 00 00 00 00 00 00 30 36 00 00 00 00 00 .........06.....
+00b0 00 00 00 00 00 00 00 00 00 56 69 64 65 75 6d 41 .........VideumA
+00c0 56 20 2d 20 50 6c 75 67 20 61 6e 64 20 50 6c 61 V...Plug.and.Pla
+00d0 79 00 00 00 00 00 00 57 69 6e 6e 6f 76 00 00 00 y......Winnov...
+00e0 00 00 00 00 00 00 00 00 00 00 00 34 35 58 45 37 ...........45XE7
+00f0 33 30 30 34 38 30 32 30 00 00 00 00 00 00 00 6d 30048020.......m
diff --git a/i2c/eeprom/eeprom.c b/i2c/eeprom/eeprom.c
new file mode 100644
index 00000000..9dd77ec2
--- /dev/null
+++ b/i2c/eeprom/eeprom.c
@@ -0,0 +1,187 @@
+/* ------------------------------------------------------------------------- */
+/* eeprom -- read eeprom contents */
+/* revamped by Gerd Knorr */
+/* ------------------------------------------------------------------------- */
+static char *rcsid="$Id: eeprom.c,v 1.1 1996/07/23 20:32:12 i2c Exp $";
+/*
+ * $Log: eeprom.c,v $
+ * Revision 1.1 1996/07/23 20:32:12 i2c
+ * Initial revision
+ *
+ * Revision 1.2 1996/07/06 17:20:38 i2c
+ * rewrote loop
+ *
+ * Revision 1.1 1996/03/15 08:55:53 root
+ * Initial revision
+ *
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "i2c.h"
+
+char *dev="/dev/i2c0";
+int wr=0, adr=0xa0;
+
+
+
+void usage(char *name)
+{
+ fprintf(stderr,"This is a i2c EEPROM tool\n");
+ fprintf(stderr," read data: %s [ options ] > file\n",name);
+ fprintf(stderr," write data: %s [ options ] -w < file\n",name);
+ fprintf(stderr,"\n");
+ fprintf(stderr,"File format is a hex dump. Without \"-w\" switch\n");
+ fprintf(stderr,"only parsing (and printing) of the data is done,\n");
+ fprintf(stderr,"writing is skipped.\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,"options:\n");
+ fprintf(stderr," -d device device to use [%s]\n",dev);
+ fprintf(stderr," -a addr set slave address [0x%02x]\n",adr);
+ fprintf(stderr,"\n");
+ exit(1);
+}
+
+void dump_buf(unsigned char *buf)
+{
+ int i,j;
+
+ for (i = 0; i < 256; i += 16) {
+ printf("%04x ",i);
+ for (j = i; j < i+16; j++) {
+ if (!(j%4))
+ printf(" ");
+ printf("%02x ",buf[j]);
+ }
+ printf(" ");
+ for (j = i; j < i+16; j++)
+ printf("%c",isalnum(buf[j]) ? buf[j] : '.');
+ printf("\n");
+ }
+}
+
+int parse_buf(unsigned char *buf)
+{
+ int i,j,n,pos,count;
+ char line[100];
+
+ for (i = 0; i < 256; i += 16) {
+ if (NULL == fgets(line,99,stdin)) {
+ fprintf(stderr,"unexpected EOF\n");
+ return -1;
+ }
+ if (1 != sscanf(line,"%x%n",&n,&pos)) {
+ fprintf(stderr,"addr parse error (%d)\n",i>>4);
+ return -1;
+ }
+ if (n != i) {
+ fprintf(stderr,"addr mismatch\n");
+ return -1;
+ }
+ for (j = i; j < i+16; j++) {
+ if (1 != sscanf(line+pos,"%x%n",&n,&count)) {
+ fprintf(stderr,"value parse error\n");
+ return -1;
+ }
+ buf[j] = n;
+ pos += count;
+ }
+ }
+ return 0;
+}
+
+int
+read_buf(int fd, unsigned char *buf)
+{
+ int i,n=8;
+ unsigned char addr;
+
+ for (i = 0; i < 256; i += n) {
+ addr = i;
+ if (-1 == (write(fd,&addr,1))) {
+ fprintf(stderr,"write addr %s: %s\n",dev,strerror(errno));
+ exit(1);
+ }
+ if (-1 == (read(fd,buf+i,n))) {
+ fprintf(stderr,"read data %s: %s\n",dev,strerror(errno));
+ exit(1);
+ }
+ }
+}
+int
+write_buf(int fd, unsigned char *buf)
+{
+ int i,j,n = 8;
+ unsigned char tmp[17];
+
+ for (i = 0; i < 256; i += n) {
+ tmp[0] = i;
+ for (j = 0; j < n; j++)
+ tmp[j+1] = buf[i+j];
+ if (-1 == (write(fd,tmp,n+1))) {
+ fprintf(stderr," write data %s: %s\n",dev,strerror(errno));
+ exit(1);
+ }
+ fprintf(stderr,"*");
+ usleep(100000); /* 0.1 sec */
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int f,c,rescue;
+ unsigned char buf[256];
+
+ /* parse options */
+ opterr=1;
+ while ( (c=getopt(argc,argv,"hrwa:d:")) != -1) {
+ switch (c){
+ case 'r':
+ rescue=1;
+ break;
+ case 'w':
+ wr=1;
+ break;
+ case 'd':
+ dev = optarg;
+ break;
+ case 'a':
+ adr = strtol(optarg,NULL,0);
+ break;
+ case 'h':
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ if (-1 == (f = open(dev,O_RDWR))) {
+ fprintf(stderr,"open %s: %s\n",dev,strerror(errno));
+ exit(1);
+ }
+ ioctl(f,I2C_SLAVE,adr>>1);
+ memset(buf,0,256);
+
+ if (isatty(fileno(stdin))) {
+ /* read */
+ read_buf(f,buf);
+ dump_buf(buf);
+ } else {
+ /* write */
+ if (-1 == parse_buf(buf))
+ exit(1);
+ dump_buf(buf);
+ if (wr) {
+ fprintf(stderr,"writing to eeprom now... ");
+ write_buf(f,buf);
+ fprintf(stderr," ok\n");
+ }
+ }
+
+ close(f);
+ exit(0);
+}
diff --git a/i2c/hw-monitor.c b/i2c/hw-monitor.c
new file mode 100644
index 00000000..8ff86ef7
--- /dev/null
+++ b/i2c/hw-monitor.c
@@ -0,0 +1,182 @@
+ /*
+ EISCA Fan SMBus (or i2c) driver
+ Based on various char-device sources.
+
+ Copyright (c) 1998 Kyösti Mälkki
+
+ 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.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "i2c.h"
+#include "algo-bit.h"
+
+/* Fan defines */
+#define I2C_GL518SM 0x2d /* 7-bit i2c slave address */
+#define REGMASK 0x1f
+#define PROCNAME "temperature"
+
+/* i2c */
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+static struct i2c_client *client = &client_template;
+
+/* ---------------------------------------------------------------------- */
+
+static unsigned int gl_sysmon_read(int reg, int count)
+{
+ struct i2c_msg msgs[2];
+ char write[1]={0};
+ char read[2]={0,0};
+ int ret;
+ unsigned int val;
+
+ msgs[0].addr = msgs[1].addr = client->addr;
+ msgs[0].flags = msgs[1].flags =
+ (client->flags & (I2C_M_TEN|I2C_M_TENMASK));
+
+ msgs[0].len = 1;
+ msgs[0].buf = write;
+ write[0] = reg & REGMASK;
+
+ msgs[1].flags |= I2C_M_RD;
+ msgs[1].len = count;
+ msgs[1].buf = read;
+
+ ret = i2c_transfer(client->adapter, msgs, 2);
+
+ if ( 2 != ret ) return ret;
+ if (count==1)
+ val = read[0] & 0xff;
+ else
+ val = ( (read[0]<<8)|(read[1] & 0xff) ) & 0xffff;
+
+ return val;
+}
+
+static int gl_sysmon_write(int reg, unsigned int val, int count)
+{
+ unsigned char buffer[5];
+
+ buffer[0] = reg & REGMASK;
+ if (count==2) {
+ buffer[1] = (val >> 8) & 0xff;
+ buffer[2] = val & 0xff;
+ count = 3;
+ } else {
+ buffer[1] = val & 0xff;
+ count = 2;
+ }
+
+ if (count != i2c_master_send(client, buffer, count))
+ return -1;
+ return 0;
+}
+
+static int gl_sysmon_info(char *buf, char **start, off_t fpos, int length, int dummy)
+{
+ char * p=buf;
+ int i;
+ unsigned int regs[32];
+
+ for (i=0; i<32; i++) {
+ regs[i] = 0;
+ regs[i] = gl_sysmon_read(i, (i>6 && i<13) ? 2 : 1);
+ }
+
+ p += sprintf(buf, "CPU temperature %d Celsius\n", (regs[4]-119));
+
+ return p - buf;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct proc_dir_entry *ent;
+
+static int gl_sysmon_attach(struct i2c_adapter *adap)
+{
+ client->adapter = adap;
+
+ i2c_attach_client(client);
+ gl_sysmon_write(3, 64, 1);
+
+ ent = create_proc_entry(PROCNAME, 0, 0);
+ ent->get_info = gl_sysmon_info;
+
+ printk("EISCA Fan connected\n");
+ return 0;
+}
+
+static int gl_sysmon_detach(struct i2c_client *client)
+{
+ gl_sysmon_write(3, 128, 1);
+ i2c_detach_client(client);
+ remove_proc_entry(PROCNAME, 0);
+
+ printk("EISCA Fan disconnected\n");
+ return 0;
+}
+
+static int
+gl_sysmon_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ return -1;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+ "GL518SM",
+ -1,
+ DF_NOTIFY,
+ gl_sysmon_attach,
+ gl_sysmon_detach,
+ gl_sysmon_command,
+};
+
+static struct i2c_client client_template = {
+ "EISCA Cooler",
+ I2C_DRIVERID_GL518SM,
+ 0,
+ I2C_GL518SM,
+ NULL,
+ &driver
+};
+
+#ifdef MODULE
+MODULE_AUTHOR("Kyosti Malkki ");
+MODULE_DESCRIPTION("i2c driver for GL518SM");
+
+int init_module(void)
+{
+ i2c_add_driver(&driver);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ i2c_del_driver(&driver);
+}
+#endif
diff --git a/i2c/i2c-core.c b/i2c/i2c-core.c
new file mode 100644
index 00000000..03ae5532
--- /dev/null
+++ b/i2c/i2c-core.c
@@ -0,0 +1,467 @@
+/* ------------------------------------------------------------------------- */
+/* i2c.c - a device driver for the iic-bus interface */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-98 Simon G. Vogl
+
+ 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. */
+/* ------------------------------------------------------------------------- */
+#define RCSID "$Id: i2c.c,v 1.7 1998/09/28 06:45:38 i2c Exp i2c $"
+/* ------------------------------------------------------------------------- */
+
+#include
+#include
+#include
+#include
+
+#include "i2c.h"
+
+/* ----- global defines ---------------------------------------------------- */
+
+/* exclusive access to the bus */
+/*#define SPINLOCK*/
+#ifdef SPINLOCK
+#define I2C_LOCK(adap) spin_lock_irqsave(&adap->lock,adap->lockflags)
+#define I2C_UNLOCK(adap) spin_unlock_irqrestore(&adap->lock,adap->lockflags)
+#else
+#define I2C_LOCK(adap) down(&adap->lock)
+#define I2C_UNLOCK(adap) up(&adap->lock)
+#endif
+
+#define DEB(x) if (i2c_debug>=1) x;
+#define DEB2(x) if (i2c_debug>=2) x;
+
+/* ----- global variables -------------------------------------------------- */
+
+/**** algorithm list */
+struct i2c_algorithm *algorithms[I2C_ALGO_MAX];
+int algo_count;
+
+/**** adapter list */
+struct i2c_adapter *adapters[I2C_ADAP_MAX];
+int adap_count;
+
+/**** drivers list */
+struct i2c_driver *drivers[I2C_DRIVER_MAX];
+int driver_count;
+
+/**** debug level */
+int i2c_debug=1;
+
+/* ---------------------------------------------------
+ * registering functions
+ * ---------------------------------------------------
+ */
+
+/* -----
+ * Algorithms - used to access groups of similar hw adapters or
+ * specific interfaces like the PCF8584 et al.
+ */
+int i2c_add_algorithm(struct i2c_algorithm *algo)
+{
+ int i;
+
+ for (i = 0; i < I2C_ALGO_MAX; i++)
+ if (NULL == algorithms[i])
+ break;
+ if (I2C_ALGO_MAX == i) {
+ printk(KERN_WARNING
+ " i2c: register_algorithm(%s) - enlarge I2C_ALGO_MAX.\n",
+ algo->name);
+ return -ENOMEM;
+ }
+
+ algorithms[i] = algo;
+ algo_count++;
+
+ DEB(printk("i2c: algorithm %s registered.\n",algo->name));
+ return 0;
+}
+
+
+int i2c_del_algorithm(struct i2c_algorithm *algo)
+{
+ int i;
+
+ for (i = 0; i < I2C_ALGO_MAX; i++)
+ if (algo == algorithms[i])
+ break;
+ if (I2C_ALGO_MAX == i) {
+ printk(KERN_WARNING
+ " i2c: unregister_algorithm: [%s] not found.\n",
+ algo->name);
+ return -ENODEV;
+ }
+ algorithms[i] = NULL;
+ algo_count--;
+
+ DEB(printk("i2c: algorithm unregistered: %s\n",algo->name));
+ return 0;
+}
+
+
+/* -----
+ * i2c_add_adapter is called from within the algorithm layer,
+ * when a new hw adapter registers. A new device is register to be
+ * available for clients.
+ */
+int i2c_add_adapter(struct i2c_adapter *adap)
+{
+ int i;
+
+ for (i = 0; i < I2C_ADAP_MAX; i++)
+ if (NULL == adapters[i])
+ break;
+ if (I2C_ADAP_MAX == i) {
+ printk(KERN_WARNING
+ " i2c: register_adapter(%s) - enlarge I2C_ADAP_MAX.\n",
+ adap->name);
+ return -ENOMEM;
+ }
+
+
+ adapters[i] = adap;
+ adap_count++;
+
+ /* init data types */
+#ifdef SPINLOCK
+ adap->lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
+#else
+ adap->lock = MUTEX;
+#endif
+
+ /* inform drivers of new adapters */
+ for (i=0;iflags&DF_NOTIFY)
+ drivers[i]->attach_adapter(adap);
+
+ DEB(printk("i2c: adapter %s registered.\n",adap->name));
+ return 0;
+}
+
+int i2c_del_adapter(struct i2c_adapter *adap)
+{
+ int i,j;
+
+ for (i = 0; i < I2C_ADAP_MAX; i++)
+ if (adap == adapters[i])
+ break;
+ if (I2C_ADAP_MAX == i) {
+ printk(KERN_WARNING
+ " i2c: unregister_adapter adap [%s] not found.\n",
+ adap->name);
+ return -ENODEV;
+ }
+
+ /* detach any active clients */
+ for (j=0;jclients[j];
+ if ( (client!=NULL)
+ /* && (client->driver->flags & DF_NOTIFY) */ )
+ /* detaching devices is unconditional of the set notify
+ * flag, as _all_ clients that reside on the adapter
+ * must be deleted, as this would cause invalid states.
+ */
+ i2c_detach_client(client);
+ }
+ /* all done, now unregister */
+ adapters[i] = NULL;
+ adap_count--;
+
+ DEB(printk("i2c: adapter unregistered: %s\n",adap->name));
+ return 0;
+}
+
+/* -----
+ * What follows is the "upwards" interface: commands for talking to clients,
+ * which implement the functions to access the physical information of the
+ * chips.
+ */
+
+int i2c_add_driver(struct i2c_driver *driver)
+{
+ int i;
+
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (NULL == drivers[i])
+ break;
+ if (I2C_DRIVER_MAX == i) {
+ printk(KERN_WARNING
+ " i2c: register_driver(%s) - enlarge I2C_DRIVER_MAX.\n",
+ driver->name);
+ return -ENOMEM;
+ }
+
+ drivers[i] = driver;
+ driver_count++;
+
+ DEB(printk("i2c: driver %s registered.\n",driver->name));
+
+ /* now look for instances of driver on our adapters
+ */
+ if ( driver->flags&DF_NOTIFY )
+ for (i=0;iattach_adapter(adapters[i]);
+
+ return 0;
+}
+
+int i2c_del_driver(struct i2c_driver *driver)
+{
+ int i,j,k;
+
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (driver == drivers[i])
+ break;
+ if (I2C_DRIVER_MAX == i) {
+ printk(KERN_WARNING " i2c: unregister_driver: [%s] not found\n",
+ driver->name);
+ return -ENODEV;
+ }
+ /* Have a look at each adapter, if clients of this driver are still
+ * attached. If so, detach them to be able to kill the driver afterwards.
+ */
+ DEB2(printk("i2c: unregister_driver - looking for clients.\n"));
+ /* removing clients does not depend on the notify flag, else
+ * invalid operation might (will!) result, when using stale client
+ * pointers.
+ */
+ for (k=0;kname));
+ for (j=0;jclients[j];
+ if (client != NULL && client->driver == driver) {
+ DEB2(printk("i2c: detaching client %s:\n",
+ client->name));
+ /*i2c_detach_client(client);*/
+ driver->detach_client(client);
+ }
+ }
+ }
+ drivers[i] = NULL;
+ driver_count--;
+
+ DEB(printk("i2c: driver unregistered: %s\n",driver->name));
+ return 0;
+}
+
+
+int i2c_attach_client(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct i2c_algorithm *algo = adapter->algo;
+ int i;
+
+ for (i = 0; i < I2C_CLIENT_MAX; i++)
+ if (NULL == adapter->clients[i])
+ break;
+ if (I2C_CLIENT_MAX == i) {
+ printk(KERN_WARNING
+ " i2c: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n",
+ client->name);
+ return -ENOMEM;
+ }
+
+ adapter->clients[i] = client;
+ adapter->client_count++;
+ if (algo->client_register != NULL)
+ algo->client_register(client);
+ DEB(printk("i2c: client [%s] registered to adapter [%s](pos. %d).\n",
+ client->name, adapter->name,i));
+ return 0;
+}
+
+
+int i2c_detach_client(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct i2c_algorithm *algo = adapter->algo;
+ int i;
+
+ for (i = 0; i < I2C_CLIENT_MAX; i++)
+ if (client == adapter->clients[i])
+ break;
+ if (I2C_CLIENT_MAX == i) {
+ printk(KERN_WARNING " i2c: unregister_client [%s] not found\n",
+ client->name);
+ return -ENODEV;
+ }
+
+ if (algo->client_unregister != NULL)
+ algo->client_unregister(client);
+ /* client->driver->detach_client(client);*/
+ adapter->clients[i] = NULL;
+ adapter->client_count--;
+ DEB(printk("i2c: client [%s] unregistered.\n",client->name));
+ return 0;
+}
+
+int i2c_init(void)
+{
+ /* clear algorithms */
+ memset(algorithms,0,sizeof(algorithms));
+ memset(adapters,0,sizeof(adapters));
+ memset(drivers,0,sizeof(drivers));
+ algo_count=0;
+ adap_count=0;
+ driver_count=0;
+
+ printk("i2c module initialized.\n");
+ return 0;
+}
+
+
+/* ----------------------------------------------------
+ * the functional interface to the i2c busses.
+ * ----------------------------------------------------
+ */
+
+int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num)
+{
+ int ret;
+
+ DEB(printk("master_xfer: %s with %d msgs.\n",adap->name,num));
+
+ I2C_LOCK(adap);
+ ret = adap->algo->master_xfer(adap,msgs,num);
+ I2C_UNLOCK(adap);
+
+ return ret;
+}
+
+int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
+{
+ int ret;
+ struct i2c_adapter *adap=client->adapter;
+ struct i2c_msg msg;
+ msg.addr = client->addr;
+ msg.flags = client->flags & ( I2C_M_TEN|I2C_M_TENMASK );
+ msg.len = count;
+ (const char *)msg.buf = buf;
+
+ DEB(printk("master_send: writing %d bytes on %s.\n",
+ count,client->adapter->name));
+
+ I2C_LOCK(adap);
+ ret = adap->algo->master_xfer(adap,&msg,1);
+ I2C_UNLOCK(adap);
+
+ /* if everything went ok (i.e. 1 msg transmitted), return #bytes
+ * transmitted, else error code.
+ */
+ return (ret == 1 )? count : ret;
+}
+
+int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
+{
+ struct i2c_adapter *adap=client->adapter;
+ struct i2c_msg msg;
+ int ret;
+ msg.addr = client->addr;
+ msg.flags = client->flags & ( I2C_M_TEN|I2C_M_TENMASK );
+ msg.flags |= I2C_M_RD;
+ msg.len = count;
+ msg.buf = buf;
+
+ DEB(printk("master_recv: reading %d bytes on %s.\n",
+ count,client->adapter->name));
+
+ I2C_LOCK(adap);
+ ret = adap->algo->master_xfer(adap,&msg,1);
+ I2C_UNLOCK(adap);
+
+ /* if everything went ok (i.e. 1 msg transmitted), return #bytes
+ * transmitted, else error code.
+ */
+ return (ret == 1 )? count : ret;
+}
+
+
+int i2c_control(struct i2c_client *client,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ struct i2c_adapter *adap = client->adapter;
+
+ DEB2(printk("i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg));
+ switch ( cmd ) {
+ case I2C_RETRIES:
+ adap->retries = arg;
+ break;
+ case I2C_TIMEOUT:
+ adap->timeout = arg;
+ break;
+ default:
+ if (adap->algo->algo_control!=NULL)
+ ret = adap->algo->algo_control(adap,cmd,arg);
+ }
+ return ret;
+}
+
+int i2c_probe(struct i2c_client *client, int low_addr, int hi_addr)
+{
+ int i;
+ struct i2c_msg msg;
+ struct i2c_msg *pmsg = &msg;
+ msg.flags=client->flags & (I2C_M_TENMASK | I2C_M_TEN );
+ msg.buf = NULL;
+ msg.len = 0;
+ I2C_LOCK(client->adapter);
+ for (i = low_addr; i <= hi_addr; i++) {
+ client->addr=i;
+ /* TODO: implement a control statement in the algo layer
+ * that does address lookup only.
+ */
+ if (1 == client->adapter->
+ algo->master_xfer(client->adapter,pmsg,1))
+ break;
+ }
+ I2C_UNLOCK(client->adapter);
+ return (i <= hi_addr) ? i : -1;
+}
+
+#ifdef MODULE
+MODULE_AUTHOR("Simon G. Vogl ");
+MODULE_DESCRIPTION("I2C-Bus main module");
+MODULE_PARM(i2c_debug, "i");
+MODULE_PARM_DESC(i2c_debug,"debug level");
+
+EXPORT_SYMBOL(i2c_add_algorithm);
+EXPORT_SYMBOL(i2c_del_algorithm);
+EXPORT_SYMBOL(i2c_add_adapter);
+EXPORT_SYMBOL(i2c_del_adapter);
+EXPORT_SYMBOL(i2c_add_driver);
+EXPORT_SYMBOL(i2c_del_driver);
+EXPORT_SYMBOL(i2c_attach_client);
+EXPORT_SYMBOL(i2c_detach_client);
+
+EXPORT_SYMBOL(i2c_master_send);
+EXPORT_SYMBOL(i2c_master_recv);
+EXPORT_SYMBOL(i2c_control);
+EXPORT_SYMBOL(i2c_transfer);
+
+
+int init_module(void)
+{
+ return i2c_init();
+}
+
+void cleanup_module(void)
+{
+}
+#endif
diff --git a/i2c/i2c-dev.c b/i2c/i2c-dev.c
new file mode 100644
index 00000000..44d76d6d
--- /dev/null
+++ b/i2c/i2c-dev.c
@@ -0,0 +1,364 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-dev.c - i2c-bus driver, char device interface */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-97 Simon G. Vogl
+
+ 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. */
+/* ------------------------------------------------------------------------- */
+#define RCSID "$Id: i2c-dev.c,v 1.6 1998/09/28 06:45:38 i2c Exp i2c $"
+/* ------------------------------------------------------------------------- */
+
+#include
+#include
+#include
+#include
+
+#if LINUX_VERSION_CODE >= 0x020100
+# include
+#else
+# include
+#endif
+
+#include "i2c.h"
+
+/* ----- global defines ---------------------------------------------------- */
+#define DEB(x) /* should be reasonable open, close &c. */
+#define DEBE(x) x /* error messages ~ */
+#define DEBI(x) /* ioctl and its arguments */
+
+/* ----- global variables -------------------------------------------------- */
+
+/* save the registered char devices.
+ * there is one device per i2c adapter.
+ */
+#define I2C_DEV_MAX I2C_ADAP_MAX
+struct i2c_client *devs[I2C_DEV_MAX];
+int dev_count;
+
+struct i2c_driver driver;
+struct i2c_client dev_template = {
+ "I2C char device", /* name */
+ -1, /* id */
+ 0, /* flags */
+ 0, /* address */
+ NULL, /* adapter */
+ &driver, /* driver */
+};
+
+
+/* ----- local functions --------------------------------------------------- */
+
+#if LINUX_VERSION_CODE >= 0x020100
+long long i2c_lseek(struct file * file, long long offset, int origin)
+#else
+int i2c_lseek (struct inode * inode, struct file *file, off_t offset, int origin)
+#endif
+{
+ return -ESPIPE;
+}
+
+
+int i2c_open(struct inode * inode, struct file * file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+
+ if (minor >= dev_count ) {
+ DEBE(printk("i2c: minor exceeded ports\n"));
+ return -ENODEV;
+ }
+ file->private_data = devs[minor];
+ MOD_INC_USE_COUNT;
+ i2c_attach_client(devs[minor]); /* tell adapter it is in use. */
+
+ DEB(printk("i2c_open: i2c%d\n",minor));
+ return 0;
+}
+
+#if LINUX_VERSION_CODE >= 0x020100
+int i2c_release (struct inode * inode, struct file * file)
+#else
+void i2c_release (struct inode * inode, struct file * file)
+#endif
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+
+ file->private_data=NULL;
+ DEB(printk("i2c_close: i2c%d\n",minor));
+ i2c_detach_client(devs[minor]);
+ MOD_DEC_USE_COUNT;
+#if LINUX_VERSION_CODE >= 0x020100
+ return 0;
+#endif
+}
+
+#if LINUX_VERSION_CODE >= 0x020140 /* file operations changed again...*/
+ssize_t i2c_write(struct file * file,
+ const char * buf, size_t count, loff_t *ppos)
+#else
+# if LINUX_VERSION_CODE >= 0x020100
+long i2c_write(struct inode * inode, struct file * file,
+ const char * buf, unsigned long count)
+# else
+int i2c_write (struct inode *inode, struct file *file,
+ const char *buf, int count)
+# endif
+#endif
+{
+#if LINUX_VERSION_CODE >= 0x020140
+ struct inode *inode = file->f_dentry->d_inode;
+#endif
+ int ret;
+ char *tmp;
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct i2c_client *client =
+ (struct i2c_client *)file->private_data;
+
+ if (minor>=dev_count){
+ DEBE(printk("i2c_write: minor %d invalid\n",minor));
+ return -EINVAL;
+ }
+
+ /* copy user space data to kernel space. */
+ tmp = kmalloc(count,GFP_KERNEL);
+ if (tmp==NULL)
+ return -ENOMEM;
+#if LINUX_VERSION_CODE >= 0x020100
+ copy_from_user(tmp,buf,count);
+#else
+ memcpy_fromfs(tmp,buf,count);
+#endif
+
+ DEB(printk("i2c_write: i2c%d writing %d bytes.\n",minor,count));
+
+ ret = i2c_master_send(client,tmp,count);
+ kfree(tmp);
+ return ret;
+}
+
+#if LINUX_VERSION_CODE >= 0x020140 /* file operations changed again...*/
+ssize_t i2c_read(struct file * file,char * buf, size_t count, loff_t *ppos)
+#else
+#if LINUX_VERSION_CODE >= 0x020100
+long i2c_read(struct inode * inode, struct file * file,
+ char * buf, unsigned long count)
+#else
+int i2c_read (struct inode *inode, struct file *file, char *buf, int count)
+#endif
+#endif
+{
+#if LINUX_VERSION_CODE >= 0x020140
+ struct inode *inode = file->f_dentry->d_inode;
+#endif
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct i2c_client *client =
+ (struct i2c_client *)file->private_data;
+ char *tmp;
+ int ret;
+
+ DEB(printk("i2c_read: i2c%d reading %d bytes from %d.\n",minor,count,client->addr));
+ if (minor>=dev_count) {
+ DEBE(printk("i2c_write: minor %d invalid\n",minor));
+ return -EINVAL;
+ }
+
+ /* copy user space data to kernel space. */
+ tmp = kmalloc(count,GFP_KERNEL);
+ if (tmp==NULL)
+ return -ENOMEM;
+ ret = i2c_master_recv(client,tmp,count);
+#if LINUX_VERSION_CODE >= 0x020100
+ copy_to_user(buf,tmp,count);
+#else
+ memcpy_tofs(buf,tmp,count);
+#endif
+
+ return ret;
+}
+
+
+int i2c_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct i2c_client *client =
+ (struct i2c_client *)file->private_data;
+ int ret = 0;
+
+ DEBI(printk("i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg));
+ switch ( cmd ) {
+ case I2C_SLAVE:
+ client->addr = arg;
+ break;
+ case I2C_TENBIT:
+ client->flags &= !I2C_M_TENMASK;
+ if (arg<0)
+ return 0;
+ switch(arg) {
+ case 0:
+ client->flags|=I2C_M_TEN0;
+ break;
+ case 1:
+ client->flags|=I2C_M_TEN1;
+ break;
+ case 2:
+ client->flags|=I2C_M_TEN2;
+ break;
+ case 3:
+ client->flags|=I2C_M_TEN3;
+ break;
+ default:
+ printk("i2c-dev(%d): illegal arg to I2C_TEN: %ld\n"
+ ,minor,arg);
+ };
+ break;
+#if 0
+ case I2C_WRITE_SIZE:
+ if ( arg >= I2C_BUFFER_SIZE ) {
+ printk("i2c%d: write size too big (%ld)",minor,arg);
+ return -E2BIG;
+ }
+ data->writelength = arg;
+ if ( arg > 0 )
+ i2c_table[minor].flags|= P_REG;
+ else
+ i2c_table[minor].flags&=!P_REG;
+ break;
+ case I2C_WRITE_BUF:
+#if LINUX_VERSION_CODE >= 0x020100
+ copy_from_user(data->buf,(char*)arg,data->writelength);
+#else
+ memcpy_fromfs(data->buf,(char*)arg,data->writelength);
+#endif
+ break;
+#endif
+ default:
+ ret = i2c_control(client,cmd,arg);
+ }
+ DEB(printk("i2c(dev): handled ioctl (%d,%ld)\n",cmd,arg));
+ return ret;
+}
+
+
+/* ----- module functions --------------------------------------------- */
+struct file_operations i2c_fops = {
+ i2c_lseek,
+ i2c_read,
+ i2c_write,
+ NULL, /* i2c_readdir */
+ NULL, /* i2c_select */
+ i2c_ioctl,
+ NULL, /* i2c_mmap */
+ i2c_open,
+#if LINUX_VERSION_CODE >= 0x020178
+ NULL, /* i2c_flush */
+#endif
+ i2c_release,
+};
+
+int attach_adapter(struct i2c_adapter *adap)
+{
+ int i;
+ struct i2c_client *client;
+
+ for (i = 0; i < I2C_DEV_MAX; i++)
+ if (NULL == devs[i])
+ break;
+ if (I2C_DEV_MAX == i)
+ return -ENOMEM;
+
+ client = (struct i2c_client *)kmalloc(sizeof(struct i2c_client),
+ GFP_KERNEL);
+ if (client==NULL)
+ return -ENOMEM;
+ memcpy(client,&dev_template,sizeof(struct i2c_client));
+ client->adapter = adap;
+/* for combined r/w:
+ client->data = kmalloc(sizeof(char)*I2C_BUFFER_SIZE,GFP_KERNEL);
+*/
+ devs[i] = client;
+ dev_count++;
+
+ DEB(printk("i2c(char): registered '%s' as minor %d\n",adap->name,i));
+ return 0;
+}
+
+int detach_adapter(struct i2c_client *client)
+{
+ struct i2c_adapter *adap = client->adapter;
+ int i;
+ for (i = 0; i < I2C_DEV_MAX; i++)
+ if (devs[i]->adapter == adap)
+ break;
+ if (I2C_DEV_MAX == i)
+ {
+ printk(KERN_WARNING "i2c(char): detach adapter %s not found\n",
+ adap->name);
+ return -ENODEV;
+ }
+ if (devs[i]->data)
+ kfree(devs[i]->data);
+ kfree(devs[i]);
+ devs[i] = NULL;
+ dev_count--;
+
+ DEB(printk("i2c(char): adapter unregistered: %s\n",adap->name));
+ return 0;
+}
+
+int command(struct i2c_client *client,unsigned int cmd, void *arg)
+{
+ return -1;
+}
+
+
+
+struct i2c_driver driver = {
+ "i2c character device",
+ 2, /* id */
+ DF_NOTIFY, /* flags */
+ attach_adapter,
+ detach_adapter,
+ command,
+};
+
+#ifdef MODULE
+MODULE_AUTHOR("Simon G. Vogl ");
+MODULE_DESCRIPTION("I2C-Bus character device interface");
+
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (register_chrdev(I2C_MAJOR,"i2c",&i2c_fops)) {
+ printk("i2c: unable to get major %d for i2c bus\n",I2C_MAJOR);
+ return -EIO;
+ }
+
+ memset(&devs,0,sizeof(devs));
+ dev_count = 0;
+
+ i2c_add_driver(&driver);
+ printk("i2c char device interface initialized.\n");
+ return 0;
+}
+
+
+void cleanup_module(void)
+{
+ i2c_del_driver(&driver);
+ unregister_chrdev(I2C_MAJOR,"i2c");
+}
+
+#endif
diff --git a/i2c/i2c.h b/i2c/i2c.h
new file mode 100644
index 00000000..bb8a1b5a
--- /dev/null
+++ b/i2c/i2c.h
@@ -0,0 +1,371 @@
+/* ------------------------------------------------------------------------- */
+/* */
+/* i2c.h - definitions for the \iic-bus interface */
+/* */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995 Simon G. Vogl
+
+ 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 _I2C_H
+#define _I2C_H
+
+#ifdef __KERNEL__
+
+/* define spinlock to use spinlocks for sync., else use semaphores*/
+/*#define SPINLOCK*/
+
+#ifdef SPINLOCK
+#include /* for spinlock_t */
+#else
+#include
+#endif
+/* --- General options ------------------------------------------------ */
+
+#define I2C_ALGO_MAX 4 /* control memory consumption */
+#define I2C_ADAP_MAX 16
+#define I2C_DRIVER_MAX 16
+#define I2C_CLIENT_MAX 32
+
+struct i2c_msg;
+struct i2c_algorithm;
+struct i2c_adapter;
+struct i2c_client;
+struct i2c_driver;
+
+
+/*
+ * The master routines are the ones normally used to transmit data to devices
+ * on a bus (or read from them). Apart from two basic transfer functions to transmit
+ * one message at a time, a more complex version can be used to transmit an arbitrary
+ * number of messages without interruption.
+ */
+extern int i2c_master_send(struct i2c_client *,const char* ,int);
+extern int i2c_master_recv(struct i2c_client *,char* ,int);
+
+/* Transfer num messages.
+ */
+extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],int num);
+
+
+/*
+ * Some adapter types (i.e. PCF 8584 based ones) may support slave behaviuor.
+ * This is not tested/implemented yet and will change in the future.
+ */
+extern int i2c_slave_send(struct i2c_client *,char*,int);
+extern int i2c_slave_recv(struct i2c_client *,char*,int);
+
+
+
+/*
+ * I2C Message - could be used in the current interface to
+ */
+struct i2c_msg {
+ unsigned char addr; /* slave address */
+ unsigned short flags;
+#define I2C_M_TEN 0x10 /* we have a ten bit chip address */
+#define I2C_M_TEN0 0x10 /* herein lie the first 2 bits */
+#define I2C_M_TEN1 0x12
+#define I2C_M_TEN2 0x14
+#define I2C_M_TEN3 0x16
+#define I2C_M_TENMASK 0x06
+#define I2C_M_RD 0x01
+ short len; /* msg length */
+ char *buf; /* pointer to msg data */
+};
+
+/*
+ * A driver is capable of handling one or more physical devices present on
+ * I2C adapters. This information is used to inform the driver of adapter
+ * events.
+ */
+
+struct i2c_driver {
+ char name[32];
+ int id;
+ unsigned int flags; /* div., see below */
+
+ /* notifies the driver that a new bus has appeared. This routine
+ * can be used by the driver to test if the bus meets its conditions
+ * & seek for the presence of the chip(s) it supports. If found, it
+ * registers the client(s) that are on the bus to the i2c admin. via
+ * i2c_attach_client
+ */
+ int (*attach_adapter)(struct i2c_adapter *);
+
+ /* tells the driver that a client is about to be deleted & gives it
+ * the chance to remove its private data. Also, if the client struct
+ * has been dynamically allocated by the driver in the function above,
+ * it must be freed here.
+ */
+ int (*detach_client)(struct i2c_client *);
+
+ /* a ioctl like command that can be used to perform specific functions
+ * with the device.
+ */
+ int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
+
+ /* These two are mainly used for bookkeeping & dynamic unloading of
+ * kernel modules. inc_use tells the driver that a client is being
+ * used by another module & that it should increase its ref. counter.
+ * dec_use is the inverse operation.
+ * NB: Make sure you have no circular dependencies, or else you get a
+ * deadlock when trying to unload the modules.
+ */
+ void (*inc_use)(struct i2c_client *client);
+ void (*dec_use)(struct i2c_client *client);
+};
+
+/*
+ * i2c_client identifies a single device (i.e. chip) that is connected to an
+ * i2c bus. The behaviour is defined by the routines of the driver. This
+ * function is mainly used for lookup & other admin. functions.
+ */
+struct i2c_client {
+ char name[32];
+ int id;
+ unsigned int flags; /* div., see below */
+ unsigned char addr; /* chip address - NOTE: 7bit */
+ /* addresses are stored in the */
+ /* _LOWER_ 7 bits of this char */
+ /* 10 bit addresses use the full*/
+ /* 8 bits & the flags like in */
+ /* i2c_msg */
+ struct i2c_adapter *adapter; /* the adapter we sit on */
+ struct i2c_driver *driver; /* and our access routines */
+ void *data; /* for the clients */
+};
+
+
+/*
+ * The following structs are for those who like to implement new bus drivers:
+ * i2c_algorithm is the interface to a class of hardware solutions which can
+ * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584
+ * to name two of the most common.
+ */
+struct i2c_algorithm {
+ char name[32]; /* textual description */
+ unsigned int id;
+ /*
+ int (*master_send)(struct i2c_client *,const char*,int);
+ int (*master_recv)(struct i2c_client *,char*,int);
+ int (*master_comb)(struct i2c_client *,char*,const char*,int,int,int);
+ */
+ int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg msgs[], int num);
+
+ /* --- these optional/future use for some adapter types.*/
+ int (*slave_send)(struct i2c_adapter *,char*,int);
+ int (*slave_recv)(struct i2c_adapter *,char*,int);
+
+ /* --- ioctl like call to set div. parameters. */
+ int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);
+
+ /* --- administration stuff. */
+ int (*client_register)(struct i2c_client *);
+ int (*client_unregister)(struct i2c_client *);
+};
+
+
+/*
+ * i2c_adapter is the structure used to identify a physical i2c bus along
+ * with the access algorithms necessary to access it.
+ */
+struct i2c_adapter {
+ char name[32]; /* some useful name to identify the adapter */
+ unsigned int id;/* == is algo->id | hwdep.struct->id, */
+ /* for registered values see below */
+ struct i2c_algorithm *algo;/* the algorithm to access the bus */
+
+ void *data; /* private data for the adapter */
+ /* some data fields that are used by all types */
+ /* these data fields are readonly to the public */
+ /* and can be set via the i2c_ioctl call */
+
+ /* data fields that are valid for all devices */
+#ifdef SPINLOCK
+ spinlock_t lock;/* used to access the adapter exclusively */
+ unsigned long lockflags;
+#else
+ struct semaphore lock;
+#endif
+ unsigned int flags;/* flags specifying div. data */
+
+ struct i2c_client *clients[I2C_CLIENT_MAX];
+ int client_count;
+
+ int timeout;
+ int retries;
+};
+
+
+/*flags for the driver struct:
+ */
+#define DF_NOTIFY 0x01 /* notify on bus (de/a)ttaches */
+
+
+#if 0 /* deprecate! */
+/*flags for the client struct:
+ */
+#define CF_TEN 0x100000 /* we have a ten bit chip address */
+#define CF_TEN0 0x100000 /* herein lie the first 2 bits */
+#define CF_TEN1 0x110000
+#define CF_TEN2 0x120000
+#define CF_TEN3 0x130000
+#define TENMASK 0x130000
+#endif
+
+/* ----- functions exported by i2c.o */
+
+/* administration...
+ */
+extern int i2c_add_algorithm(struct i2c_algorithm *);
+extern int i2c_del_algorithm(struct i2c_algorithm *);
+
+extern int i2c_add_adapter(struct i2c_adapter *);
+extern int i2c_del_adapter(struct i2c_adapter *);
+
+extern int i2c_add_driver(struct i2c_driver *);
+extern int i2c_del_driver(struct i2c_driver *);
+
+extern int i2c_attach_client(struct i2c_client *);
+extern int i2c_detach_client(struct i2c_client *);
+
+
+/*
+ * A utility function used in the attach-phase of drivers. Returns at the first address
+ * that acks in the given range.
+ */
+extern int i2c_probe(struct i2c_client *client, int low_addr, int hi_addr);
+
+/* An ioctl like call to set div. parameters of the adapter.
+ */
+extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
+
+
+#endif /* __KERNEL__ */
+
+
+/* ----- commands for the ioctl like i2c_command call:
+ * note that additional calls are defined in the algorithm and hw
+ * dependent layers - these can be listed here, or see the
+ * corresponding header files.
+ */
+ /* -> bit-adapter specific ioctls */
+#define I2C_RETRIES 0x0701 /* number times a device adress should */
+ /* be polled when not acknowledging */
+#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */
+
+
+/* this is for i2c-dev.c */
+#define I2C_SLAVE 0x0703 /* Change slave address */
+ /* Attn.: Slave address is 7 bits long, */
+ /* these are to be passed as the */
+ /* lowest 7 bits in the arg. */
+ /* for 10-bit addresses pass lower 8bits*/
+#define I2C_TENBIT 0x0704 /* with 0-3 as arg to this call */
+ /* a value <0 resets to 7 bits */
+/* ... algo-bit.c recognizes */
+#define I2C_UDELAY 0x0705 /* set delay in microsecs between each */
+ /* written byte (except address) */
+#define I2C_MDELAY 0x0706 /* millisec delay between written bytes */
+
+#if 0
+#define I2C_ADDR 0x0707 /* Change adapter's \iic address */
+ /* ...not supported by all adap's */
+
+#define I2C_RESET 0x07fd /* reset adapter */
+#define I2C_CLEAR 0x07fe /* when lost, use to clear stale info */
+#define I2C_V_SLOW 0x07ff /* set jiffies delay call with int */
+
+#define I2C_INTR 0x0708 /* Pass interrupt number - 2be impl. */
+
+#endif
+
+/*
+ * ---- Driver types -----------------------------------------------------
+ */
+
+#define I2C_DRIVERID_MSP3400 1
+#define I2C_DRIVERID_TUNER 2
+#define I2C_DRIVERID_VIDEOTEXT 3
+#define I2C_DRIVERID_GL518SM 4
+
+/*
+ * ---- Adapter types ----------------------------------------------------
+ *
+ * First, we distinguish between several algorithms to access the hardware
+ * interface types, as a PCF 8584 needs other care than a bit adapter.
+ */
+
+#define ALGO_NONE 0x00000
+#define ALGO_BIT 0x10000 /* bit style adapters */
+#define ALGO_PCF 0x20000 /* PCF 8584 style adapters */
+
+#define ALGO_MASK 0xf0000 /* Mask for algorithms */
+#define ALGO_SHIFT 0x10 /* right shift to get index values */
+
+#define I2C_HW_ADAPS 0x10000 /* number of different hw implements per*/
+ /* algorithm layer module */
+#define I2C_HW_MASK 0xffff /* space for indiv. hw implmentations */
+
+
+/* hw specific modules that are defined per algorithm layer
+ */
+
+/* --- Bit algorithm adapters */
+#define HW_B_LP 0x00 /* Parallel port Philips style adapter */
+#define HW_B_LPC 0x01 /* Parallel port, over control reg. */
+#define HW_B_SER 0x02 /* Serial line interface */
+#define HW_B_ELV 0x03 /* ELV Card */
+#define HW_B_VELLE 0x04 /* Vellemann K8000 */
+#define HW_B_BT848 0x05 /* BT848 video boards */
+#define HW_B_WNV 0x06 /* Winnov Videums */
+#define HW_B_MB 0x07 /* Via vt82c586b */
+
+/* --- PCF 8584 based algorithms */
+#define HW_P_LP 0x00 /* Parallel port interface */
+#define HW_P_ISA 0x01 /* generic ISA Bus inteface card */
+#define HW_P_ELEK 0x02 /* Elektor ISA Bus inteface card */
+
+
+
+
+/* ----- I2C-DEV: char device interface stuff ------------------------- */
+
+#define I2C_MAJOR 89 /* Device major number */
+
+
+# if LINUX_VERSION_CODE < 0x020100
+/* Hack to make this thing compile under 2.0.xx kernels
+ */
+
+# ifdef MODULE
+# define MODULE_AUTHOR(noone)
+# define MODULE_DESCRIPTION(none)
+# define MODULE_PARM(no,param)
+# define MODULE_PARM_DESC(no,description)
+# define EXPORT_SYMBOL(noexport)
+# define EXPORT_NO_SYMBOLS
+# endif
+
+# ifndef NULL
+# define NULL ( (void *) 0 )
+# endif
+#endif
+
+# ifndef ENODEV
+# include
+# endif
+#endif
diff --git a/i2c/old-code/algo-pcf.c b/i2c/old-code/algo-pcf.c
new file mode 100644
index 00000000..a8e36236
--- /dev/null
+++ b/i2c/old-code/algo-pcf.c
@@ -0,0 +1,291 @@
+/* ------------------------------------------------------------------------- */
+/* adap-bit.c i2c driver algorithms for bit-shift adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-97 Simon G. Vogl
+
+ 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. */
+/* ------------------------------------------------------------------------- */
+static char alg_rcsid[] = "$Id: algo-pcf.c,v 1.1 1998/09/05 18:20:09 i2c Exp $";
+
+#include
+#include
+#include
+#include
+#include
+
+
+#if LINUX_VERSION_CODE >= 0x020100
+
+# include
+#else
+# include
+#endif
+
+
+#include
+#include
+#include
+
+#include "i2c.h"
+#include "algo-pcf.h"
+
+/* ----- global defines ---------------------------------------------------- */
+#define DEB(x) /* should be reasonable open, close &c. */
+#define DEB2(x) /* low level debugging - very slow */
+#define DEBE(x) /* error messages */
+#define DEBI(x) /* ioctl and its arguments */
+#define DEBACK(x) x /* ack failed message */
+#define DEBSTAT(x) /* print several statistical values */
+
+#define DEBPROTO(x) /* debug the protocol by showing transferred bytes*/
+
+
+/* ----- global variables --------------------------------------------- */
+
+/* module parameters:
+ */
+static int test=0; /* see if the line-setting functions work */
+static int scan=0; /* have a look at what's hanging 'round */
+
+/*
+ * This array contains the hw-specific functions for
+ * each port (hardware) type.
+ */
+static struct pcf_adapter *pcf_adaps[PCF_ADAP_MAX];
+static int adap_count;
+static struct i2c_adapter *i2c_adaps[PCF_ADAP_MAX];
+
+/* --- setting states on the bus with the right timing: --------------- */
+
+/*
+ * Sanity check for the adapter hardware - check the reaction of
+ * the bus lines only if it seems to be idle.
+ */
+static int test_bus(struct pcf_adapter *adap)
+{
+}
+
+/* ----- Utility functions
+ */
+
+
+/* send a message to a client.
+ */
+static int pcf_send(struct i2c_client *client,const char *buf, int count)
+{
+ struct i2c_adapter *adapter=client->adapter;
+ struct pcf_adapter *adap=(struct pcf_adapter*)adapter->data;
+ int ret,i;
+
+ DEB2(printk(" i2c_write: wrote %d bytes.\n",wrcount));
+ return wrcount;
+}
+
+
+static int pcf_recv(struct i2c_client *client,char *buf,int count)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct pcf_adapter *adap = (struct pcf_adapter*)adapter->data;
+ unsigned int flags = client->flags;
+ char addr;
+ int ret=0,i,rdcount;
+
+ DEB(printk("i2c(bit): i2c_read: %d byte(s) read.\n", rdcount ));
+ return rdcount;
+}
+
+
+/*
+ * alpha version of combined transmit
+ */
+static int pcf_comb(struct i2c_client *client, char *readbuf,const char *writebuf,
+ int nread, int nwrite, int dir)
+{
+ /* struct i2c_adapter *adapter = client->adapter;
+ struct pcf_adapter *adap = (struct pcf_adapter*)adapter->data;
+ unsigned int flags = client->flags;
+ char addr;
+ int ret=0,i,rdcount=0,wrcount=0;
+
+
+ DEB(printk("i2c(bit): i2c_read: %d byte(s) read.\n", rdcount ));
+ return wrcount+rdcount;
+ */
+ return 0;
+}
+
+
+static int algo_control(struct i2c_adapter *adapter,
+ unsigned int cmd, unsigned long arg)
+{
+ return 0;
+}
+
+static int client_register(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct pcf_adapter *adap = (struct pcf_adapter*)adapter->data;
+
+ if (adap->client_register != NULL)
+ return adap->client_register(client);
+ return 0;
+}
+
+int client_unregister(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct pcf_adapter *adap = (struct pcf_adapter*)adapter->data;
+
+ if (adap->client_unregister != NULL)
+ return adap->client_unregister(client);
+ return 0;
+}
+
+/* -----exported algorithm data: ------------------------------------- */
+
+struct i2c_algorithm pcf_algo = {
+ "PCF 8584 algorithm",
+ ALGO_BIT,
+ pcf_send, /* master_xmit */
+ pcf_recv, /* master_recv */
+ pcf_comb, /* master_comb */
+ NULL, /* slave_xmit */
+ NULL, /* slave_recv */
+ algo_control, /* ioctl */
+ client_register,
+ client_unregister,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_pcf_add_bus(struct pcf_adapter *adap)
+{
+ int i,ack;
+ struct i2c_adapter *i2c_adap;
+
+ for (i = 0; i < PCF_ADAP_MAX; i++)
+ if (NULL == pcf_adaps[i])
+ break;
+ if (PCF_ADAP_MAX == i)
+ return -ENOMEM;
+
+ if (test) {
+ int ret = test_bus(adap);
+ if (ret<0)
+ return -ENODEV;
+ }
+ i2c_adap = kmalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (i2c_adap == NULL)
+ return -ENOMEM;
+
+ pcf_adaps[i] = adap;
+ adap_count++;
+ DEB(printk("i2c(bit): algorithm %s registered.\n",adap->name));
+
+ /* register new adapter to i2c module... */
+
+ memset(i2c_adap,0,sizeof(struct i2c_adapter));
+ strcpy(i2c_adap->name,adap->name);
+ i2c_adap->id = pcf_algo.id | adap->id;
+ i2c_adap->algo = &pcf_algo;
+ i2c_adap->data = adap;
+ i2c_adap->timeout = 100; /* default values, should */
+ i2c_adap->retries = 3; /* be replaced by defines */
+ i2c_adaps[i] = i2c_adap;
+ i2c_add_adapter(i2c_adap);
+
+ /* scan bus */
+ if (scan) {
+#if 0
+ printk(KERN_INFO "i2c(bit): scanning bus %s.\n", adap->name);
+ for (i = 0x00; i < 0xff; i+=2) {
+ i2c_start(adap);
+ ack = i2c_outb(adap,i);
+ i2c_stop(adap);
+ if (ack>0) {
+ printk(KERN_INFO
+ "i2c(bit): found chip at addr=0x%2x\n",i>>1);
+ }
+ }
+#endif
+ }
+ return 0;
+}
+
+
+int i2c_pcf_del_bus(struct pcf_adapter *adap)
+{
+ int i;
+
+ for (i = 0; i < PCF_ADAP_MAX; i++)
+ if ( adap == pcf_adaps[i])
+ break;
+ if ( PCF_ADAP_MAX == i) {
+ printk(KERN_WARNING "i2c(bit): could not unregister bus: %s\n",
+ adap->name);
+ return -ENODEV;
+ }
+
+ pcf_adaps[i] = NULL;
+ i2c_del_adapter(i2c_adaps[i]);
+ kfree(i2c_adaps[i]);
+ i2c_adaps[i] = NULL;
+ adap_count--;
+ DEB(printk("i2c(bit): adapter unregistered: %s\n",adap->name));
+
+ return 0;
+}
+
+int algo_pcf_init (void)
+{
+ int i;
+
+ for (i=0;i
+#include
+#include
+#include
+#include
+#include
+
+
+#include "i2c.h"
+#include "algo-bit.h"
+
+
+#define BIT_LP_MAX 3 /* max. number of addresses to probe */
+
+struct bit_lp_data {
+ unsigned int base; /* base address */
+};
+
+static struct bit_lp_data bit_lp_adaps[BIT_LP_MAX] = {
+ {0,},
+ {0,},
+ {0,},
+ };
+static int adap_count=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 */
+
+/* ----- printer port defines ------------------------------------------*/
+ /* Pin Port Inverted name */
+#define I2C_ON 0x20 /* 12 status N paper */
+ /* ... only for phil. not used */
+#define I2C_SDA 0x80 /* 9 data N data7 */
+#define I2C_SCL 0x08 /* 17 ctrl N dsel */
+
+#define I2C_SDAIN 0x80 /* 11 stat Y busy */
+#define I2C_SCLIN 0x08 /* 15 stat Y enable */
+
+#define I2C_DMASK 0x7f
+#define I2C_CMASK 0xf7
+
+/* --- Convenience defines for the parallel port: */
+#define BASE bit_lp_adaps[minor].base
+#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_lp_setscl(int minor, int state)
+{
+ if (state) {
+ outb(I2C_SCL, CTRL);
+ } else {
+ outb(I2C_CMASK, CTRL);
+ }
+}
+
+static void bit_lp_setsda(int minor, int state)
+{
+ if (state) {
+ outb(I2C_DMASK , DATA);
+ } else {
+ outb(I2C_SDA , DATA);
+ }
+}
+
+static int bit_lp_getscl(int minor)
+{
+ return ( 0 != ( (inb(STAT)) & I2C_SCLIN ) );
+}
+
+static int bit_lp_getsda(int minor)
+{
+ return ( 0 != ( (inb(STAT)) & I2C_SDAIN ) );
+}
+
+static int bit_lp_init(int minor)
+{
+ if (check_region(bit_lp_adaps[minor].base,
+ (bit_lp_adaps[minor].base == 0x3bc)? 3 : 8) < 0 ) {
+ return -ENODEV;
+ } else {
+ request_region(bit_lp_adaps[minor].base,
+ (bit_lp_adaps[minor].base == 0x3bc)? 3 : 8,
+ "i2c (parallel port adapter)");
+ bit_lp_setsda(minor,1);
+ bit_lp_setscl(minor,1);
+ }
+ printk("i2c%d: scl: %d sda %d \n",minor,bit_lp_getscl(minor),bit_lp_getsda(minor));
+ return 0;
+}
+
+static void bit_lp_exit(int minor)
+{
+ release_region( bit_lp_adaps[minor].base ,
+ (bit_lp_adaps[minor].base == 0x3bc)? 3 : 8 );
+ release_region( bit_lp_adaps[minor].base + 0x0400, 8 );
+}
+
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+struct bit_adapter bit_lp_ops = {
+ "Philips Parallel port adapter",
+ bit_lp_setscl,
+ bit_lp_setsda,
+ bit_lp_getscl,
+ bit_lp_getsda,
+ bit_lp_init,
+ bit_lp_exit
+};
+
+#ifdef MODULE
+static int base[BIT_LP_MAX+1] = { [0 ... BIT_LP_MAX] = 0 };
+MODULE_PARM(base, "1-" __MODULE_STRING(BIT_LP_MAX) "i");
+
+/*
+EXPORT_SYMBOL(i2c_bit_add_bus);
+EXPORT_SYMBOL(i2c_bit_del_bus);
+*/
+int init_module(void)
+{
+ /* Work out how many ports we have, then get parport_share to parse
+ the irq values. */
+ unsigned int i;
+ for (i = 0; i < BIT_LP_MAX && base[i]; i++) {
+ bit_lp_adaps[adap_count].base = base[i];
+ if (bit_lp_init(adap_count)==0) {
+/* i2c_bit_add_bus(struct bit_adapter *algo);*/
+/* bit_add_adapter();*/
+ adap_count++;
+ }
+ }
+ if (i==0) { /* no values specified -> probe */
+ }
+
+/* count += probe_one_port(0x3bc, irq[0], dma[0]);
+ count += probe_one_port(0x378, irq[0], dma[0]);
+ count += probe_one_port(0x278, irq[0], dma[0]);
+*/
+ printk("bit_lp: found %d devices.\n",adap_count);
+
+ if (adap_count==0)
+ return -ENODEV;
+ else
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ int i;
+ for (i=0;i
+#include
+#include
+#include
+#include
+
+#include "i2c.h"
+#include "i2c-priv.h"
+
+/* ----- 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 DEBHW(x) x /* lowest level hardware debug -- log changes of*/
+ /* the bit lines... */
+
+#define basePort(port) (i2c_table[minor].base+(port))
+
+/* ----- local functions ---------------------------------------------- */
+
+#if (PCFADAPS) > 1
+# define Local static
+#else
+# define Local inline
+#endif
+
+
+
+Local int pcf_read (int minor, int adr)
+{
+ int ret;
+ udelay(10); /* Give the card some time */
+ ret = inb(basePort( (adr!=0) ));/* force max. increment of 1 */
+ return ret;
+}
+
+
+Local void pcf_write (int minor, int adr,char data)
+{
+ udelay(10); /* Give the card some time */
+ outb(data,basePort( (adr!=0) ));
+}
+
+
+Local int pcf_init (int minor)
+{
+ if (check_region(i2c_table[minor].base, 4) < 0 ) {
+ return -ENODEV;
+ } else {
+ request_region(i2c_table[minor].base, 4, "i2c (Elektor)");
+ }
+ return 0;
+}
+
+
+Local void pcf_exit (int minor)
+{
+ release_region( i2c_table[minor].base, 4 );
+}
+
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+#if (PCFADAPS) > 1
+struct i2c_pcf_ops pcf_lp_ops = {
+ pcf_read,
+ pcf_write,
+ pcf_init,
+ pcf_exit
+};
+#endif
diff --git a/i2c/old-code/pcf-isa.c b/i2c/old-code/pcf-isa.c
new file mode 100644
index 00000000..c1292541
--- /dev/null
+++ b/i2c/old-code/pcf-isa.c
@@ -0,0 +1,110 @@
+/* ------------------------------------------------------------------------- */
+/* pcf-isa.c i2c-hw access for PCF 8584 on ISA boards */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-96 Simon G. Vogl
+
+ 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. */
+/* ------------------------------------------------------------------------- */
+static char rcsid[] = "$Id: pcf-isa.c,v 1.1 1998/09/05 18:20:09 i2c Exp $";
+/*
+ * $Log: pcf-isa.c,v $
+ * Revision 1.1 1998/09/05 18:20:09 i2c
+ * Initial revision
+ *
+ * Revision 1.3 1998/01/20 10:01:29 i2c
+ * *** empty log message ***
+ *
+ * Revision 1.2 1996/11/20 20:20:46 i2c
+ * first version for ISA bus.
+ *
+ * Revision 1.1 1996/11/17 11:00:03 i2c
+ * Initial revision
+ *
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "i2c.h"
+#include "i2c-priv.h"
+
+/* ----- 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 */
+
+/* ----- local functions --------------------------------------------------- */
+
+#if (PCFADAPS) > 1
+# define Local static
+#else
+# define Local inline
+#endif
+
+
+Local int pcf_read (int minor, int adr)
+{
+ if (adr)
+ return inb(BASE + 1); /* read status port */
+ else
+ return inb(BASE); /* read data port */
+}
+
+
+Local void pcf_write (int minor, int adr,char data)
+{
+ if (adr)
+ outb(data, BASE + 1);
+ else
+ outb(data, BASE);
+}
+
+
+Local int pcf_init (int minor)
+{
+ if (check_region(i2c_table[minor].base, 2) < 0 ) {
+ DEBE(printk("i2c_init: Port %#x already in use.\n",
+ i2c_table[minor].base));
+ return -ENODEV;
+ } else {
+ request_region(i2c_table[minor].base, 2,
+ "i2c (ISA bus)");
+ }
+ return 0;
+}
+
+
+Local void pcf_exit (int minor)
+{
+ release_region( i2c_table[minor].base , 2 );
+}
+
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+#if (PCFADAPS) > 1
+struct i2c_pcf_ops pcf_isa_ops = {
+ pcf_read,
+ pcf_write,
+ pcf_init,
+ pcf_exit
+};
+#endif
\ No newline at end of file
diff --git a/i2c/old-code/pcf-lp.c b/i2c/old-code/pcf-lp.c
new file mode 100644
index 00000000..cbe80875
--- /dev/null
+++ b/i2c/old-code/pcf-lp.c
@@ -0,0 +1,228 @@
+/* ------------------------------------------------------------------------- */
+/* pcf-lp.c i2c-hw access for PCF 8584 on bidir. parallel ports */
+/* ------------------------------------------------------------------------- */
+/*
+-----.-.---....------..-.-.---.... Oh bugger! Hope it works this time......
+
+ Copyright (C) 1995-97 Simon G. Vogl
+
+ 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. */
+/* ------------------------------------------------------------------------- */
+static char rcsid[] = "$Id: pcf-lp.c,v 1.1 1998/09/05 18:20:09 i2c Exp $";
+/*
+ * $Log: pcf-lp.c,v $
+ * Revision 1.1 1998/09/05 18:20:09 i2c
+ * Initial revision
+ *
+ * Revision 1.4 1998/01/20 10:01:29 i2c
+ * *** empty log message ***
+ *
+ * Revision 1.3 1997/06/15 14:21:37 i2c
+ * removed debugging messages
+ *
+ * Revision 1.2 1997/06/03 06:00:10 i2c
+ * first version that works
+ *
+ * Revision 1.2 1996/11/20 20:20:46 i2c
+ * first version for ISA bus.
+ *
+ * Revision 1.1 1996/11/17 11:00:03 i2c
+ * Initial revision
+ *
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "i2c.h"
+#include "i2c-priv.h"
+
+/* ----- 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 DEBHW(x) x /* lowest level hardware debug -- log changes of*/
+ /* the bit lines... */
+
+#define lpPort(port) (i2c_table[minor].base+(port))
+
+
+/* ----- local variables ---------------------------------------------- */
+
+static unsigned char ctrl; /* remember line states */
+
+ /* (re)set line states */
+#define Strobe(arg) if (!arg) ctrl|= 0x01; else ctrl &=!0x01;\
+ outb_p(ctrl,lpPort(2)) /* Strobe -- pin 1 */
+#define AutoLF(arg) if (!arg) ctrl|= 0x02; else ctrl &=!0x02;\
+ outb_p(ctrl,lpPort(2)) /* AutoLF -- pin 14 */
+#define Init(arg) if ( arg) ctrl|= 0x04; else ctrl &=!0x04;\
+ outb(ctrl,lpPort(2)) /* Init -- pin 16 */
+#define Select(arg) if (!arg) ctrl|= 0x08; else ctrl &=!0x08;\
+ outb_p(ctrl,lpPort(2)) /* Sel. in - pin 17 */
+ /* 0x10 -- Int Enable */
+#define ReadBit(arg) if(arg) ctrl|= 0x20; else ctrl &=!0x20;\
+ outb_p(ctrl,lpPort(2)) /* direction bit */
+
+#define inStr() (! (0x01 & inb(lpPort(2)) ) ) /* Strobe -- pin 1 */
+#define inALF() (! (0x02 & inb(lpPort(2)) ) ) /* AutoLF -- pin 14 */
+#define inIni() ( (0x04 & inb(lpPort(2)) ) ) /* Init -- pin 16 */
+#define inSel() (! (0x08 & inb(lpPort(2)) ) ) /* Sel. in - pin 17 */
+ /* 0x10 -- Int Enable */
+/*
+#define Argl() printk("(wr-%d cs-%d a0-%d (%#2x, %#2x))\n", \
+ inStr(),inALF(),inIni(),inb(lpPort(0)),inb(lpPort(1)) )
+*/
+#define Argl() /**/
+
+#define wr(arg) Strobe(arg); Argl() /* write line */
+#define cs(arg) AutoLF(arg); Argl() /* chip select */
+#define a0(arg) Init (arg); Argl() /* address line */
+
+/* ----- local functions ---------------------------------------------- */
+/*
+#if (PCFADAPS) > 1
+# define Local static
+#else
+# define Local inline
+#endif
+*/
+#define Local /**/
+
+/* --------- okay, I borrowed it. Stays here for debugging.
+ * check the epp status. After a EPP transfer, it should be true that
+ * 1) the TIMEOUT bit (SPP_STR.0) is clear
+ * 2) the READY bit (SPP_STR.7) is set
+ * returns 1 if okay
+ */
+static int ex_ppa_check_epp_status(int minor)
+{
+ char r;
+ inb(STAT);
+ r = inb(STAT);
+
+ if (r & 1) {
+ outb(r, STAT);
+ outb(r&0xfe, STAT);
+ printk("timed out on port 0x%04x\n", BASE);
+ return 0;
+ }
+ if (!(r & 0x80)) {
+ return 0;
+ }
+ return 1;
+}
+
+
+Local int pcf_read (int minor, int adr)
+{
+ int ret;
+ a0(adr);
+ ex_ppa_check_epp_status(minor);
+ ret = inb(lpPort(4));
+ return ret;
+}
+
+
+Local void pcf_write (int minor, int adr,char data)
+{
+ a0(adr);
+ ex_ppa_check_epp_status(minor);
+ outb(data,lpPort(4));
+}
+
+
+Local int pcf_init (int minor)
+{
+ char ctrl,ecr; /* parallel port registers */
+
+ if (check_region(i2c_table[minor].base, 8) < 0 ) {
+ return -ENODEV;
+ } else {
+ request_region(i2c_table[minor].base, 8, "i2c (pcf-lp)");
+ }
+
+ /* This is the standard detection algorithm for ECP ports */
+ /* now detect, what kind of parallel port we have: */
+ ecr = inb(i2c_table[minor].base+0x402);
+ ctrl= inb(i2c_table[minor].base+0x002);
+ if (ecr!=ctrl) { /* Okay, we seem to have an extended port :) */
+ if (check_region(i2c_table[minor].base + 0x400, 8) < 0 ) {
+ DEBE(printk( "i2c_init, port %#x: ext. ports already in use "
+ "using only standard driver.\n",
+ i2c_table[minor].base));
+ return -ENODEV;
+ } else {
+ if ( (ecr & 0x03) != 0x01 ) { /* FIFO empty? */
+ printk("FIFO not empty\n");
+ return -ENODEV;
+ }
+
+ outb(0x34,i2c_table[minor].base+0x402);
+ if (inb(i2c_table[minor].base+0x402) != 0x35 ){ /* bits 0,1 readonly */
+ printk("bits 0,1 not rd/only");
+ return -ENODEV;
+ }
+ /* Okay, now we should have an ECP-capable printer port */
+ printk("i2c%d: ECP parallel port.\n",minor);
+ request_region(i2c_table[minor].base+0x0400, 3 ,
+ "i2c (Extended Parallel port adapter)");
+ outb(0x94 ,lpPort(0x402)); /* EPP mode */
+ ctrl = inb(CTRL);
+
+ if (i2c_table[minor].irq > 0){ /* enable int. */
+ outb(inb(lpPort(0x402)|0x10), lpPort(0x402));
+ outb(ctrl|0x10,CTRL);
+ }
+
+ ex_ppa_check_epp_status(minor);
+ printk("status reads %2x\n",pcf_read(minor,1));
+ ex_ppa_check_epp_status(minor);
+ printk("data reads %2x\n",pcf_read(minor,0));
+ }
+ } else {
+ printk("i2c%d: Need EPP port. Sorry.\n",minor);
+ return -ENODEV;
+ }
+ /* Okay, now it's time to init my data structures */
+
+ return 0;
+}
+
+
+Local void pcf_exit (int minor)
+{
+ release_region( i2c_table[minor].base, 8 );
+ release_region( i2c_table[minor].base + 0x0400, 3 );
+}
+
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+#if (PCFADAPS) > 1
+struct i2c_pcf_ops pcf_lp_ops = {
+ pcf_read,
+ pcf_write,
+ pcf_init,
+ pcf_exit
+};
+#endif
diff --git a/i2c/old-code/pcf8584.h b/i2c/old-code/pcf8584.h
new file mode 100644
index 00000000..b3db0403
--- /dev/null
+++ b/i2c/old-code/pcf8584.h
@@ -0,0 +1,72 @@
+/* -------------------------------------------------------------------- */
+/* PCF 8584 global defines */
+/* -------------------------------------------------------------------- */
+/* Copyright (C) 19996 Simon G. Vogl
+
+ 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. */
+/* -------------------------------------------------------------------- */
+/* $Id: pcf8584.h,v 1.1 1998/07/29 08:09:51 i2c Exp $
+ * $Log: pcf8584.h,v $
+ * Revision 1.1 1998/07/29 08:09:51 i2c
+ * Initial revision
+ *
+ */
+
+
+/* ----- Control register bits ---------------------------------------- */
+#define PCF_PIN 0x80
+#define PCF_ESO 0x40
+#define PCF_ES1 0x20
+#define PCF_ES2 0x10
+#define PCF_ENI 0x08
+#define PCF_STA 0x04
+#define PCF_STO 0x02
+#define PCF_ACK 0x01
+
+/* ----- Status register bits ----------------------------------------- */
+/*#define PCF_PIN 0x80 as above*/
+
+#define PCF_INI 0x40 /* 1 if not initialized */
+#define PCF_STS 0x20
+#define PCF_BER 0x10
+#define PCF_AD0 0x08
+#define PCF_LRB 0x08
+#define PCF_AAS 0x04
+#define PCF_LAB 0x02
+#define PCF_BB 0x01
+
+/* ----- Chip clock frequencies --------------------------------------- */
+#define PCF_CLK3 0x00
+#define PCF_CLK443 0x10
+#define PCF_CLK6 0x14
+#define PCF_CLK8 0x18
+#define PCF_CLK12 0x1c
+
+/* ----- transmission frequencies ------------------------------------- */
+#define PCF_TRNS90 0x00 /* 90 kHz */
+#define PCF_TRNS45 0x01 /* 45 kHz */
+#define PCF_TRNS11 0x02 /* 11 kHz */
+#define PCF_TRNS15 0x03 /* 1.5 kHz */
+
+
+/* ----- Access to internal registers according to ES1,ES2 ------------ */
+/* they are mapped to the data port ( a0 = 0 ) */
+/* available when ESO == 0 : */
+
+#define PCF_OWNADR 0
+#define PCF_INTREG PCF_ES2
+#define PCF_CLKREG PCF_ES1
+
+