/* 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. */
/* ------------------------------------------------------------------------- */
/* With some changes from Ky�sti M�lkki <kmalkki@cc.hut.fi>.
All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and
Jean Delvare <khali@linux-fr.org> */
/* $Id: i2c-core.c,v 1.115 2005/11/05 21:00:58 khali Exp $ */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include "i2c.h"
#include <asm/uaccess.h>
/* ----- global defines ---------------------------------------------------- */
#if I2C_LINUX_2_4_BINARY_COMPATIBILITY
#define I2C_LOCK_LIST(adap) down(&adap->bus)
#define I2C_UNLOCK_LIST(adap) up(&adap->bus)
#else
#define I2C_LOCK_LIST(adap) down(&adap->list)
#define I2C_UNLOCK_LIST(adap) up(&adap->list)
#endif
#define DEB(x) if (i2c_debug>=1) x;
#define DEB2(x) if (i2c_debug>=2) x;
/* ----- global variables -------------------------------------------------- */
DECLARE_MUTEX(core_lists);
static struct i2c_adapter *adapters[I2C_ADAP_MAX];
static struct i2c_driver *drivers[I2C_DRIVER_MAX];
/**** debug level */
static int i2c_debug;
/* ---------------------------------------------------
* /proc entry declarations
*----------------------------------------------------
*/
#ifdef CONFIG_PROC_FS
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);
/* To implement the dynamic /proc/bus/i2c-? files, we need our own
implementation of the read hook */
static struct file_operations i2cproc_operations = {
.read = i2cproc_bus_read,
};
static int i2cproc_register(struct i2c_adapter *adap, int bus);
static void i2cproc_remove(int bus);
#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,res = 0;
down(&core_lists);
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);
res = -ENOMEM;
goto ERROR0;
}
#ifdef CONFIG_PROC_FS
res = i2cproc_register(adap, i);
if (res<0)
goto ERROR0;
#endif /* def CONFIG_PROC_FS */
adapters[i] = adap;
/* init data types */
init_MUTEX(&adap->bus);
#if !I2C_LINUX_2_4_BINARY_COMPATIBILITY
init_MUTEX(&adap->list);
#endif
/* inform drivers of new adapters */
for (j=0;j<I2C_DRIVER_MAX;j++)
if (drivers[j]!=NULL &&
(drivers[j]->flags&(I2C_DF_NOTIFY|I2C_DF_DUMMY)))
/* We ignore the return code; if it fails, too bad */
drivers[j]->attach_adapter(adap);
DEB(printk(KERN_DEBUG "i2c-core.o: adapter %s registered as adapter %d.\n",
adap->name,i));
ERROR0:
up(&core_lists);
return res;
}
int i2c_del_adapter(struct i2c_adapter *adap)
{
int i,j,res = 0;
down(&core_lists);
for (i = 0; i < I2C_ADAP_MAX; i++)
if (adap == adapters[i])
break;
if (I2C_ADAP_MAX == i) {
printk(KERN_WARNING "i2c-core.o: unregister_adapter adap [%s] not found.\n",
adap->name);
res = -ENODEV;
goto ERROR0;
}
/* DUMMY drivers do not register their clients, so we have to
* use a trick here: we call driver->attach_adapter to
* *detach* it! Of course, each dummy driver should know about
* this or hell will break loose...
*/
for (j = 0; j < I2C_DRIVER_MAX; j++)
if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY))
if ((res = drivers[j]->attach_adapter(adap))) {
printk(KERN_WARNING "i2c-core.o: can't detach adapter %s "
"while detaching driver %s: driver not "
"detached!\n", adap->name, drivers[j]->name);
goto ERROR0;
}
/* detach any active clients. This must be done first, because
* it can fail; in which case we give up. */
for (j=0;j<I2C_CLIENT_MAX;j++) {
struct i2c_client *client = adap->clients[j];
if (client!=NULL)
/* 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.
*/
if ((res=client->driver->detach_client(client))) {
printk(KERN_ERR "i2c-core.o: adapter %s not "
"unregistered, because client at "
"address %02x can't be detached\n",
adap->name, client->addr);
goto ERROR0;
}
}
#ifdef CONFIG_PROC_FS
i2cproc_remove(i);
#endif /* def CONFIG_PROC_FS */
adapters[i] = NULL;
DEB(printk(KERN_DEBUG "i2c-core.o: adapter unregistered: %s\n",adap->name));
ERROR0:
up(&core_lists);
return res;
}
/* -----
* 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;
down(&core_lists);
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);
up(&core_lists);
return -ENOMEM;
}
drivers[i] = driver;
DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));
/* now look for instances of driver on our adapters
*/
if (driver->flags& (I2C_DF_NOTIFY|I2C_DF_DUMMY)) {
for (i=0;i<I2C_ADAP_MAX;i++)
if (adapters[i]!=NULL)
/* Ignore errors */
driver->attach_adapter(adapters[i]);
}
up(&core_lists);
return 0;
}
int i2c_del_driver(struct i2c_driver *driver)
{
int i,j,k,res = 0;
down(&core_lists);
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);
up(&core_lists);
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(KERN_DEBUG "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.
*/
for (k=0;k<I2C_ADAP_MAX;k++) {
struct i2c_adapter *adap = adapters[k];
if (adap == NULL) /* skip empty entries. */
continue;
DEB2(printk(KERN_DEBUG "i2c-core.o: examining adapter %s:\n",
adap->name));
if (driver->flags & I2C_DF_DUMMY) {
/* DUMMY drivers do not register their clients, so we have to
* use a trick here: we call driver->attach_adapter to
* *detach* it! Of course, each dummy driver should know about
* this or hell will b
i2c_Drivers.tar.gz_IIC_i2c 驱动_i2c驱动 linux_linux i2c 驱动_linux 驱动
版权申诉
5星 · 超过95%的资源 178 浏览量
2022-09-23
06:32:31
上传
评论
收藏 135KB GZ 举报
朱moyimi
- 粉丝: 61
- 资源: 1万+
最新资源
- sony 索尼IMX334摄像头模组电路板AD版硬件PCB图(6层板).zip
- 基于flask和echarts融合交易策略的bitfinex可视化微服务.zip
- 包含了wvp-assist.tar wvp-talk.tar zlmediakit.tar .
- 3r4efgh53wgrf43tw
- 2024新版Java基础从入门到精通全套视频+资料下载
- Spring AI大模型视频教程+ChatGPT视频教程+OpenAI大模型视频教程(资料+视频教程)
- ABB工业机器人教程PDF版本
- 123321123323211
- yolov8实战第八天-pyqt5-yolov8实现车牌识别系统(论文(8700+字+数据集+完整部署代码+代码使用说明)
- 三相桥式全桥整流电路MATALB Simulink仿真文件
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