OFN鼠标驱动(一) --- I2C驱动的分析(DS1337)

 

本文以Linux自带的驱动DS1337为例,对IIC驱动进行分析。

DS1337所在的位置为Linux\drivers\i2c\chips\ds1337.c。

 

IIC通信协议,对于我们这些MCU出身的人来说,应该已经很熟悉了,这里就不再介绍。而DS1337为一个时钟IC,具体的规格书可以随便BAIDU到中文版本,这里我们就先不多花时间来复习这些前期的准备知识了。

当然,如果读者还不清楚这两个知识点的话,在读本文前建议先花点时间了解一下这些基本知识。

 

 

驱动的入口一般都是module_init,不过我们在进入这个入口之前,我们还是先看看一些变量的定义,以及宏的申明:

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

/*

 * Functions declaration

 */

//这个是IIC设备的器件地址,至于是怎么用到的,我们后面会分析到

static      unsigned short       normal_i2c[] = { 0x68, I2C_CLIENT_END };

 

I2C_CLIENT_INSMOD_1(ds1337);

//平白无故的冒出这么一个东西,第一反应是这个东西是一个宏

//于是我们在include\linux\i2c.h中找到了他的申明:

#define   I2C_CLIENT_INSMOD_1(chip1)                                           \

enum      chips { any_chip,   chip1 };                                                    \

I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "        \

                     "boldly assume to be present");                     \

I2C_CLIENT_MODULE_PARM_FORCE(chip1);                                         \

