2
0
mirror of https://github.com/lm-sensors/lm-sensors synced 2025-09-02 15:25:38 +00:00

The beginnings of i2c-dev

Everything is in, except the IOCTL hook (which will be pretty simple to add).
It compiles cleanly. It is not tested at all.

Also a very small fix for i2c-proc, and Makefile.


git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@158 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
Frodo Looijaard
1999-01-13 01:32:09 +00:00
parent 90627a9461
commit 81c78982f6
10 changed files with 837 additions and 3 deletions

View File

@@ -24,7 +24,7 @@
# Uncomment the third line on SMP systems if the magic invocation fails. It # Uncomment the third line on SMP systems if the magic invocation fails. It
# is a bit complicated because SMP configuration changed around kernel 2.1.130 # is a bit complicated because SMP configuration changed around kernel 2.1.130
SMP := $(shell if grep -q '^SMP[[:space:]]*=' /usr/src/linux/Makefile || \ SMP := $(shell if grep -q '^SMP[[:space:]]*=' /usr/src/linux/Makefile || \
grep -q '^CONFIG_SMP=y' /usr/src/linux/.config ; \ grep -q '^[[:space:]]*\#define[[::space:]]*CONFIG_SMP[[:space:]]*1' /usr/include/linux/autoconf.h ; \
then echo 1; else echo 0; fi) then echo 1; else echo 0; fi)
#SMP := 0 #SMP := 0
#SMP := 1 #SMP := 1

4
TODO
View File

@@ -1,5 +1,6 @@
Many, many things. Most notably: Many, many things. Most notably:
* Fans give overflow if small values are written to them.
* At least the bit-lp and bit-velle modules do no detection on loading; * At least the bit-lp and bit-velle modules do no detection on loading;
ask Simon whether this is possible to add. ask Simon whether this is possible to add.
* kmalloc with GFP_KERNEL can cause a context switch! Check whether this is * kmalloc with GFP_KERNEL can cause a context switch! Check whether this is
@@ -12,10 +13,13 @@ Many, many things. Most notably:
* Make it SMP-safe: there are no spinlocks yet. They are needed at many * Make it SMP-safe: there are no spinlocks yet. They are needed at many
places, probably (everywhere where global vars are accessed). This must be places, probably (everywhere where global vars are accessed). This must be
done for the i2c modules, too. done for the i2c modules, too.
* Better general locking, or at least a once-over to check no race-conditions
remain.
* Make lm78.c detect 'double hits', (same chip connected to both SMBus and * Make lm78.c detect 'double hits', (same chip connected to both SMBus and
ISA). ISA).
* Better chip detection; insmod-time paramters to set addresses * Better chip detection; insmod-time paramters to set addresses
(difficult, because of all i2c busses!). (difficult, because of all i2c busses!).
* At least one case report that unused port addresses do not return 0xff
* Registrate which i2c addresses are used (a la ISA) for each adapter. * Registrate which i2c addresses are used (a la ISA) for each adapter.
* Rename i2c-proc.c to i2c-user.c, and extend it with /dev entries; * Rename i2c-proc.c to i2c-user.c, and extend it with /dev entries;
or, create a better i2c-dev.c, that understands SMBus commands. or, create a better i2c-dev.c, that understands SMBus commands.

View File

@@ -28,7 +28,8 @@ SRCTARGETS := $(MODULE_DIR)/smbus.o $(MODULE_DIR)/piix4.o $(MODULE_DIR)/isa.o \
$(MODULE_DIR)/i2c-proc.o $(MODULE_DIR)/gl518sm.o \ $(MODULE_DIR)/i2c-proc.o $(MODULE_DIR)/gl518sm.o \
$(MODULE_DIR)/eeprom.o $(MODULE_DIR)/w83781d.o \ $(MODULE_DIR)/eeprom.o $(MODULE_DIR)/w83781d.o \
$(MODULE_DIR)/lm80.o $(MODULE_DIR)/adm1021.o \ $(MODULE_DIR)/lm80.o $(MODULE_DIR)/adm1021.o \
$(MODULE_DIR)/adm9240.o $(MODULE_DIR)/ltc1710.o $(MODULE_DIR)/adm9240.o $(MODULE_DIR)/ltc1710.o \
$(MODULE_DIR)/i2c-dev.o
SRCHEADERFILES := $(MODULE_DIR)/sensors.h $(MODULE_DIR)/isa.h \ SRCHEADERFILES := $(MODULE_DIR)/sensors.h $(MODULE_DIR)/isa.h \
$(MODULE_DIR)/smbus.h $(MODULE_DIR)/smbus.h

