2
0
mirror of https://github.com/lm-sensors/lm-sensors synced 2025-08-31 14:25:39 +00:00

The basic directory structure for lmsensors2.

README.directories contains a description of the directories I created;
  read it if you have questions about them.
doc/design is the design document I sent before through email.
doc/useful_addresses.html contains links to I2C, SMBus and sensors
  information.

Note that we may have to change minor i2c things, like Makefiles; this
is why I put it in the archive too (we should, of course, send important
changes to Simon Vogl).


git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@3 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
Frodo Looijaard
1998-11-02 20:29:28 +00:00
parent 8e82d8354a
commit 11e88380d5
32 changed files with 5012 additions and 0 deletions

14
README.directories Normal file
View File

@@ -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.

BIN
archive/mod-19981006.tar.gz Normal file

Binary file not shown.

497
doc/design Normal file
View File

@@ -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 */
}

60
doc/useful_addresses.html Normal file
View File

@@ -0,0 +1,60 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
<TITLE>I&#178C, SMBus and hardware monitoring references</TITLE>
</HEAD>
<BODY>
<H1>I&#178C, SMBus and hardware monitoring references</H1>
This document contains all kinds of useful references to I&#178C and SMBus
documents and implementations, and to hardware sensors documentation and
implementations. Please report any other references you have found!
<UL>
<LI>I&#178C
<UL>
<LI>
<A HREF="http://www.geocities.com/SiliconValley/9504/mic_b000.htm">General
overview</A>
<LI>
<A HREF="http://kar10.kar.elf.stuba.sk/~balogh/MM/i2c/i2cindex.htm">I&#178C
FAQ</A>
<LI>
<A HREF="http://ftp.philipsmcu.com">Philips, the I&#178C developers</A>
<BR>This site contains many example programs</BR>
<LI>
<A HREF="http://www.tk.uni-linz.ac.at/~simon/private/i2c/v4l">Simon Vogl's
I&#178C Linux kernel module</A>
</UL>
<LI>SMBus
<UL>
<LI><A HREF="http://www.sbs-forum.org/specs/index.html">SMBus specification
documents</A>
</UL>
<LI>Hardware monitoring chips
<UL>
<LI><A HREF="http://www.national.com">National Semiconductors</A>
<BR>LM75/78/79/80 reference sheets
<LI><A HREF="http://www.winbond.com.tw">Winbond</A>
<BR>W83781D reference sheet
</UL>
<LI>Hardware monitoring implementations
<UL>
<LI><A HREF="http://www.netroedge.com/~lm78">The official lm_sensors
homepage</A>
<LI><A HREF="http://www.lysator.liu.se/~alla/files/lm78_stuff/">Alexander
Larsson's lm78 module</A>
<BR>This is the original module lm_sensors is based upon
<LI><A HREF="http://www.tu-chemnitz.de/~ronsc/tree/2_Projects/0_c++/lm78/index.html">Ronald Schmidt's lm78 module</A>
<LI><A HREF="ftp://ftp.vu.union.edu/pub/users/hagopiar/">Beowulf project lm78
module</A>
<BR>Written by Erik Hendriks
<LI><A HREF="http://pweb.uunet.de/ganzfix.duew/">txwd, another lm78 module</A>
<LI><A HREF="http://stimpy.netroedge.com/intranet/tellerstats/">A web-based
hardware monitor</A>
<BR>This is created by Phil Edelbrock, one of our main project contributors
<LI><A HREF="http://users.ox.ac.uk/~kebl0850/wmlm78/">wmlm78 homepage</A>
wmlm78 is a graphical extension of lm_sensors, which can be docked in Window
Manager.
</UL>
</UL>
</BODY>
</HTML>

40
i2c/Makefile Normal file
View File

@@ -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

22
i2c/README Normal file
View File

@@ -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

36
i2c/README.bitmb Normal file
View File

@@ -0,0 +1,36 @@
README for bit-mb.c and hw-monitor.c
September 23, 1998. Ky<4B>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<4B>sti M<>lkki kmalkki@cc.hut.fi