static      unsigned short *forces[] = { force,      force_##chip1, NULL };              \

I2C_CLIENT_INSMOD_COMMON

 

我们先不管其他的宏,先把这里给套入参数:

enum      chips       {any_chip,     ds1337};

I2C_CLIENT_MODULE_PARM(….)

I2C_CLIENT_MODULE_PARM_FORCE(ds1337);

static      unsigned short        *forces[] = {force,               force_ds1337,       NULL};

I2C_CLIENT_INSMOD_COMMON

 

*forces[]里面的东西从哪来的?

呵呵,先别着急,我们先把前面两个宏展开来:

 

%%%%%%%%%%%%%%%%%%%%

#define   I2C_CLIENT_MODULE_PARM(var,   desc)            \

  static unsigned   short var[I2C_CLIENT_MAX_OPTS] = I2C_CLIENT_DEFAULTS;       \

       I2C_CLIENT_MAX_OPTS = 48

       I2C_CLIENT_DEFAULTS  =  I2C_CLIENT_END,也就是0xfffeU

       所以这里很容易理解:定义一个变量数组force[48],并将值全部初始化为0xfffeU

  static unsigned int     var##_num; \              

       定义变量force_num

  module_param_array(var,        short,     &var##_num,        0); \

       在include\linux\Moduleparam.h中,我们找到如下定义:

       #define   module_param_array(name, type, nump, perm)          \

       module_param_array_named(name,     name,     type,      nump,    perm)

       这个宏再挖下去话题就远了,我们只要知道这个宏的作用就行了:

       force(var) – 模块参数名(就像一个变量名一样)

       short – 参数类型

       *force_num – 保存元素个数

       0 – 权限

  MODULE_PARM_DESC(var,desc)

       这里只是一个字符串信息描述

 

可见,这个宏目前可见的作用是声明了一个变量数组force[48],并将该数组全部初始为为I2C_CLIENT_END

 

%%%%%%%%%%%%%%%%%%%%

#define   I2C_CLIENT_MODULE_PARM_FORCE(name)                            \

I2C_CLIENT_MODULE_PARM(force_##name,                                           \

                     "List of adapter,address pairs which are "                                   \

                     "unquestionably assumed to contain a `"                             \

                     # name     "' chip")

展开一下就是:

IC2_CLIENT_MODULE_PARM(force_ds1337,

       “….”       ds1337 “chip”)

这个宏刚刚分析过,也就是在这里又建立了一个数组:

force_ds1337[48] = {…}

 

%%%%%%%%%%%%%%%%%%%%

看完上面两个宏的分析,以下这行代码就容易理解了:

static      unsigned short        *forces[] = {force,               force_ds1337,       NULL};

指针数组 ^_^

 

最后,才是I2C_CLIENT_INSMOD_1(ds1337)的核心部分:

I2C_CLIENT_INSMOD_COMMON

 

#define   I2C_CLIENT_INSMOD_COMMON                                \

I2C_CLIENT_MODULE_PARM(probe, "List of adapter,address pairs to scan "       \

                     "additionally");                                                  \

       这里定义了probe[]数组

I2C_CLIENT_MODULE_PARM(ignore, "List of adapter,address pairs not to "       \

                     "scan");    

       这里定义了ignore[]数组                                                      \

static struct    i2c_client_address_data        addr_data = {                \

       .normal_i2c    = normal_i2c,                                                  \

       .probe            = probe,                                                          \

       .ignore           = ignore,                                                         \

       .forces            = forces,                                                          \

}

 

对一下结构体原型:

struct      i2c_client_address_data {

       unsigned short       *normal_i2c;

       unsigned short       *probe;

       unsigned short       *ignore;

       unsigned short       **forces;

};

 

应该没什么疑问了吧。

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

/*

 * Driver data (common to all clients)

 */

//I2C的结构体,很大,这里只初始化了需要用到的部分

static struct    i2c_driver      ds1337_driver = {

       .driver = {

              .name      = "ds1337",

       },

       .attach_adapter       = ds1337_attach_adapter,

       .detach_client         = ds1337_detach_client,

       .command             = ds1337_command,

};

 

/*

 * Client data (each client gets its own)

 */

//指定设备的结构体,不同的设备按自己的需要有不同的定义

struct      ds1337_data {

       struct i2c_client     client;

       struct list_head      list;

};

 

/*

 * Internal variables

 */

static      LIST_HEAD(ds1337_clients);      //声明一个空链表ds1337_clients

 

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

准备工作做完,我们该看代码了,先从入口看起

 

module_init(ds1337_init);

 

static int        __init     ds1337_init(void)

{

       return     i2c_add_driver(&ds1337_driver);

}

 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

在I2C.h中

static      inline     int i2c_add_driver(struct i2c_driver *driver)

{

       return     i2c_register_driver(THIS_MODULE, driver);

}

 

然后进入I2C_core.c

这里传近来的*driver = ds1337_driver

int   i2c_register_driver(struct module *owner,   struct i2c_driver    *driver)

{

       int res;

 

       /* new style driver methods can't mix with legacy ones */

       #define is_newstyle_driver(d)      ((d)->probe || (d)->remove)

       //从ds1337_driver结构体定义中可以看到,probe和remove均未定义,所以这个if不成立。

       //简单的看一眼这个if的实现代码可发现,这个if实际是说明了,i2c_driver中,probe+remove和attach_adapter等函数是互斥的,应该是两种扫描方法(或则说是两种I2C驱动架构),只能选择一种来描述。

       if (is_newstyle_driver(driver)) {

              if (driver->attach_adapter || driver->detach_adapter || driver->detach_client) {

                     printk(KERN_WARNING

                                   "i2c-core: driver [%s] is confused\n",

                                   driver->driver.name);

                     return     -EINVAL;

              }

       }

 

       /* add the driver to the list of i2c drivers in the driver core */

       driver->driver.owner     = owner;               //模块所有者

       driver->driver.bus         = &i2c_bus_type;   //挂上总线类型,他的定义在i2c_core.c中

 

static      struct bus_type      i2c_bus_type = {

       .name             = "i2c",

       .dev_attrs              = i2c_dev_attrs,

       .match            = i2c_device_match,

       .uevent           = i2c_device_uevent,

       .probe            = i2c_device_probe,

       .remove          = i2c_device_remove,

       .shutdown       = i2c_device_shutdown,

       .suspend         = i2c_device_suspend,

       .resume          = i2c_device_resume,

};

 

       /* for new style drivers, when registration returns the driver core

        * will have called probe() for all matching-but-unbound devices.

        */

       res = driver_register(&driver->driver);        //注册设备到内核中

       if (res)

              return res;

 

       mutex_lock(&core_lists);                           //互斥锁

 

       //将driver->list加进drivers链表中(这条代码在2.6.25中失踪了)

       list_add_tail(&driver->list,&drivers);

 

       //打印信息

       pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

 

       /* legacy drivers scan i2c busses directly */

       //如果attach_adapter定义,则执行if。

       //我们在ds1337_driver的声明中已经将该成员赋值为ds1337_attach_adapter

       if (driver->attach_adapter) {

              struct i2c_adapter *adapter;        //定义一个I2C的适配器

 

              // list_for_each_entry:第一个参数为传入的遍历指针,指向宿主数据结构,第二个参数为链表头,为list_head结构,第三个参数为list_head结构在宿主结构中的成员名。

              //这里遍历了整个适配器,并调用adapter函数,要注意的是,设备注册进函数是在系统初始化或者模块加载的时候完成的。

              list_for_each_entry(adapter, &adapters, list) {

                     driver->attach_adapter(adapter);

              }

       }

 

       mutex_unlock(&core_lists);                        //解锁

       return 0;

}

EXPORT_SYMBOL(i2c_register_driver);

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

接着我们看探测函数:driver->attach_adapter(adapter);

 

//这个函数除去一些保护检查代码外,就是最后一个循环的最后一个函数调用是实际起作用的:i2c_probe_address

static int        ds1337_attach_adapter(struct i2c_adapter *adapter)

{

       //注意这里的addr_data就是一开始我们分析参数的时候,宏

       // I2C_CLIENT_INSMOD_1所声明的数组

       return     i2c_probe(adapter,        &addr_data,   ds1337_detect);

}

 

同样在i2c-core.c中找到他的实现:

int   i2c_probe(

       struct i2c_adapter                       *adapter,

       struct i2c_client_address_data      *address_data,       

       int (*found_proc) (struct i2c_adapter *, int, int))

{

       int   i, err;

       int   adap_id = i2c_adapter_id(adapter);              //获取adapter->nr

 

       //forces存在,所以这个if执行

       if (address_data->forces) {

              unsigned short       **forces = address_data->forces;

              int   kind;

 

              for (kind = 0; forces[kind]; kind++) {

                     //由于用I2C_CLIENT_MODULE_PARM定义时,forces全给定义成了I2C_CLIENT_END,所以这个for实际没用

                     for (i = 0; forces[kind][i] != I2C_CLIENT_END;  i += 2) {

                            if (forces[kind][i] == adap_id

                             || forces[kind][i] == ANY_I2C_BUS) {

                                   dev_dbg(&adapter->dev, "found force "

                                          "parameter for adapter %d, "

                                          "addr 0x%02x, kind %d\n",

                                          adap_id, forces[kind][i + 1],

                                          kind);

                                   err = i2c_probe_address(adapter,

                                          forces[kind][i + 1],

                                          kind, found_proc);

                                   if (err)

                                          return err;

                            }

                     }

              }

       }

 

       /* Stop here if we can't use   SMBUS_QUICK */

       //又是一段检查用的代码

       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {

              if (address_data->probe[0] == I2C_CLIENT_END

               && address_data->normal_i2c[0] == I2C_CLIENT_END)

                     return 0;

 

              dev_warn(&adapter->dev, "SMBus Quick command not supported, "

                      "can't probe for chips\n");

              return -1;

       }

 

       //同上,probe都是I2C_CLIENT_END所以这里的代码都无意义

       for (i = 0;      address_data->probe[i] != I2C_CLIENT_END; i += 2) {

              if (address_data->probe[i] == adap_id

               || address_data->probe[i] == ANY_I2C_BUS) {

                     dev_dbg(&adapter->dev, "found probe parameter for "

                            "adapter %d, addr 0x%02x\n", adap_id,

                            address_data->probe[i + 1]);

                     err = i2c_probe_address(adapter,

                                          address_data->probe[i + 1],

                                          -1, found_proc);

                     if (err)

                            return err;

              }

       }

 

       //由于normal_i2d有定义器件地址,所以这个循环执行

       for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {

              int   j, ignore;

 

              ignore = 0;

 

              //同样,这个循环也是不执行的

              for (j = 0; address_data->ignore[j] != I2C_CLIENT_END;  j += 2) {

                     if ((address_data->ignore[j] == adap_id ||

                          address_data->ignore[j] == ANY_I2C_BUS)

                      && address_data->ignore[j + 1]

                         == address_data->normal_i2c[i]) {

                            dev_dbg(&adapter->dev, "found ignore "

                                   "parameter for adapter %d, "

                                   "addr 0x%02x\n", adap_id,

                                   address_data->ignore[j + 1]);

                            ignore = 1;

                            break;

                     }

              }

              if (ignore)

                     continue;

 

              //打印信息

              dev_dbg(&adapter->dev, "found normal entry for adapter %d, "

                     "addr 0x%02x\n", adap_id,

                     address_data->normal_i2c[i]);

 

              //调用探测地址函数

              //可以说这个函数分析完了,也就这句代码是实际起作用的

              err = i2c_probe_address(adapter, address_data->normal_i2c[i],

                                   -1, found_proc);

              if (err)

                     return err;

       }

 

       return 0;

}

EXPORT_SYMBOL(i2c_probe);

 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

static int        i2c_probe_address(

       struct i2c_adapter *adapter,

       int                        addr,                    //设备地址

       int                        kind,                     //-1

       int (*found_proc) (struct i2c_adapter *, int, int))

{

       int err;

 

       /* Make sure the address is valid */

       //检查地址是否合法

       if (addr < 0x03 || addr > 0x77) {

              dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",

                      addr);

              return     -EINVAL;

       }

 

       /* Skip if already in use */

       //检查适配器上是否已经有该地址(地址冲突)

       if (i2c_check_addr(adapter, addr))

              return 0;

 

       /* Make sure there is something at this address, unless forced */

       //i2c_smbus_xfer函数挖得有点深,这里先放一放

       if (kind < 0) {

              if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,

                               I2C_SMBUS_QUICK, NULL) < 0)

                     return 0;

 

              /* prevent 24RF08 corruption */

              if ((addr & ~0x0f) == 0x50)

                     i2c_smbus_xfer(adapter, addr, 0, 0, 0,

                                   I2C_SMBUS_QUICK, NULL);

       }

 

       /* Finally call the custom detection function */

       err = found_proc(adapter, addr, kind);         //回调传入的函数

 

       //返回错误处理

       if (err == -ENODEV)

              err = 0;

 

       if (err)

              dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n",

                      addr, err);

       return err;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