407
kernel/i2c-dev.c Normal file
View File

@@ -0,0 +1,407 @@
/*
i2c-dev.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 1995-1997, 1999 by Frodo Looijaard <frodol@dds.nl> and
Simon 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.
*/
/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
But I have used so much of his original code and ideas that it seems
only fair to recognize him as co-author -- Frodo */
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/malloc.h>
#include "compat.h"
#include "i2c.h"
#include "isa.h"
#include "sensors.h"
#include "version.h"
#ifdef MODULE
extern int init_module(void);
extern int cleanup_module(void);
#endif /* def MODULE */
/* struct file_operations changed too often in the 2.1 series for nice code */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
static loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin);
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56))
static long long i2cdev_lseek (struct file *file, long long offset, int origin);
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
static long long i2cdev_llseek (struct inode *inode, struct file *file,
long long offset, int origin);
#else
static int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset,
int origin);
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
loff_t *offset);
static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
loff_t *offset);
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
static long i2cdev_read (struct inode *inode, struct file *file, char *buf,
unsigned long count);
static long i2cdev_write (struct inode *inode, struct file *file,
const char *buf, unsigned long offset);
#else
static int i2cdev_read(struct inode *inode, struct file *file, char *buf,
int count);
static int i2cdev_write(struct inode *inode, struct file *file,
const char *buf, int count);
#endif
static int i2cdev_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
static int i2cdev_open (struct inode *inode, struct file *file);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
static int i2cdev_release (struct inode *inode, struct file *file);
#else
static void i2cdev_release (struct inode *inode, struct file *file);
#endif
static int i2cdev_attach_adapter(struct i2c_adapter *adap);
static int i2cdev_detach_client(struct i2c_client *client);
static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
void *arg);
static void i2cdev_inc_use(struct i2c_client *client);
static void i2cdev_dec_use(struct i2c_client *client);
static int i2cdev_init(void);
static int i2cdev_cleanup(void);
static struct file_operations i2cdev_fops = {
i2cdev_lseek,
i2cdev_read,
i2cdev_write,
NULL, /* i2cdev_readdir */
NULL, /* i2cdev_select */
i2cdev_ioctl,
NULL, /* i2cdev_mmap */
i2cdev_open,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118)
NULL, /* i2cdev_flush */
#endif
i2cdev_release,
};
#define I2CDEV_CLIENTS_MAX I2C_ADAP_MAX
static struct i2c_client *i2cdev_clients[I2CDEV_CLIENTS_MAX];
static struct i2c_driver i2cdev_driver = {
/* name */ "i2c-dev dummy driver",
/* id */ I2C_DRIVERID_I2CDEV,
/* flags */ DF_NOTIFY,
/* attach_adapter */ &i2cdev_attach_adapter,
/* detach_client */ &i2cdev_detach_client,
/* command */ &i2cdev_command,
/* inc_use */ &i2cdev_inc_use,
/* dec_use */ &i2cdev_dec_use
};
static struct i2c_client i2cdev_client_template = {
/* name */ "I2C /dev entry",
/* id */ 1,
/* flags */ 0,
/* addr */ -1,
/* adapter */ NULL,
/* driver */ &i2cdev_driver,
/* data */ NULL
};
static int i2cdev_initialized;
/* Note that the lseek function is called llseek in 2.1 kernels. But things
are complicated enough as is. */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin)
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56))
long long i2cdev_lseek (struct file *file, long long offset, int origin)
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
long long i2cdev_llseek (struct inode *inode, struct file *file,
long long offset, int origin)
#else
int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset,
int origin)
#endif
{
return -ESPIPE;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
loff_t *offset)
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
static long i2cdev_read (struct inode *inode, struct file *file, char *buf,
unsigned long count)
#else
static int i2cdev_read(struct inode *inode, struct file *file, char *buf,
int count)
#endif
{
char *tmp;
int ret;
struct i2c_client *client = (struct i2c_client *)file->private_data;
#ifdef DEBUG
printk("i2cdev_read: i2c%d reading %d bytes from %d.\n",minor,count,
client->addr);
#endif
/* copy user space data to kernel space. */
tmp = kmalloc(count,GFP_KERNEL);
if (tmp==NULL)
return -ENOMEM;
ret = i2c_master_recv(client,tmp,count);
copy_to_user(buf,tmp,count);
kfree(tmp);
return ret;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
loff_t *offset)
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
static long i2cdev_write (struct inode *inode, struct file *file,
const char *buf, unsigned long offset)
#else
static int i2cdev_write(struct inode *inode, struct file *file,
const char *buf, int count)
#endif
{
int ret;
char *tmp;
struct i2c_client *client = (struct i2c_client *)file->private_data;
/* copy user space data to kernel space. */
tmp = kmalloc(count,GFP_KERNEL);
if (tmp==NULL)
return -ENOMEM;
copy_from_user(tmp,buf,count);
#ifdef DEBUG
printk("i2c_write: i2c%d writing %d bytes.\n",minor,count);
#endif
ret = i2c_master_send(client,tmp,count);
kfree(tmp);
return ret;
}
int i2cdev_open (struct inode *inode, struct file *file)
{
unsigned int minor = MINOR(inode->i_rdev);
struct i2c_client *client;
if (! i2cdev_clients[minor]) {
#ifdef DEBUG
printk("i2cdev: trying to open unattached adapter i2c-%d\n",minor);
#endif
return -ENODEV;
}
/* Note that we here allocate a client for later use, but we will *not*
register this client! Yes, this is safe. No, it is not very clean. */
if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
return -ENOMEM;
memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
client->adapter = i2cdev_clients[minor]->adapter;
file->private_data = client;
MOD_INC_USE_COUNT;
#ifdef DEBUG
printk("i2cdev_open: i2c-%d\n",minor);
#endif
return 0;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
static int i2cdev_release (struct inode *inode, struct file *file)
#else
static void i2cdev_release (struct inode *inode, struct file *file)
#endif
{
kfree(file->private_data);
file->private_data=NULL;
#ifdef DEBUG
printk("i2c_close: i2c-%d\n", MINOR(inode->i_rdev));
#endif
MOD_DEC_USE_COUNT;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
return 0;
#endif
}
int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
int i,res;
struct i2c_client *client;
if ((i = i2c_adapter_id(adap)) < 0) {
printk("i2cdev_attach_adapter: unknown adapter?!?\n");
return -ENODEV;
}
if (i >= I2CDEV_CLIENTS_MAX) {
printk("i2cdev_attach_adapter: adapter number too large?!? (%d)\n",i);
return -ENODEV;
}
if (i2cdev_clients[i]) {
printk("i2cdev_attach_adapter: adapter already in use?!? (%d)\n",i);
return -EBUSY;
}
if (i2c_is_isa_adapter(adap)) {
printk("i2cdev_attach_adapter: Can't open ISA adapter!\n");
return -ENODEV;
}
if (! (client = (struct i2c_client *)kmalloc(sizeof(struct i2c_client),
GFP_KERNEL)))
return -ENOMEM;
memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
client->adapter = adap;
if ((res = i2c_attach_client(client))) {
printk("i2cdev_attach_adapter: attaching client failed.\n");
kfree(client);
return res;
}
i2cdev_clients[i] = client;
printk("i2cdev: registered '%s' as minor %d\n",adap->name,i);
return 0;
}
int i2cdev_detach_client(struct i2c_client *client)
{
struct i2c_adapter *adap = client->adapter;
int i,res;
if ((i = i2c_adapter_id(adap)) < 0) {
printk("i2cdev_detach_adapter: unknown adapter?!?\n");
return -ENODEV;
}
if (i >= I2CDEV_CLIENTS_MAX) {
printk("i2cdev_detach_adapter: adapter number too large?!? (%d)\n",i);
return -ENODEV;
}
if (!i2cdev_clients[i]) {
printk("i2cdev_detach_adapter: adapter not in use?!? (%d)\n",i);
return -ENODEV;
}
if ((res = i2c_detach_client(client))) {
printk("i2cdev_detach_adapter: detaching client failed.\n");
return res;
}
kfree(i2cdev_clients[i]);
i2cdev_clients[i] = NULL;
#ifdef DEBUG
printk("i2c(char): adapter unregistered: %s\n",adap->name);
#endif
return 0;
}
static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
return -1;
}
static void i2cdev_inc_use(struct i2c_client *client)
{
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
}
static void i2cdev_dec_use(struct i2c_client *client)
{
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
int i2cdev_init(void)
{
int res;
printk("i2c-dev.o version %s (%s)\n",LM_VERSION,LM_DATE);
i2cdev_initialized = 0;
if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) {
printk("i2c-dev.o: unable to get major %d for i2c bus\n",I2C_MAJOR);
return -EIO;
}
i2cdev_initialized ++;
if ((res = i2c_add_driver(&i2cdev_driver))) {
printk("i2c-dev.o: Driver registration failed, module not inserted.\n");
i2cdev_cleanup();
return res;
}
i2cdev_initialized ++;
return 0;
}
int i2cdev_cleanup(void)
{
int res;
if (i2cdev_initialized >= 2) {
if ((res = i2c_del_driver(&i2cdev_driver))) {
printk("i2c-dev.o: Driver deregistration failed, "
"module not removed.\n");
return res;
}
i2cdev_initialized ++;
}
if (i2cdev_initialized >= 1) {
if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) {
printk("i2c-dev.o: unable to release major %d for i2c bus\n",I2C_MAJOR);
return res;
}
i2cdev_initialized --;
}
return 0;
}
#ifdef MODULE
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C /dev entries driver");
int init_module(void)
{
return i2cdev_init();
}
int cleanup_module(void)
{
return i2cdev_cleanup();
}
#endif /* def MODULE */