665
i2c/algo-bit.c Normal file
View File

@@ -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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/malloc.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= 0x020100
# include <asm/uaccess.h>
#else
# include <asm/segment.h>
#endif
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/sched.h>
#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;i<retries;i++) {
ret = i2c_outb(adap,addr);
if (ret==1)
break; /* success! */
i2c_stop(adap);
udelay(5/*adap->udelay*/);
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;i<num;i++) {
pmsg = &msgs[i];
ret = bit_doAddress(adap,pmsg,adapter->retries);
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 (i<num-1) {
i2c_repstart(adap);
}
}
i2c_stop(adap);
return num;
}
int algo_control(struct i2c_adapter *adapter,
unsigned int cmd, unsigned long arg)
{
return 0;
}
int client_register(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
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<BIT_ADAP_MAX;i++) {
bit_adaps[i]=NULL;
}
adap_count=0;
i2c_add_algorithm(&bit_algo);
return 0;
}
#ifdef MODULE
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
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

38
i2c/algo-bit.h Normal file
View File

@@ -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 */

146
i2c/bit-elv.c Normal file
View File

@@ -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 <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/errno.h>
#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

188
i2c/bit-lp.c Normal file
View File

@@ -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 <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <asm/io.h>
#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 <simon@tk.uni-linz.ac.at>");
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

163
i2c/bit-mb.c Normal file
View File

@@ -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<4B>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 <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <asm/io.h>
#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 <kmalkki@cc.hut.fi>");
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

195
i2c/bit-velle.c Normal file
View File

@@ -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 <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/string.h> /* for 2.0 kernels to get NULL */
#include <asm/errno.h> /* for 2.0 kernels to get ENODEV */
#include <asm/io.h>
#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 <simon@tk.uni-linz.ac.at>");
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

32
i2c/detect/Makefile Normal file
View File

@@ -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

68
i2c/detect/detect.c Normal file
View File

@@ -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 <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <linux/delay.h>
#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);
}

23
i2c/drivers/Makefile Normal file
View File

@@ -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

172
i2c/drivers/eeprom.c Normal file
View File

