patch-2.3.34 linux/drivers/i2c/i2c-core.c
Next file: linux/drivers/i2c/i2c-dev.c
Previous file: linux/drivers/i2c/i2c-algo-pcf.c
Back to the patch index
Back to the overall index
- Lines: 1354
- Date:
Thu Dec 16 13:59:38 1999
- Orig file:
v2.3.33/linux/drivers/i2c/i2c-core.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.33/linux/drivers/i2c/i2c-core.c linux/drivers/i2c/i2c-core.c
@@ -0,0 +1,1353 @@
+/* i2c-core.c - a device driver for the iic-bus interface */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-99 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-core.c,v 1.42 1999/11/30 20:06:42 frodo Exp $"
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
+ All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+#include <linux/config.h>
+
+#include <linux/i2c.h>
+
+/* ----- compatibility stuff ----------------------------------------------- */
+
+/* 2.0.0 kernel compatibility */
+#if LINUX_VERSION_CODE < 0x020100
+#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
+
+#include <linux/version.h>
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c))
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,53)
+#include <linux/init.h>
+#else
+#define __init
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,4))
+#define copy_from_user memcpy_fromfs
+#define copy_to_user memcpy_tofs
+#else
+#include <asm/uaccess.h>
+#endif
+
+/* ----- global defines ---------------------------------------------------- */
+
+/* exclusive access to the bus */
+#define I2C_LOCK(adap) down(&adap->lock)
+#define I2C_UNLOCK(adap) up(&adap->lock)
+
+#define ADAP_LOCK() down(&adap_lock)
+#define ADAP_UNLOCK() up(&adap_lock)
+
+#define DRV_LOCK() down(&driver_lock)
+#define DRV_UNLOCK() up(&driver_lock)
+
+#define DEB(x) if (i2c_debug>=1) x;
+#define DEB2(x) if (i2c_debug>=2) x;
+
+/* ----- global variables -------------------------------------------------- */
+
+/**** lock for writing to global variables: the adapter & driver list */
+struct semaphore adap_lock;
+struct semaphore driver_lock;
+
+/**** adapter list */
+static struct i2c_adapter *adapters[I2C_ADAP_MAX];
+static int adap_count;
+
+/**** drivers list */
+static struct i2c_driver *drivers[I2C_DRIVER_MAX];
+static int driver_count;
+
+/**** debug level */
+static int i2c_debug=1;
+static void i2c_dummy_adapter(struct i2c_adapter *adapter);
+static void i2c_dummy_client(struct i2c_client *client);
+
+/* ---------------------------------------------------
+ * /proc entry declarations
+ *----------------------------------------------------
+ */
+
+/* Note that quite some things changed within the 2.1 kernel series.
+ Some things below are somewhat difficult to read because of this. */
+
+#ifdef CONFIG_PROC_FS
+
+static int i2cproc_init(void);
+static int i2cproc_cleanup(void);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) && \
+ (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))
+static void monitor_bus_i2c(struct inode *inode, int fill);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+
+static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count,
+ loff_t *ppos);
+static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
+ int *eof , void *private);
+
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
+
+static int i2cproc_bus_read(struct inode * inode, struct file * file,
+ char * buf, int count);
+static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
+ int unused);
+
+static struct proc_dir_entry proc_bus_dir =
+ {
+ /* low_ino */ 0, /* Set by proc_register_dynamic */
+ /* namelen */ 3,
+ /* name */ "bus",
+ /* mode */ S_IRUGO | S_IXUGO | S_IFDIR,
+ /* nlink */ 2, /* Corrected by proc_register[_dynamic] */
+ /* uid */ 0,
+ /* gid */ 0,
+ /* size */ 0,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,36))
+ /* ops */ &proc_dir_inode_operations,
+#endif
+ };
+
+static struct proc_dir_entry proc_bus_i2c_dir =
+ {
+ /* low_ino */ 0, /* Set by proc_register_dynamic */
+ /* namelen */ 3,
+ /* name */ "i2c",
+ /* mode */ S_IRUGO | S_IFREG,
+ /* nlink */ 1,
+ /* uid */ 0,
+ /* gid */ 0,
+ /* size */ 0,
+ /* ops */ NULL,
+ /* get_info */ &read_bus_i2c
+ };
+
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+
+/* To implement the dynamic /proc/bus/i2c-? files, we need our own
+ implementation of the read hook */
+static struct file_operations i2cproc_operations = {
+ NULL,
+ i2cproc_bus_read,
+};
+
+static struct inode_operations i2cproc_inode_operations = {
+ &i2cproc_operations
+};
+
+static int i2cproc_initialized = 0;
+
+#else /* undef CONFIG_PROC_FS */
+
+#define i2cproc_init()
+#define i2cproc_cleanup()
+
+#endif /* CONFIG_PROC_FS */
+
+
+/* ---------------------------------------------------
+ * registering functions
+ * ---------------------------------------------------
+ */
+
+/* -----
+ * 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,j;
+
+ ADAP_LOCK();
+ for (i = 0; i < I2C_ADAP_MAX; i++)
+ if (NULL == adapters[i])
+ break;
+ if (I2C_ADAP_MAX == i) {
+ printk(KERN_WARNING
+ " i2c-core.o: register_adapter(%s) - enlarge I2C_ADAP_MAX.\n",
+ adap->name);
+ ADAP_UNLOCK();
+ return -ENOMEM;
+ }
+
+ adapters[i] = adap;
+ adap_count++;
+ ADAP_UNLOCK();
+
+ /* init data types */
+ init_MUTEX(&adap->lock);
+
+ i2c_dummy_adapter(adap); /* actually i2c_dummy->add_adapter */
+#ifdef CONFIG_PROC_FS
+
+ if (i2cproc_initialized) {
+ char name[8];
+ struct proc_dir_entry *proc_entry;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29))
+ int res;
+#endif
+
+ sprintf(name,"i2c-%d", i);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ proc_entry = create_proc_entry(name,0,proc_bus);
+ if (! proc_entry) {
+ printk("i2c-core.o: Could not create /proc/bus/%s\n",
+ name);
+ return -ENOENT;
+ }
+ proc_entry->ops = &i2cproc_inode_operations;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27))
+ proc_entry->owner = THIS_MODULE;
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58))
+ proc_entry->fill_inode = &monitor_bus_i2c;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
+ adap->proc_entry = NULL;
+ if (!(proc_entry = kmalloc(sizeof(struct proc_dir_entry)+
+ strlen(name)+1, GFP_KERNEL))) {
+ printk("i2c-core.o: Out of memory!\n");
+ return -ENOMEM;
+ }
+ memset(proc_entry,0,sizeof(struct proc_dir_entry));
+ proc_entry->namelen = strlen(name);
+ proc_entry->name = (char *) (proc_entry + 1);
+ proc_entry->mode = S_IRUGO | S_IFREG;
+ proc_entry->nlink = 1;
+ proc_entry->ops = &i2cproc_inode_operations;
+
+ /* Nasty stuff to keep GCC satisfied */
+ {
+ char *procname;
+ (const char *) procname = proc_entry->name;
+ strcpy (procname,name);
+ }
+
+ if ((res = proc_register_dynamic(&proc_bus_dir, proc_entry))) {
+ printk("i2c-core.o: Could not create %s.\n",name);
+ kfree(proc_entry);
+ return res;
+ }
+
+ adap->proc_entry = proc_entry;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+
+ adap->inode = proc_entry->low_ino;
+ }
+
+#endif /* def CONFIG_PROC_FS */
+
+ /* inform drivers of new adapters */
+ DRV_LOCK();
+ for (j=0;j<I2C_DRIVER_MAX;j++)
+ if (drivers[j]!=NULL && drivers[j]->flags&I2C_DF_NOTIFY)
+ drivers[j]->attach_adapter(adap);
+ DRV_UNLOCK();
+
+ DEB(printk("i2c-core.o: adapter %s registered as adapter %d.\n",adap->name,i));
+
+ return 0;
+}
+
+
+int i2c_del_adapter(struct i2c_adapter *adap)
+{
+ int i,j;
+ ADAP_LOCK();
+ for (i = 0; i < I2C_ADAP_MAX; i++)
+ if (adap == adapters[i])
+ break;
+ if (I2C_ADAP_MAX == i) {
+ printk( " i2c-core.o: unregister_adapter adap [%s] not found.\n",
+ adap->name);
+ ADAP_UNLOCK();
+ return -ENODEV;
+ }
+
+ i2c_dummy_adapter(adap); /* actually i2c_dummy->del_adapter */
+#ifdef CONFIG_PROC_FS
+ if (i2cproc_initialized) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ char name[8];
+ sprintf(name,"i2c-%d", i);
+ remove_proc_entry(name,proc_bus);
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
+ int res;
+ if (adapters[i]->proc_entry) {
+ if ((res = proc_unregister(&proc_bus_dir,
+ adapters[i]->proc_entry->low_ino))) {
+ printk("i2c-core.o: Deregistration of /proc "
+ "entry failed\n");
+ ADAP_UNLOCK();
+ return res;
+ }
+ kfree(adapters[i]->proc_entry);
+ }
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+ }
+#endif /* def CONFIG_PROC_FS */
+
+ /* 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 & I2C_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.
+ */
+ client->driver->detach_client(client);
+ /* i2c_detach_client(client); --- frodo */
+ }
+ /* all done, now unregister */
+ adapters[i] = NULL;
+ adap_count--;
+
+ ADAP_UNLOCK();
+ DEB(printk("i2c-core.o: 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,j;
+ DRV_LOCK();
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (NULL == drivers[i])
+ break;
+ if (I2C_DRIVER_MAX == i) {
+ printk(KERN_WARNING
+ " i2c-core.o: register_driver(%s) - enlarge I2C_DRIVER_MAX.\n",
+ driver->name);
+ DRV_UNLOCK();
+ return -ENOMEM;
+ }
+
+ drivers[i] = driver;
+ driver_count++;
+
+ DRV_UNLOCK(); /* driver was successfully added */
+
+ DEB(printk("i2c-core.o: driver %s registered.\n",driver->name));
+
+ /* Notify all existing adapters and clients to dummy driver */
+ ADAP_LOCK();
+ if (driver->flags&I2C_DF_DUMMY) {
+ for (i=0; i<I2C_ADAP_MAX; i++) {
+ if (adapters[i]) {
+ driver->attach_adapter(adapters[i]);
+ for (j=0; j<I2C_CLIENT_MAX; j++)
+ if (adapters[i]->clients[j])
+ driver->detach_client(adapters[i]->clients[j]);
+ }
+ }
+ ADAP_UNLOCK();
+ return 0;
+ }
+
+ /* now look for instances of driver on our adapters
+ */
+ if ( driver->flags&I2C_DF_NOTIFY ) {
+ for (i=0;i<I2C_ADAP_MAX;i++)
+ if (adapters[i]!=NULL)
+ driver->attach_adapter(adapters[i]);
+ }
+ ADAP_UNLOCK();
+ return 0;
+}
+
+int i2c_del_driver(struct i2c_driver *driver)
+{
+ int i,j,k;
+
+ DRV_LOCK();
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (driver == drivers[i])
+ break;
+ if (I2C_DRIVER_MAX == i) {
+ printk(KERN_WARNING " i2c-core.o: unregister_driver: [%s] not found\n",
+ driver->name);
+ DRV_UNLOCK();
+ 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-core.o: 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.
+ */
+ ADAP_LOCK(); /* should be moved inside the if statement... */
+ if ((driver->flags&I2C_DF_DUMMY)==0)
+ for (k=0;k<I2C_ADAP_MAX;k++) {
+ struct i2c_adapter *adap = adapters[k];
+ if (adap == NULL) /* skip empty entries. */
+ continue;
+ DEB2(printk("i2c-core.o: 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-core.o: detaching client %s:\n",
+ client->name));
+ /*i2c_detach_client(client);*/
+ driver->detach_client(client);
+ }
+ }
+ }
+ ADAP_UNLOCK();
+ drivers[i] = NULL;
+ driver_count--;
+ DRV_UNLOCK();
+
+ DEB(printk("i2c-core.o: driver unregistered: %s\n",driver->name));
+ return 0;
+}
+
+
+int i2c_attach_client(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ 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-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n",
+ client->name);
+ return -ENOMEM;
+ }
+
+ adapter->clients[i] = client;
+ adapter->client_count++;
+ i2c_dummy_client(client);
+
+ if (adapter->client_register != NULL)
+ adapter->client_register(client);
+ DEB(printk("i2c-core.o: 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;
+ 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-core.o: unregister_client [%s] not found\n",
+ client->name);
+ return -ENODEV;
+ }
+
+ if (adapter->client_unregister != NULL)
+ adapter->client_unregister(client);
+ /* client->driver->detach_client(client);*/
+
+ adapter->clients[i] = NULL;
+ adapter->client_count--;
+ i2c_dummy_client(client);
+
+ DEB(printk("i2c-core.o: client [%s] unregistered.\n",client->name));
+ return 0;
+}
+
+void i2c_inc_use_client(struct i2c_client *client)
+{
+
+ if (client->driver->inc_use != NULL)
+ client->driver->inc_use(client);
+
+ if (client->adapter->inc_use != NULL)
+ client->adapter->inc_use(client->adapter);
+}
+
+void i2c_dec_use_client(struct i2c_client *client)
+{
+
+ if (client->driver->dec_use != NULL)
+ client->driver->dec_use(client);
+
+ if (client->adapter->dec_use != NULL)
+ client->adapter->dec_use(client->adapter);
+}
+
+/* ----------------------------------------------------
+ * The /proc functions
+ * ----------------------------------------------------
+ */
+
+#ifdef CONFIG_PROC_FS
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) && \
+ (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))
+/* Monitor access to /proc/bus/i2c*; make unloading i2c-proc impossible
+ if some process still uses it or some file in it */
+void monitor_bus_i2c(struct inode *inode, int fill)
+{
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+}
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
+
+/* This function generates the output for /proc/bus/i2c */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof,
+ void *private)
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
+int read_bus_i2c(char *buf, char **start, off_t offset, int len, int unused)
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+{
+ int i;
+ int nr = 0;
+ /* Note that it is safe to write a `little' beyond len. Yes, really. */
+ for (i = 0; (i < I2C_ADAP_MAX) && (nr < len); i++)
+ if (adapters[i]) {
+ nr += sprintf(buf+nr, "i2c-%d\t", i);
+ if (adapters[i]->algo->smbus_xfer) {
+ if (adapters[i]->algo->master_xfer)
+ nr += sprintf(buf+nr,"smbus/i2c");
+ else
+ nr += sprintf(buf+nr,"smbus ");
+ } else if (adapters[i]->algo->master_xfer)
+ nr += sprintf(buf+nr,"i2c ");
+ else
+ nr += sprintf(buf+nr,"dummy ");
+ nr += sprintf(buf+nr,"\t%-32s\t%-32s\n",
+ adapters[i]->name,
+ adapters[i]->algo->name);
+ }
+ return nr;
+}
+
+/* This function generates the output for /proc/bus/i2c-? */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count,
+ loff_t *ppos)
+{
+ struct inode * inode = file->f_dentry->d_inode;
+#else (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29))
+int i2cproc_bus_read(struct inode * inode, struct file * file,char * buf,
+ int count)
+{
+#endif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ char *kbuf;
+ struct i2c_client *client;
+ int i,j,len=0;
+
+ if (count < 0)
+ return -EINVAL;
+ if (count > 4000)
+ count = 4000;
+ for (i = 0; i < I2C_ADAP_MAX; i++)
+ if (adapters[i]->inode == inode->i_ino) {
+ /* We need a bit of slack in the kernel buffer; this makes the
+ sprintf safe. */
+ if (! (kbuf = kmalloc(count + 80,GFP_KERNEL)))
+ return -ENOMEM;
+ for (j = 0; j < I2C_CLIENT_MAX; j++)
+ if ((client = adapters[i]->clients[j]))
+ /* Filter out dummy clients */
+ if (client->driver->id != I2C_DRIVERID_I2CDEV)
+ len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n",
+ client->addr,
+ client->name,client->driver->name);
+ if (file->f_pos+len > count)
+ len = count - file->f_pos;
+ len = len - file->f_pos;
+ if (len < 0)
+ len = 0;
+ copy_to_user (buf,kbuf+file->f_pos,len);
+ file->f_pos += len;
+ kfree(kbuf);
+ return len;
+ }
+ return -ENOENT;
+}
+
+int i2cproc_init(void)
+{
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ struct proc_dir_entry *proc_bus_i2c;
+#else
+ int res;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+
+ i2cproc_initialized = 0;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ if (! proc_bus) {
+ printk("i2c-core.o: /proc/bus/ does not exist");
+ i2cproc_cleanup();
+ return -ENOENT;
+ }
+ proc_bus_i2c = create_proc_entry("i2c",0,proc_bus);
+ if (!proc_bus_i2c) {
+ printk("i2c-core.o: Could not create /proc/bus/i2c");
+ i2cproc_cleanup();
+ return -ENOENT;
+ }
+ proc_bus_i2c->read_proc = &read_bus_i2c;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27))
+ proc_bus_i2c->owner = THIS_MODULE;
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58))
+ proc_bus_i2c->fill_inode = &monitor_bus_i2c;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+ i2cproc_initialized += 2;
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
+ /* In Linux 2.0.x, there is no /proc/bus! But I hope no other module
+ introduced it, or we are fucked. And 2.0.35 and earlier does not
+ export proc_dir_inode_operations, so we grab it from proc_net,
+ which also uses it. Not nice. */
+ proc_bus_dir.ops = proc_net.ops;
+ if ((res = proc_register_dynamic(&proc_root, &proc_bus_dir))) {
+ printk("i2c-core.o: Could not create /proc/bus/");
+ i2cproc_cleanup();
+ return res;
+ }
+ i2cproc_initialized ++;
+ if ((res = proc_register_dynamic(&proc_bus_dir, &proc_bus_i2c_dir))) {
+ printk("i2c-core.o: Could not create /proc/bus/i2c\n");
+ i2cproc_cleanup();
+ return res;
+ }
+ i2cproc_initialized ++;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+ return 0;
+}
+
+int i2cproc_cleanup(void)
+{
+
+ if (i2cproc_initialized >= 1) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ remove_proc_entry("i2c",proc_bus);
+ i2cproc_initialized -= 2;
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
+ int res;
+ if (i2cproc_initialized >= 2) {
+ if ((res = proc_unregister(&proc_bus_dir,
+ proc_bus_i2c_dir.low_ino))) {
+ printk("i2c-core.o: could not delete "
+ "/proc/bus/i2c, module not removed.");
+ return res;
+ }
+ i2cproc_initialized --;
+ }
+ if ((res = proc_unregister(&proc_root,proc_bus_dir.low_ino))) {
+ printk("i2c-core.o: could not delete /proc/bus/, "
+ "module not removed.");
+ return res;
+ }
+ i2cproc_initialized --;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+ }
+ return 0;
+}
+
+
+#endif /* def CONFIG_PROC_FS */
+
+/* ---------------------------------------------------
+ * dummy driver notification
+ * ---------------------------------------------------
+ */
+
+static void i2c_dummy_adapter(struct i2c_adapter *adap)
+{
+ int i;
+ for (i=0; i<I2C_DRIVER_MAX; i++)
+ if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY))
+ drivers[i]->attach_adapter(adap);
+}
+
+static void i2c_dummy_client(struct i2c_client *client)
+{
+ int i;
+ for (i=0; i<I2C_DRIVER_MAX; i++)
+ if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY))
+ drivers[i]->detach_client(client);
+}
+
+
+/* ----------------------------------------------------
+ * the functional interface to the i2c busses.
+ * ----------------------------------------------------
+ */
+
+int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num)
+{
+ int ret;
+
+ if (adap->algo->master_xfer) {
+ DEB2(printk("i2c-core.o: 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;
+ } else {
+ printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
+ adap->id);
+ return -ENOSYS;
+ }
+}
+
+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;
+
+ if (client->adapter->algo->master_xfer) {
+ msg.addr = client->addr;
+ msg.flags = client->flags & I2C_M_TEN;
+ msg.len = count;
+ (const char *)msg.buf = buf;
+
+ DEB2(printk("i2c-core.o: 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;
+ } else {
+ printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
+ client->adapter->id);
+ return -ENOSYS;
+ }
+}
+
+int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
+{
+ struct i2c_adapter *adap=client->adapter;
+ struct i2c_msg msg;
+ int ret;
+ if (client->adapter->algo->master_xfer) {
+ msg.addr = client->addr;
+ msg.flags = client->flags & I2C_M_TEN;
+ msg.flags |= I2C_M_RD;
+ msg.len = count;
+ msg.buf = buf;
+
+ DEB2(printk("i2c-core.o: 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);
+
+ DEB2(printk("i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n",
+ ret, count, client->addr));
+
+ /* if everything went ok (i.e. 1 msg transmitted), return #bytes
+ * transmitted, else error code.
+ */
+ return (ret == 1 )? count : ret;
+ } else {
+ printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
+ client->adapter->id);
+ return -ENOSYS;
+ }
+}
+
+
+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-core.o: 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;
+}
+
+/* ----------------------------------------------------
+ * the i2c address scanning function
+ * Will not work for 10-bit addresses!
+ * ----------------------------------------------------
+ */
+int i2c_probe(struct i2c_adapter *adapter,
+ struct i2c_client_address_data *address_data,
+ i2c_client_found_addr_proc *found_proc)
+{
+ int addr,i,found,err;
+ int adap_id = i2c_adapter_id(adapter);
+
+ /* Forget it if we can't probe using SMBUS_QUICK */
+ if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK))
+ return -1;
+
+ for (addr = 0x00;
+ addr <= 0x7f;
+ addr++) {
+
+ /* If it is in one of the force entries, we don't do any detection
+ at all */
+ found = 0;
+
+ for (i = 0;
+ !found && (address_data->force[i] != I2C_CLIENT_END);
+ i += 3) {
+ if (((adap_id == address_data->force[i]) ||
+ (address_data->force[i] == ANY_I2C_BUS)) &&
+ (addr == address_data->force[i+1])) {
+ DEB2(printk("i2c-core.o: found force parameter for adapter %d, addr %04x\n",
+ adap_id,addr));
+ if ((err = found_proc(adapter,addr,0,0)))
+ return err;
+ found = 1;
+ }
+ }
+ if (found)
+ continue;
+
+ /* If this address is in one of the ignores, we can forget about it
+ right now */
+ for (i = 0;
+ !found && (address_data->ignore[i] != I2C_CLIENT_END);
+ i += 2) {
+ if (((adap_id == address_data->ignore[i]) ||
+ ((address_data->ignore[i] == ANY_I2C_BUS))) &&
+ (addr == address_data->ignore[i+1])) {
+ DEB2(printk("i2c-core.o: found ignore parameter for adapter %d, "
+ "addr %04x\n", adap_id ,addr));
+ found = 1;
+ }
+ }
+ for (i = 0;
+ !found && (address_data->ignore_range[i] != I2C_CLIENT_END);
+ i += 3) {
+ if (((adap_id == address_data->ignore_range[i]) ||
+ ((address_data->ignore_range[i]==ANY_I2C_BUS))) &&
+ (addr >= address_data->ignore_range[i+1]) &&
+ (addr <= address_data->ignore_range[i+2])) {
+ DEB2(printk("i2c-core.o: found ignore_range parameter for adapter %d, "
+ "addr %04x\n", adap_id,addr));
+ found = 1;
+ }
+ }
+ if (found)
+ continue;
+
+ /* Now, we will do a detection, but only if it is in the normal or
+ probe entries */
+ for (i = 0;
+ !found && (address_data->normal_i2c[i] != I2C_CLIENT_END);
+ i += 1) {
+ if (addr == address_data->normal_i2c[i]) {
+ found = 1;
+ DEB2(printk("i2c-core.o: found normal i2c entry for adapter %d, "
+ "addr %02x", adap_id,addr));
+ }
+ }
+
+ for (i = 0;
+ !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END);
+ i += 2) {
+ if ((addr >= address_data->normal_i2c_range[i]) &&
+ (addr <= address_data->normal_i2c_range[i+1])) {
+ found = 1;
+ DEB2(printk("i2c-core.o: found normal i2c_range entry for adapter %d, "
+ "addr %04x\n", adap_id,addr));
+ }
+ }
+
+ for (i = 0;
+ !found && (address_data->probe[i] != I2C_CLIENT_END);
+ i += 2) {
+ if (((adap_id == address_data->probe[i]) ||
+ ((address_data->probe[i] == ANY_I2C_BUS))) &&
+ (addr == address_data->probe[i+1])) {
+ found = 1;
+ DEB2(printk("i2c-core.o: found probe parameter for adapter %d, "
+ "addr %04x\n", adap_id,addr));
+ }
+ }
+ for (i = 0;
+ !found && (address_data->probe_range[i] != I2C_CLIENT_END);
+ i += 3) {
+ if (((adap_id == address_data->probe_range[i]) ||
+ (address_data->probe_range[i] == ANY_I2C_BUS)) &&
+ (addr >= address_data->probe_range[i+1]) &&
+ (addr <= address_data->probe_range[i+2])) {
+ found = 1;
+ DEB2(printk("i2c-core.o: found probe_range parameter for adapter %d, "
+ "addr %04x\n", adap_id,addr));
+ }
+ }
+ if (!found)
+ continue;
+
+ /* OK, so we really should examine this address. First check
+ whether there is some client here at all! */
+ if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
+ if ((err = found_proc(adapter,addr,0,-1)))
+ return err;
+ }
+ return 0;
+}
+
+/* +++ frodo
+ * return id number for a specific adapter
+ */
+int i2c_adapter_id(struct i2c_adapter *adap)
+{
+ int i;
+ for (i = 0; i < I2C_ADAP_MAX; i++)
+ if (adap == adapters[i])
+ return i;
+ return -1;
+}
+
+/* The SMBus parts */
+
+extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value)
+{
+ return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ value,0,I2C_SMBUS_QUICK,NULL);
+}
+
+extern s32 i2c_smbus_read_byte(struct i2c_client * client)
+{
+ union i2c_smbus_data data;
+ if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data))
+ return -1;
+ else
+ return 0x0FF & data.byte;
+}
+
+extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value)
+{
+ return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL);
+}
+
+extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command)
+{
+ union i2c_smbus_data data;
+ if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data))
+ return -1;
+ else
+ return 0x0FF & data.byte;
+}
+
+extern s32 i2c_smbus_write_byte_data(struct i2c_client * client,
+ u8 command, u8 value)
+{
+ union i2c_smbus_data data;
+ data.byte = value;
+ return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_BYTE_DATA,&data);
+}
+
+extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command)
+{
+ union i2c_smbus_data data;
+ if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data))
+ return -1;
+ else
+ return 0x0FFFF & data.word;
+}
+
+extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
+ u8 command, u16 value)
+{
+ union i2c_smbus_data data;
+ data.word = value;
+ return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_WORD_DATA,&data);
+}
+
+extern s32 i2c_smbus_process_call(struct i2c_client * client,
+ u8 command, u16 value)
+{
+ union i2c_smbus_data data;
+ data.word = value;
+ if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_PROC_CALL, &data))
+ return -1;
+ else
+ return 0x0FFFF & data.word;
+}
+
+/* Returns the number of read bytes */
+extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
+ u8 command, u8 *values)
+{
+ union i2c_smbus_data data;
+ int i;
+ if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_READ,command,
+ I2C_SMBUS_BLOCK_DATA,&data))
+ return -1;
+ else {
+ for (i = 1; i <= data.block[0]; i++)
+ values[i-1] = data.block[i];
+ return data.block[0];
+ }
+}
+
+extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
+ u8 command, u8 length, u8 *values)
+{
+ union i2c_smbus_data data;
+ int i;
+ if (length > 32)
+ length = 32;
+ for (i = 1; i <= length; i++)
+ data.block[i] = values[i-1];
+ data.block[0] = length;
+ return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_BLOCK_DATA,&data);
+}
+
+/* Simulate a SMBus command using the i2c protocol
+ No checking of parameters is done! */
+static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
+ unsigned short flags,
+ char read_write, u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ /* So we need to generate a series of msgs. In the case of writing, we
+ need to use only one message; when reading, we need two. We initialize
+ most things with sane defaults, to keep the code below somewhat
+ simpler. */
+ unsigned char msgbuf0[33];
+ unsigned char msgbuf1[33];
+ int num = read_write == I2C_SMBUS_READ?2:1;
+ struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
+ { addr, flags | I2C_M_RD, 0, msgbuf1 }
+ };
+ int i;
+
+ msgbuf0[0] = command;
+ switch(size) {
+ case I2C_SMBUS_QUICK:
+ msg[0].len = 0;
+ /* Special case: The read/write field is used as data */
+ msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0;
+ num = 1;
+ break;
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_READ) {
+ /* Special case: only a read! */
+ msg[0].flags = I2C_M_RD | flags;
+ num = 1;
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_READ)
+ msg[1].len = 1;
+ else {
+ msg[0].len = 2;
+ msgbuf0[1] = data->byte;
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (read_write == I2C_SMBUS_READ)
+ msg[1].len = 2;
+ else {
+ msg[0].len=3;
+ msgbuf0[1] = data->word & 0xff;
+ msgbuf0[2] = (data->word >> 8) & 0xff;
+ }
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ num = 2; /* Special case */
+ msg[0].len = 3;
+ msg[1].len = 2;
+ msgbuf0[1] = data->word & 0xff;
+ msgbuf0[2] = (data->word >> 8) & 0xff;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ printk("i2c-core.o: Block read not supported under "
+ "I2C emulation!\n");
+ return -1;
+ } else {
+ msg[1].len = data->block[0] + 1;
+ if (msg[1].len > 32) {
+ printk("i2c-core.o: smbus_access called with "
+ "invalid block write size (%d)\n",
+ msg[1].len);
+ return -1;
+ }
+ for (i = 1; i <= msg[1].len; i++)
+ msgbuf0[i] = data->block[i];
+ }
+ break;
+ default:
+ printk("i2c-core.o: smbus_access called with invalid size (%d)\n",
+ size);
+ return -1;
+ }
+
+ if (i2c_transfer(adapter, msg, num) < 0)
+ return -1;
+
+ if (read_write == I2C_SMBUS_READ)
+ switch(size) {
+ case I2C_SMBUS_BYTE:
+ data->byte = msgbuf0[0];
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ data->byte = msgbuf1[0];
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ data->word = msgbuf1[0] | (msgbuf1[1] << 8);
+ break;
+ }
+ return 0;
+}
+
+
+s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
+ char read_write, u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ s32 res;
+ flags = flags & I2C_M_TEN;
+ if (adapter->algo->smbus_xfer) {
+ I2C_LOCK(adapter);
+ res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
+ command,size,data);
+ I2C_UNLOCK(adapter);
+ } else
+ res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
+ command,size,data);
+ return res;
+}
+
+
+/* You should always define `functionality'; the 'else' is just for
+ backward compatibility. */
+u32 i2c_get_functionality (struct i2c_adapter *adap)
+{
+ if (adap->algo->functionality)
+ return adap->algo->functionality(adap);
+ else
+ return 0xffffffff;
+}
+
+int i2c_check_functionality (struct i2c_adapter *adap, u32 func)
+{
+ u32 adap_func = i2c_get_functionality (adap);
+ return (func & adap_func) == func;
+}
+
+
+static int __init i2c_init(void)
+{
+ printk("i2c-core.o: i2c core module\n");
+ memset(adapters,0,sizeof(adapters));
+ memset(drivers,0,sizeof(drivers));
+ adap_count=0;
+ driver_count=0;
+
+ init_MUTEX(&adap_lock);
+ init_MUTEX(&driver_lock);
+
+ i2cproc_init();
+
+ return 0;
+}
+
+#ifndef MODULE
+#ifdef CONFIG_I2C_CHARDEV
+ extern int i2c_dev_init(void);
+#endif
+#ifdef CONFIG_I2C_ALGOBIT
+ extern int algo_bit_init(void);
+#endif
+#ifdef CONFIG_I2C_BITLP
+ extern int bitlp_init(void);
+#endif
+#ifdef CONFIG_I2C_BITELV
+ extern int bitelv_init(void);
+#endif
+#ifdef CONFIG_I2C_BITVELLE
+ extern int bitvelle_init(void);
+#endif
+#ifdef CONFIG_I2C_BITVIA
+ extern int bitvia_init(void);
+#endif
+
+#ifdef CONFIG_I2C_ALGOPCF
+ extern int algo_pcf_init(void);
+#endif
+#ifdef CONFIG_I2C_PCFISA
+ extern int pcfisa_init(void);
+#endif
+
+/* This is needed for automatic patch generation: sensors code starts here */
+/* This is needed for automatic patch generation: sensors code ends here */
+
+int __init i2c_init_all(void)
+{
+ /* --------------------- global ----- */
+ i2c_init();
+
+#ifdef CONFIG_I2C_CHARDEV
+ i2c_dev_init();
+#endif
+ /* --------------------- bit -------- */
+#ifdef CONFIG_I2C_ALGOBIT
+ i2c_algo_bit_init();
+#endif
+#ifdef CONFIG_I2C_PHILIPSPAR
+ i2c_bitlp_init();
+#endif
+#ifdef CONFIG_I2C_ELV
+ i2c_bitelv_init();
+#endif
+#ifdef CONFIG_I2C_VELLEMAN
+ i2c_bitvelle_init();
+#endif
+
+ /* --------------------- pcf -------- */
+#ifdef CONFIG_I2C_ALGOPCF
+ i2c_algo_pcf_init();
+#endif
+#ifdef CONFIG_I2C_ELEKTOR
+ i2c_pcfisa_init();
+#endif
+/* This is needed for automatic patch generation: sensors code starts here */
+/* This is needed for automatic patch generation: sensors code ends here */
+
+ return 0;
+}
+
+#endif
+
+
+
+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_inc_use_client);
+EXPORT_SYMBOL(i2c_dec_use_client);
+
+
+EXPORT_SYMBOL(i2c_master_send);
+EXPORT_SYMBOL(i2c_master_recv);
+EXPORT_SYMBOL(i2c_control);
+EXPORT_SYMBOL(i2c_transfer);
+EXPORT_SYMBOL(i2c_adapter_id);
+EXPORT_SYMBOL(i2c_probe);
+
+EXPORT_SYMBOL(i2c_smbus_xfer);
+EXPORT_SYMBOL(i2c_smbus_write_quick);
+EXPORT_SYMBOL(i2c_smbus_read_byte);
+EXPORT_SYMBOL(i2c_smbus_write_byte);
+EXPORT_SYMBOL(i2c_smbus_read_byte_data);
+EXPORT_SYMBOL(i2c_smbus_write_byte_data);
+EXPORT_SYMBOL(i2c_smbus_read_word_data);
+EXPORT_SYMBOL(i2c_smbus_write_word_data);
+EXPORT_SYMBOL(i2c_smbus_process_call);
+EXPORT_SYMBOL(i2c_smbus_read_block_data);
+EXPORT_SYMBOL(i2c_smbus_write_block_data);
+
+EXPORT_SYMBOL(i2c_get_functionality);
+EXPORT_SYMBOL(i2c_check_functionality);
+
+#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");
+
+int init_module(void)
+{
+ return i2c_init();
+}
+
+void cleanup_module(void)
+{
+ i2cproc_cleanup();
+}
+#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)