OFN鼠标驱动(二) -- I2C驱动的移植(1)

在分析完DS1337的驱动之后,我们对I2C的驱动的移植有了个简单的认识,于是仿照DS1337的驱动,我们写了OFN的I2C部分:

 

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/string.h>
#include <linux/rtc.h>  /* get the user-level API */
#include <linux/bcd.h>
#include <linux/list.h>

 

/*
 * Functions declaration
 */
#define I2C_ADDR_OFN350 (0x66 >> 1)
static unsigned short normal_i2c[] = { I2C_ADDR_OFN350, I2C_CLIENT_END };

I2C_CLIENT_INSMOD_1(ofn350);

static int ofn350_attach_adapter(struct i2c_adapter *adapter);
static int ofn350_detect(struct i2c_adapter *adapter, int address, int kind);
static void ofn350_init_client(struct i2c_client *client);
static int ofn350_detach_client(struct i2c_client *client);
static int ofn350_command(struct i2c_client *client, unsigned int cmd,
     void *arg);

/*
 * Driver data (common to all clients)
 */
static struct i2c_driver ofn350_driver = {
 .driver = {
  .name = "ofn350",
 },
 .attach_adapter = ofn350_attach_adapter,  //注册时创建设备节点(调用适配器连接节点)
 .detach_client = ofn350_detach_client,   //让设备脱离适配器
 .command = ofn350_command,
};

/*
 * Client data (each client gets its own)
 */
struct ofn350_data {
 struct i2c_client client;
 struct list_head list;
};

/*
 * Internal variables
 */
static LIST_HEAD(ofn350_clients);

static inline int ofn350_read(struct i2c_client *client, u8 reg, u8 *value)
{
 s32 tmp = i2c_smbus_read_byte_data(client, reg);

 if (tmp < 0)
  return -EIO;

 *value = tmp;

 return 0;
}

/*
 * Chip access functions
 */
static int ofn350_command(struct i2c_client *client, unsigned int cmd,
     void *arg)
{
 dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);

 switch (cmd) {

 default:
  return -EINVAL;
 }
}

/*
 * Public API for access to specific device. Useful for low-level
 * RTC access from kernel code.
 */
int ofn350_do_command(int bus, int cmd, void *arg)
{
 struct list_head *walk;
 struct list_head *tmp;
 struct ofn350_data *data;

 list_for_each_safe(walk, tmp, &ofn350_clients) {
  data = list_entry(walk, struct ofn350_data, list);
  if (data->client.adapter->nr == bus)
   return ofn350_command(&data->client, cmd, arg);
 }

 return -ENODEV;
}

static int ofn350_attach_adapter(struct i2c_adapter *adapter)
{
 return i2c_probe(adapter, &addr_data, ofn350_detect);
}

/*
 * The following function does more than just detection. If detection
 * succeeds, it also registers the new chip.
 */
static int ofn350_detect(struct i2c_adapter *adapter, int address, int kind)
{
 struct i2c_client *new_client;
 struct ofn350_data *data;
 int err = 0;
 const char *name = "";
 
 //
 printk("<1>ofn350_detect\n");

 //
 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
         I2C_FUNC_I2C))
  goto exit;

 if (!(data = kzalloc(sizeof(struct ofn350_data), GFP_KERNEL))) {
  err = -ENOMEM;
  goto exit;
 }
 INIT_LIST_HEAD(&data->list);

 /* The common I2C client data is placed right before the
  * DS1337-specific data.
  */
 new_client = &data->client;
 i2c_set_clientdata(new_client, data);
 new_client->addr = address;
 new_client->adapter = adapter;
 new_client->driver = &ofn350_driver;
 new_client->flags = 0;

 /*
  * Now we do the remaining detection. A negative kind means that
  * the driver was loaded with no force parameter (default), so we
  * must both detect and identify the chip. A zero kind means that
  * the driver was loaded with the force parameter, the detection
  * step shall be skipped. A positive kind means that the driver
  * was loaded with the force parameter and a given kind of chip is
  * requested, so both the detection and the identification steps
  * are skipped.
  *
  * For detection, we read registers that are most likely to cause
  * detection failure, i.e. those that have more bits with fixed
  * or reserved values.
  */

 /* Default to an DS1337 if forced */
 if (kind == 0)
  kind = ofn350;

 if (kind < 0) {  /* detection and identification */
  u8 data;

  kind = ofn350;
 }

 if (kind == ofn350)
  name = "ofn350";

 /* We can fill in the remaining client fields */
 strlcpy(new_client->name, name, I2C_NAME_SIZE);

 /* Tell the I2C layer a new client has arrived */
 if ((err = i2c_attach_client(new_client)))
  goto exit_free;

 /* Initialize the DS1337 chip */
 ofn350_init_client(new_client);

 /* Add client to local list */
 list_add(&data->list, &ofn350_clients);

 return 0;

exit_free:
 kfree(data);
exit:
 return err;
}

static void ofn350_init_client(struct i2c_client *client)
{
 //初始化ofn350代码
 printk("<1>ofn350_init_client\n");
}

static int ofn350_detach_client(struct i2c_client *client)
{
 int err;
 struct ofn350_data *data = i2c_get_clientdata(client);

 //
 printk("<1>ofn350_detach_client\n");
 
 //
 if ((err = i2c_detach_client(client)))
  return err;

 list_del(&data->list);
 kfree(data);
 return 0;
}

static int __init ofn350_init(void)
{
 printk("<1>ofn350_init\n");
 return i2c_add_driver(&ofn350_driver);
}

static void __exit ofn350_exit(void)
{
 printk("<1>ofn350_exit\n");
 i2c_del_driver(&ofn350_driver);
}

MODULE_AUTHOR("Oscar Liu");
MODULE_DESCRIPTION("OFN350 driver");
MODULE_LICENSE("GPL");

EXPORT_SYMBOL_GPL(ofn350_do_command);

module_init(ofn350_init);
module_exit(ofn350_exit);

 

------------------------------------------------------------------------------------------------------------

Makefile文件如下:

# Makefile 
# Please modify here or set environments.
# KSOURCE should be pointed to the build directory of your kernel.
#
DEBUG ?= n
#KSOURCE ?= /home/azure/Utu-linux/s3c2440/Kernel/utu-linux_for_s3c2440_V1.5/
KSOURCE ?= /utu-Linux2.6.24/      #这个是我内核所在的路径

%.x:%.c
 arm-linux-gcc -o $@ $<

KBUILD_VERBOSE:=1

obj-m := ofn.o

default:
 make -C $(KSOURCE) LANG=C KBUILD_VERBOSE=${KBUILD_VERBOSE}  SUBDIRS=`pwd` modules

.PHONY: cscope
cscope:
 cscope -b -k -R

.PHONY: clean
clean:
 make -C $(KSOURCE) LANG=C KBUILD_VERBOSE=${KBUILD_VERBOSE}  SUBDIRS=`pwd` clean
 rm -f *.x *~

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值