@@ -0,0 +1,172 @@
/* experimental eeprom driver
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
#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;i<EEPROM_TO;i++) {
/* we misuse the template as a "generic" eeprom client...*/
eepromTmpl.addr = i;
ret = i2c_master_send(&eepromTmpl,(unsigned char*)&c,1);
if (ret!=1) {
/* no device at this address. */
/* printk("eeprom: failed for %x (%d)\n",i,ret);*/
continue;
}
printk("eeprom: success with %x\n",i);
if (test) {
msgs[0].addr = i;
msgs[1].addr = i;
ret = i2c_transfer(adap, msgs, 2);
if (ret != 2 ) {
printk("eeprom: test read error with %d!\n",
i);
} else {
int j;
for (j=0;j<256;j+=8)
printk("%2d: %#02x %#02x %#02x %#02x - %#02x %#02x %#02x %#02x \n",
j,buf[j+0],buf[j+1],buf[j+2],buf[j+3],
buf[j+4],buf[j+5],buf[j+6],buf[j+7]);
}
}
eeprom = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (eeprom == NULL)
return 0;
memcpy(eeprom, &eepromTmpl, sizeof(struct i2c_client));
i2c_attach_client(eeprom);
}
return 0;
}
int eeprom_detach(struct i2c_client *client)
{
printk("wnv-eeprom: Client %s wants to detach\n",client->name);
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;i<sizeof(struct EEPROM); i++) {
d+=((char *)(&dev->eeprom))[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*/

41
i2c/eeprom/Makefile Normal file
View File

@@ -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

4
i2c/eeprom/README Normal file
View File

@@ -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.

16
i2c/eeprom/a Normal file
View File

@@ -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

16
i2c/eeprom/b Normal file
View File

@@ -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

187
i2c/eeprom/eeprom.c Normal file
View File

@@ -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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#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);
}

182
i2c/hw-monitor.c Normal file
View File

@@ -0,0 +1,182 @@
/*
EISCA Fan SMBus (or i2c) driver
Based on various char-device sources.
Copyright (c) 1998 Ky<4B>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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/proc_fs.h>
#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 <kmalkki@cc.hut.fi>");
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

467
i2c/i2c-core.c Normal file
View File

@@ -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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#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;i<I2C_DRIVER_MAX;i++)
if (drivers[i]!=NULL && drivers[i]->flags&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;j<I2C_CLIENT_MAX;j++) {
struct i2c_client *client = adap->clients[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;i<I2C_ADAP_MAX;i++)
if (adapters[i]!=NULL)
driver->attach_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;k<I2C_ADAP_MAX;k++) {
struct i2c_adapter *adap = adapters[k];
if (adap == NULL) /* skip empty entries. */
continue;
DEB2(printk("i2c: examining adapter %s:\n",adap->name));
for (j=0;j<I2C_CLIENT_MAX;j++) {
struct i2c_client *client = adap->clients[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 <simon@tk.uni-linz.ac.at>");
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

364
i2c/i2c-dev.c Normal file
View File

@@ -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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#if LINUX_VERSION_CODE >= 0x020100
# include <asm/uaccess.h>
#else
# include <asm/segment.h>
#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 <simon@tk.uni-linz.ac.at>");
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

371
i2c/i2c.h Normal file
View File

@@ -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 <asm/spinlock.h> /* for spinlock_t */
#else
#include <asm/semaphore.h>
#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 <asm/errno.h>
# endif
#endif

291
i2c/old-code/algo-pcf.c Normal file
View File

@@ -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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/malloc.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= 0x020100
# include <asm/uaccess.h>
#else
# include <asm/segment.h>
#endif
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/sched.h>
#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<PCF_ADAP_MAX;i++) {
pcf_adaps[i]=NULL;
}
adap_count=0;
i2c_add_algorithm(&pcf_algo);
return 0;
}
#ifdef MODULE
MODULE_PARM(test, "i");
MODULE_PARM(scan, "i");
EXPORT_SYMBOL(i2c_pcf_add_bus);
EXPORT_SYMBOL(i2c_pcf_del_bus);
int init_module(void)
{
return algo_pcf_init();
}
void cleanup_module(void)
{
i2c_del_algorithm(&pcf_algo);
}
#endif

189
i2c/old-code/bit-lp-multi.c Normal file
View File

@@ -0,0 +1,189 @@
/* ------------------------------------------------------------------------- */
/* 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-multi.c,v 1.1 1998/09/05 18:20:09 i2c Exp $";
/* ------------------------------------------------------------------------- */
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <asm/io.h>
#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<adap_count;i++) {
int i2c_bit_del_bus(struct bit_adapter *algo);
bit_lp_exit(i);
}
/* i2c_del_algorithm(&alg_bit_opns);*/
}
#endif

115
i2c/old-code/pcf-elektor.c Normal file
View File

@@ -0,0 +1,115 @@
/* ------------------------------------------------------------------------- */
/* pcf-lp.c i2c-hw access for PCF 8584 on bidir. parallel ports */
/* ------------------------------------------------------------------------- */
/*
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-elektor.c,v 1.1 1998/09/05 18:20:09 i2c Exp $";
/*
* $Log: pcf-elektor.c,v $
* Revision 1.1 1998/09/05 18:20:09 i2c
* Initial revision
*
* Revision 1.1 1998/01/20 10:01:29 i2c
* Initial revision
*
* 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 <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/errno.h>
#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

110
i2c/old-code/pcf-isa.c Normal file
View File

@@ -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 <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/errno.h>
#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

228
i2c/old-code/pcf-lp.c Normal file
View File

@@ -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 <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/errno.h>
#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

72
i2c/old-code/pcf8584.h Normal file
View File

@@ -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