探测绕了一个弯,又绕回来了…

 

static int        ds1337_detect(

       struct i2c_adapter *adapter,

       int                        address,                //设备地址

       int                        kind)                     //-1

{

       struct i2c_client            *new_client;

       struct ds1337_data        *data;

       int   err = 0;

       const char                    *name = "";

 

       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |

                                 I2C_FUNC_I2C))

              goto exit;

 

       //申请一块内存来保存设备自己的结构体

       if (!(data = kzalloc(sizeof(struct ds1337_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 = &ds1337_driver;

       new_client->flags = 0;

 

       /* Default to an DS1337 if forced */

       //将类型设置为ds1337, 之前传进来的类型kind = -1

       if (kind == 0)

              kind = ds1337;

 

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

              u8 data;

 

              /* Check that status register bits 6-2 are zero */

              if ((ds1337_read(new_client, DS1337_REG_STATUS, &data) < 0) ||

                  (data & 0x7c))

                     goto exit_free;

              //此处删除了一些代码,都是用ds1337_read读数据的

 

              kind = ds1337;

       }

 

       if (kind == ds1337)

              name = "ds1337";

 

       /* 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 */

       //调用这个函数探测一个新的IIC设备

       //由于我们现在只是分析应用,所以先不挖这个函数。

       if ((err = i2c_attach_client(new_client)))

              goto exit_free;

 

       /* Initialize the DS1337 chip */

       //初始化DS1337设备

       ds1337_init_client(new_client);

 

       /* Add client to local list */

       list_add(&data->list, &ds1337_clients);

 

       return 0;

 

exit_free:

       kfree(data);            //释放刚申请的内存

exit:

       return err;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//初始化指定的设备

//这个函数主要展示了IIC读/写的函数调用

static void      ds1337_init_client(struct i2c_client      *client)

{

       u8 status, control;

 

       //读指定寄存器的值

       status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);

       control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);

 

       if ((status & 0x80) || (control & 0x80)) {

              /* RTC not running */

              ……

 

              i2c_transfer(client->adapter,        msg,       1);

       } else {

              /* Running: ensure that device is set in 24-hour mode */

              s32 val;

 

              val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR);

              if ((val >= 0) && (val & (1 << 6)))

                     i2c_smbus_write_byte_data(client, DS1337_REG_HOUR,

                                            val & 0x3f);

       }

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

卸载函数

static void __exit ds1337_exit(void)

{

       i2c_del_driver(&ds1337_driver);

}

 

void i2c_del_driver(struct i2c_driver *driver)

{

       struct list_head   *item1, *item2, *_n;

       struct i2c_client  *client;

       struct i2c_adapter *adap;

 

       mutex_lock(&core_lists);             //上锁

 

       /* new-style driver? */

       //如果是新的风格,则直接跳到卸载部分

       if (is_newstyle_driver(driver))

              goto unregister;

 

       //旧的风格

       list_for_each(item1,       &adapters) {          //遍历适配器

              adap = list_entry(item1, struct i2c_adapter, list);

 

              //调用自定义的释放函数

              if (driver->detach_adapter) {

                     if (driver->detach_adapter(adap)) {

                            dev_err(&adap->dev, "detach_adapter failed "

                                   "for driver [%s]\n",

                                   driver->driver.name);

                     }

              } else {

                     list_for_each_safe(item2, _n, &adap->clients) {

                            client = list_entry(item2, struct i2c_client, list);

                            if (client->driver != driver)

                                   continue;

                            dev_dbg(&adap->dev, "detaching client [%s] "

                                   "at 0x%02x\n", client->name,

                                   client->addr);

                            if (driver->detach_client(client)) {

                                   dev_err(&adap->dev, "detach_client "

                                          "failed for client [%s] at "

                                          "0x%02x\n", client->name,

                                          client->addr);

                            }

                     }

              }

       }

 

//如果是新的风格,直接运行到这里

 unregister:

       driver_unregister(&driver->driver);            //注销设备

       list_del(&driver->list);                               //从链表中删除本选项

       pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);

 

       mutex_unlock(&core_lists);                        //解锁

}

