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:
14
README.directories
Normal file
14
README.directories
Normal 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
BIN
archive/mod-19981006.tar.gz
Normal file
Binary file not shown.
497
doc/design
Normal file
497
doc/design
Normal 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
60
doc/useful_addresses.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>I²C, SMBus and hardware monitoring references</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<H1>I²C, SMBus and hardware monitoring references</H1>
|
||||
This document contains all kinds of useful references to I²C and SMBus
|
||||
documents and implementations, and to hardware sensors documentation and
|
||||
implementations. Please report any other references you have found!
|
||||
<UL>
|
||||
<LI>I²C
|
||||
<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²C
|
||||
FAQ</A>
|
||||
<LI>
|
||||
<A HREF="http://ftp.philipsmcu.com">Philips, the I²C 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²C 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
40
i2c/Makefile
Normal 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
22
i2c/README
Normal 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
36
i2c/README.bitmb
Normal 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
665
i2c/algo-bit.c
Normal 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
38
i2c/algo-bit.h
Normal 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
146
i2c/bit-elv.c
Normal 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
188
i2c/bit-lp.c
Normal 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
163
i2c/bit-mb.c
Normal 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
195
i2c/bit-velle.c
Normal 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
32
i2c/detect/Makefile
Normal 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
68
i2c/detect/detect.c
Normal 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
23
i2c/drivers/Makefile
Normal 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
172
i2c/drivers/eeprom.c
Normal 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
41
i2c/eeprom/Makefile
Normal 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
4
i2c/eeprom/README
Normal 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
16
i2c/eeprom/a
Normal 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
16
i2c/eeprom/b
Normal 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
187
i2c/eeprom/eeprom.c
Normal 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
182
i2c/hw-monitor.c
Normal 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
467
i2c/i2c-core.c
Normal 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
364
i2c/i2c-dev.c
Normal 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
371
i2c/i2c.h
Normal 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
291
i2c/old-code/algo-pcf.c
Normal 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
189
i2c/old-code/bit-lp-multi.c
Normal 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
115
i2c/old-code/pcf-elektor.c
Normal 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
110
i2c/old-code/pcf-isa.c
Normal 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
228
i2c/old-code/pcf-lp.c
Normal 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
72
i2c/old-code/pcf8584.h
Normal 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
|
||||
|
||||
|
Reference in New Issue
Block a user