View File

@@ -459,11 +459,17 @@ int i2cproc_command(struct i2c_client *client, unsigned int cmd,
/* Nothing here yet */ /* Nothing here yet */
void i2cproc_inc_use(struct i2c_client *client) void i2cproc_inc_use(struct i2c_client *client)
{ {
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
} }
/* Nothing here yet */ /* Nothing here yet */
void i2cproc_dec_use(struct i2c_client *client) void i2cproc_dec_use(struct i2c_client *client)
{ {
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
} }
#ifdef MODULE #ifdef MODULE

View File

@@ -81,6 +81,7 @@ extern void sensors_deregister_entry(int id);
#define SENSORS_PREFIX_MAX 20 #define SENSORS_PREFIX_MAX 20
/* Driver IDs */ /* Driver IDs */
#define I2C_DRIVERID_I2CDEV 1000
#define I2C_DRIVERID_I2CPROC 1001 #define I2C_DRIVERID_I2CPROC 1001
#define I2C_DRIVERID_LM78 1002 #define I2C_DRIVERID_LM78 1002
#define I2C_DRIVERID_LM75 1003 #define I2C_DRIVERID_LM75 1003

View File

@@ -28,7 +28,8 @@ SRCTARGETS := $(MODULE_DIR)/smbus.o $(MODULE_DIR)/piix4.o $(MODULE_DIR)/isa.o \
$(MODULE_DIR)/i2c-proc.o $(MODULE_DIR)/gl518sm.o \ $(MODULE_DIR)/i2c-proc.o $(MODULE_DIR)/gl518sm.o \
$(MODULE_DIR)/eeprom.o $(MODULE_DIR)/w83781d.o \ $(MODULE_DIR)/eeprom.o $(MODULE_DIR)/w83781d.o \
$(MODULE_DIR)/lm80.o $(MODULE_DIR)/adm1021.o \ $(MODULE_DIR)/lm80.o $(MODULE_DIR)/adm1021.o \
$(MODULE_DIR)/adm9240.o $(MODULE_DIR)/ltc1710.o $(MODULE_DIR)/adm9240.o $(MODULE_DIR)/ltc1710.o \
$(MODULE_DIR)/i2c-dev.o
SRCHEADERFILES := $(MODULE_DIR)/sensors.h $(MODULE_DIR)/isa.h \ SRCHEADERFILES := $(MODULE_DIR)/sensors.h $(MODULE_DIR)/isa.h \
$(MODULE_DIR)/smbus.h $(MODULE_DIR)/smbus.h

407
src/i2c-dev.c Normal file
View File

@@ -0,0 +1,407 @@
/*
i2c-dev.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 1995-1997, 1999 by Frodo Looijaard <frodol@dds.nl> and
Simon 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.
*/
/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
But I have used so much of his original code and ideas that it seems
only fair to recognize him as co-author -- Frodo */
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/malloc.h>
#include "compat.h"
#include "i2c.h"
#include "isa.h"
#include "sensors.h"
#include "version.h"
#ifdef MODULE
extern int init_module(void);
extern int cleanup_module(void);
#endif /* def MODULE */
/* struct file_operations changed too often in the 2.1 series for nice code */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
static loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin);
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56))
static long long i2cdev_lseek (struct file *file, long long offset, int origin);
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
static long long i2cdev_llseek (struct inode *inode, struct file *file,
long long offset, int origin);
#else
static int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset,
int origin);
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
loff_t *offset);
static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
loff_t *offset);
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
static long i2cdev_read (struct inode *inode, struct file *file, char *buf,
unsigned long count);
static long i2cdev_write (struct inode *inode, struct file *file,
const char *buf, unsigned long offset);
#else
static int i2cdev_read(struct inode *inode, struct file *file, char *buf,
int count);
static int i2cdev_write(struct inode *inode, struct file *file,
const char *buf, int count);
#endif
static int i2cdev_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
static int i2cdev_open (struct inode *inode, struct file *file);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
static int i2cdev_release (struct inode *inode, struct file *file);
#else
static void i2cdev_release (struct inode *inode, struct file *file);
#endif
static int i2cdev_attach_adapter(struct i2c_adapter *adap);
static int i2cdev_detach_client(struct i2c_client *client);
static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
void *arg);
static void i2cdev_inc_use(struct i2c_client *client);
static void i2cdev_dec_use(struct i2c_client *client);
static int i2cdev_init(void);
static int i2cdev_cleanup(void);
static struct file_operations i2cdev_fops = {
i2cdev_lseek,
i2cdev_read,
i2cdev_write,
NULL, /* i2cdev_readdir */
NULL, /* i2cdev_select */
i2cdev_ioctl,
NULL, /* i2cdev_mmap */
i2cdev_open,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118)
NULL, /* i2cdev_flush */
#endif
i2cdev_release,
};
#define I2CDEV_CLIENTS_MAX I2C_ADAP_MAX
static struct i2c_client *i2cdev_clients[I2CDEV_CLIENTS_MAX];
static struct i2c_driver i2cdev_driver = {
/* name */ "i2c-dev dummy driver",
/* id */ I2C_DRIVERID_I2CDEV,
/* flags */ DF_NOTIFY,
/* attach_adapter */ &i2cdev_attach_adapter,
/* detach_client */ &i2cdev_detach_client,
/* command */ &i2cdev_command,
/* inc_use */ &i2cdev_inc_use,
/* dec_use */ &i2cdev_dec_use
};
static struct i2c_client i2cdev_client_template = {
/* name */ "I2C /dev entry",
/* id */ 1,
/* flags */ 0,
/* addr */ -1,
/* adapter */ NULL,
/* driver */ &i2cdev_driver,
/* data */ NULL
};
static int i2cdev_initialized;
/* Note that the lseek function is called llseek in 2.1 kernels. But things
are complicated enough as is. */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin)
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56))
long long i2cdev_lseek (struct file *file, long long offset, int origin)
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
long long i2cdev_llseek (struct inode *inode, struct file *file,
long long offset, int origin)
#else
int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset,
int origin)
#endif
{
return -ESPIPE;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
loff_t *offset)
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
static long i2cdev_read (struct inode *inode, struct file *file, char *buf,
unsigned long count)
#else
static int i2cdev_read(struct inode *inode, struct file *file, char *buf,
int count)
#endif
{
char *tmp;
int ret;
struct i2c_client *client = (struct i2c_client *)file->private_data;
#ifdef DEBUG
printk("i2cdev_read: i2c%d reading %d bytes from %d.\n",minor,count,
client->addr);
#endif
/* copy user space data to kernel space. */
tmp = kmalloc(count,GFP_KERNEL);
if (tmp==NULL)
return -ENOMEM;
ret = i2c_master_recv(client,tmp,count);
copy_to_user(buf,tmp,count);
kfree(tmp);
return ret;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
loff_t *offset)
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
static long i2cdev_write (struct inode *inode, struct file *file,
const char *buf, unsigned long offset)
#else
static int i2cdev_write(struct inode *inode, struct file *file,
const char *buf, int count)
#endif
{
int ret;
char *tmp;
struct i2c_client *client = (struct i2c_client *)file->private_data;
/* copy user space data to kernel space. */
tmp = kmalloc(count,GFP_KERNEL);
if (tmp==NULL)
return -ENOMEM;
copy_from_user(tmp,buf,count);
#ifdef DEBUG
printk("i2c_write: i2c%d writing %d bytes.\n",minor,count);
#endif
ret = i2c_master_send(client,tmp,count);
kfree(tmp);
return ret;
}
int i2cdev_open (struct inode *inode, struct file *file)
{
unsigned int minor = MINOR(inode->i_rdev);
struct i2c_client *client;
if (! i2cdev_clients[minor]) {
#ifdef DEBUG
printk("i2cdev: trying to open unattached adapter i2c-%d\n",minor);
#endif
return -ENODEV;
}
/* Note that we here allocate a client for later use, but we will *not*
register this client! Yes, this is safe. No, it is not very clean. */
if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
return -ENOMEM;
memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
client->adapter = i2cdev_clients[minor]->adapter;
file->private_data = client;
MOD_INC_USE_COUNT;
#ifdef DEBUG
printk("i2cdev_open: i2c-%d\n",minor);
#endif
return 0;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
static int i2cdev_release (struct inode *inode, struct file *file)
#else
static void i2cdev_release (struct inode *inode, struct file *file)
#endif
{
kfree(file->private_data);
file->private_data=NULL;
#ifdef DEBUG
printk("i2c_close: i2c-%d\n", MINOR(inode->i_rdev));
#endif
MOD_DEC_USE_COUNT;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
return 0;
#endif
}
int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
int i,res;
struct i2c_client *client;
if ((i = i2c_adapter_id(adap)) < 0) {
printk("i2cdev_attach_adapter: unknown adapter?!?\n");
return -ENODEV;
}
if (i >= I2CDEV_CLIENTS_MAX) {
printk("i2cdev_attach_adapter: adapter number too large?!? (%d)\n",i);
return -ENODEV;
}
if (i2cdev_clients[i]) {
printk("i2cdev_attach_adapter: adapter already in use?!? (%d)\n",i);
return -EBUSY;
}
if (i2c_is_isa_adapter(adap)) {
printk("i2cdev_attach_adapter: Can't open ISA adapter!\n");
return -ENODEV;
}
if (! (client = (struct i2c_client *)kmalloc(sizeof(struct i2c_client),
GFP_KERNEL)))
return -ENOMEM;
memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
client->adapter = adap;
if ((res = i2c_attach_client(client))) {
printk("i2cdev_attach_adapter: attaching client failed.\n");
kfree(client);
return res;
}
i2cdev_clients[i] = client;
printk("i2cdev: registered '%s' as minor %d\n",adap->name,i);
return 0;
}
int i2cdev_detach_client(struct i2c_client *client)
{
struct i2c_adapter *adap = client->adapter;
int i,res;
if ((i = i2c_adapter_id(adap)) < 0) {
printk("i2cdev_detach_adapter: unknown adapter?!?\n");
return -ENODEV;
}
if (i >= I2CDEV_CLIENTS_MAX) {
printk("i2cdev_detach_adapter: adapter number too large?!? (%d)\n",i);
return -ENODEV;
}
if (!i2cdev_clients[i]) {
printk("i2cdev_detach_adapter: adapter not in use?!? (%d)\n",i);
return -ENODEV;
}
if ((res = i2c_detach_client(client))) {
printk("i2cdev_detach_adapter: detaching client failed.\n");
return res;
}
kfree(i2cdev_clients[i]);
i2cdev_clients[i] = NULL;
#ifdef DEBUG
printk("i2c(char): adapter unregistered: %s\n",adap->name);
#endif
return 0;
}
static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
return -1;
}
static void i2cdev_inc_use(struct i2c_client *client)
{
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
}
static void i2cdev_dec_use(struct i2c_client *client)
{
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
int i2cdev_init(void)
{
int res;
printk("i2c-dev.o version %s (%s)\n",LM_VERSION,LM_DATE);
i2cdev_initialized = 0;
if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) {
printk("i2c-dev.o: unable to get major %d for i2c bus\n",I2C_MAJOR);
return -EIO;
}
i2cdev_initialized ++;
if ((res = i2c_add_driver(&i2cdev_driver))) {
printk("i2c-dev.o: Driver registration failed, module not inserted.\n");
i2cdev_cleanup();
return res;
}
i2cdev_initialized ++;
return 0;
}
int i2cdev_cleanup(void)
{
int res;
if (i2cdev_initialized >= 2) {
if ((res = i2c_del_driver(&i2cdev_driver))) {
printk("i2c-dev.o: Driver deregistration failed, "
"module not removed.\n");
return res;
}
i2cdev_initialized ++;
}
if (i2cdev_initialized >= 1) {
if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) {
printk("i2c-dev.o: unable to release major %d for i2c bus\n",I2C_MAJOR);
return res;
}
i2cdev_initialized --;
}
return 0;
}
#ifdef MODULE
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C /dev entries driver");
int init_module(void)
{
return i2cdev_init();
}
int cleanup_module(void)
{
return i2cdev_cleanup();
}
#endif /* def MODULE */

View File

@@ -459,11 +459,17 @@ int i2cproc_command(struct i2c_client *client, unsigned int cmd,
/* Nothing here yet */ /* Nothing here yet */
void i2cproc_inc_use(struct i2c_client *client) void i2cproc_inc_use(struct i2c_client *client)
{ {
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
} }
/* Nothing here yet */ /* Nothing here yet */
void i2cproc_dec_use(struct i2c_client *client) void i2cproc_dec_use(struct i2c_client *client)
{ {
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
} }
#ifdef MODULE #ifdef MODULE

View File

@@ -81,6 +81,7 @@ extern void sensors_deregister_entry(int id);
#define SENSORS_PREFIX_MAX 20 #define SENSORS_PREFIX_MAX 20
/* Driver IDs */ /* Driver IDs */
#define I2C_DRIVERID_I2CDEV 1000
#define I2C_DRIVERID_I2CPROC 1001 #define I2C_DRIVERID_I2CPROC 1001
#define I2C_DRIVERID_LM78 1002 #define I2C_DRIVERID_LM78 1002
#define I2C_DRIVERID_LM75 1003 #define I2C_DRIVERID_LM75 1003