EXPORT_SYMBOL(i2c_del_driver);

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

在卸载函数中调用

static int        ds1337_detach_client(struct i2c_client        *client)

{

       int err;

       struct ds1337_data        *data = i2c_get_clientdata(client);

 

       if ((err = i2c_detach_client(client)))

              return err;

 

       list_del(&data->list);            //从链表中删除

       kfree(data);                          //释放内存

       return 0;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

OK,我们回头按顺序看看其他一些函数:

 

//从函数名我们就知道,这个是读函数

static inline int      ds1337_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;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//这两个函数是DS1337特有的命令函数,所以这里略过(实际要分析,也无非是按规格书上的方法从一些寄存器中读取数据)

static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)

static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt)

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//这个函数最大的问题就是,如何在用户层调用…..

static int        ds1337_command(

       struct i2c_client     *client,

       unsigned int          cmd,

       void                     *arg)

{

       dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);

 

       switch (cmd) {

       case DS1337_GET_DATE:

              return ds1337_get_datetime(client, arg);

 

       case DS1337_SET_DATE:

              return ds1337_set_datetime(client, arg);

 

       default:

              return -EINVAL;

       }

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

int   ds1337_do_command(int bus,      int cmd,         void *arg)

{

       struct list_head      *walk;

       struct list_head      *tmp;

       struct ds1337_data *data;

 

       list_for_each_safe(walk, tmp, &ds1337_clients) {

              data = list_entry(walk, struct ds1337_data, list);

              if (data->client.adapter->nr == bus)

                     return     ds1337_command(&data->client, cmd, arg);

       }

 

       return     -ENODEV;

}

 

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

结束语:

 

       经过对DS1337代码的初步分析,虽然还有很多地方不是很清楚,但是我们基本已经知道了该如何修改类似的驱动了:

 

1、  static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
改为具体设备对应的IIC地址

2、  I2C_CLIENT_INSMOD_1(ds1337);
将ds1337改为具体设备的名字,后面的ds1337也做对应的修改

3、  修改ds1337_command中响应的命令,类似于IOCTL

4、  修改ds1337_detect,探测IIC设备时的调用函数,去掉多余的东西,然后修改ds1337_init_client,写上对应的初始化寄存器代码。

 

OK,没了,简单吧?

不过还有一个大问题没解决,就是ds1337_command在用户层该如何调用,本来是想先改好一个程序在挖的,现在看来,只有提前挖了,不然真不知道这个命令该在哪调用。

你可能感兴趣的:(c,list,struct,Module,command,byte)