tq2440下的i2c驱动at24c02

好想哭,写了2个多小时的文章一下因为没保存一下弄没了,,,算了,主要是关于i2c驱动的,,把代码粘上来算了,,哭吧
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/kdev_t.h>
#include <linux/notifier.h>
#include <linux/genhd.h>
#include <linux/kallsyms.h>
#include <linux/semaphore.h>
#include <linux/mutex.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/errno.h>
/*1..分配i2c_driver   */
/*2..设置i2c_driver   */
#define at24cxx_EEPROM_SIZE		8

#define AT24C02_MAJOR  250  //设备的主设备号
#define DEBUG 1            //调试打印控制开关

static int at24c02_major = AT24C02_MAJOR;
/*声明at24c02结构体
*管理24c02的设备信息,,client信息等
*/
struct at24c02_dev
{
struct i2c_client *client;
unsigned int addr;
char name[30];
unsigned short current_pointer;//当前读写地址
struct cdev cdev;//cdev结构,,最后要注册它为字符设备
};
struct at24c02_dev *at24c02_devp;

static int at24c02_open(struct inode *inode,struct file *filp)
{
filp->private_data=at24c02_devp;//打开函数,这个函数可以写可以不写,不写的话系统会有默认的open函数
printk("at24c02_open is called\n");//这个函数的作用在于,当执行这个函数时
#if DEBUG                         // file *filp被传入属于本驱动的结构at24c02_devp
printk(KERN_NOTICE"open decvice is called\n");  //这个函数没有也可以的,,????
#endif  
return 0;  
}

static ssize_t at24c02_read(struct file *filp, char __user *buf, size_t size,loff_t *ppos) 
{
int transferred = 0;  //读到的字节个数
unsigned char my_buff[512]={0}; //读缓冲区
unsigned char ret=0;
int i = 0; 
/* 取出驱动结构,因为前面open函数里给filp赋值了*/
struct at24c02_dev *dev = (struct at24c02_dev *)filp->private_data; 
copy_from_user(my_buff,buf,1);
//dev->current_pointer = *ppos; //属于当前的读地址位置 
dev->current_pointer = my_buff[0];//这个地方根据程序需要改了下
/*检测adapter是否支持读写功能  
*start inline int i2c_check_functionality(struct adapter*adp,u32 func)  
*/
if(i2c_check_functionality(dev->client->adapter,I2C_FUNC_SMBUS_READ_BYTE_DATA))  
{  
while(transferred < size)
{  
/*s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command);*/  
/*将会调用i2c_smbus_xfer*/  
/*smbus读函数,读的设备为dev->client设备地址,设备名字,设备采用的算法,属于
的适配器都在client结构中,读的地址为current_pointer +i,会随着i的增加而增加*/ 
ret = i2c_smbus_read_byte_data(dev->client,dev->current_pointer +i);  
my_buff[i++] = (unsigned char) ret;  //返回读到的值,赋给缓冲数组  
transferred +=1;  
#if DEBUG  
printk(KERN_NOTICE"the my_buff[%d] is %x,transferred is %d\n",i,my_buff[i--],transferred);  
#endif  
  
}  
/* 从内核拷贝数据到用户空间*/
copy_to_user(buf,(void *)my_buff,transferred); 
dev->current_pointer += transferred; //记录数据读写位置 
}	
return transferred;
}
static ssize_t at24c02_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos) 
{
int i = 0;  
int transferred = 0;  //成功写的字节个数
int ret;  
unsigned char my_buff[512];  //写缓冲区
/* 取出驱动结构,因为前面open函数里给filp赋值了*/
struct at24c02_dev *dev = (struct at24c02_dev *)filp->private_data;  
/*初始写位置*/
dev->current_pointer = *ppos;  
/*检测adapter是否支持读写功能  
*start inline int i2c_check_functionality(struct adapter*adp,u32 func)  
*/
if(i2c_check_functionality(dev->client->adapter,I2C_FUNC_SMBUS_BYTE_DATA))
{
	/*从用户空间拷贝数据到内核空间*/
copy_from_user(my_buff,buf,size);
dev->current_pointer=my_buff[0];
/*因为读的时候有一个是地址所以-1*/
while(transferred<(size-1))
{
	/*s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command);*/  
/*将会调用i2c_smbus_xfer*/  
/*smbus写函数,写的设备为dev->client设备地址,设备名字,设备采用的算法,属于
的适配器都在client结构中,写的地址为current_pointer +i,会随着i的增加而增加*/
ret=i2c_smbus_write_byte_data(dev->client, dev->current_pointer+i, my_buff[i+1]);
#if DEBUG  
printk(KERN_NOTICE"write data %d-----my_buff%x\n",i,my_buff[i+1]);  
#endif
i+=1;
transferred +=1; 
}
dev->current_pointer +=transferred; 
}
return transferred;
}	
/*io命令控制函数*/
static int at24c02_ioctl(struct inode *inodep,struct file *filp,unsigned int cmd,unsigned long arg)  
{  
return 0;  
}  
/*设备释放函数,,在什么时候这个函数会执行?????*/
static int at24c02_release(struct inode*inodep,struct file *filp)  
{  
filp->private_data = NULL;  
return 0;  
}  
/*驱动中很重要的结构,注册一个驱动时就是把这个结构体中包含的
函数指针赋给设备节点结构???*/
static const struct file_operations at24c02_fops=
{
.owner = THIS_MODULE,
.open=at24c02_open,
.read=at24c02_read,
.write=at24c02_write,
.ioctl=at24c02_ioctl,
.release=at24c02_release,
};
/*创建字符设备函数,,完成字符设备文件的注册*/
static void at24c02_setup_cdev(struct at24c02_dev *dev, int index)
{
	/*MKDEV(ma,mi)	(((ma) << MINORBITS) | (mi))
产生其主设备号*/
int err, devnum = MKDEV(at24c02_major, index);  
#if DEBUG  
printk(KERN_NOTICE"the devnum is %d\n",devnum);  
#endif  
/*  初始化一个cdev结构主要是,并添加操作函数集 
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops;
*/
cdev_init(&dev->cdev, &at24c02_fops);
dev->cdev.owner = THIS_MODULE;
 /*由上面的分析可知,这句话多余了
cdev_init函数里已经绑定了这个结构
*/
dev->cdev.ops = &at24c02_fops;
/* add a char device to the system
增加一个字符设备到系统
具体怎么加入的明天老师也许会讲
*/
err = cdev_add(&dev->cdev, devnum, 1);  
if (err)  
printk(KERN_NOTICE"Error %d adding at24c02 %d", err, index);
}
static struct class *at24cxx_class;
/*
 * Called when a at24c02 device is matched with this driver
 */
static int __devinit at24cxx_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
int ret;  
 
printk(KERN_NOTICE"at24c02 probe \n");  

/*主设备号*/
dev_t devnum = MKDEV(at24c02_major,0); 
if (at24c02_major)  
{  
	/*如果定义了主设备号,那么就手动注册
register a range of device numbers
第二个参数代表几个设备号
从devnum开始的几个设备号
 __register_chrdev_region
*/
ret = register_chrdev_region(devnum,1,"at24c02");  
}  
else  
{  
	/*动态分配设备号到&devnum
从0号开始分配一个设备
*/
ret = alloc_chrdev_region(&devnum,0,1,"at24c02");  
}  
if(ret < 0)  
return ret; 
#if DEBUG  
printk(KERN_NOTICE"device number is read\n");  
#endif 
/*动态分配内存
返回值为分配的内存的地址*/
at24c02_devp=kmalloc(sizeof(struct at24c02_dev),GFP_KERNEL);

if(!at24c02_devp)
{
ret=-ENOMEM;
goto fail_malloc;
}
#if DEBUG  
printk(KERN_NOTICE"kmalloc is read\n");  
#endif
/*设置这块内存值为0*/
memset(at24c02_devp,0,sizeof(struct at24c02_dev));
/*绑定设备到本模块的结构体*/
at24c02_devp->client=client;
/*创建字符设备*/
at24c02_setup_cdev(at24c02_devp,0);
/*create a struct class structure
This is used to create a struct class pointer that can then be used
 in calls to device_create().
*/
at24cxx_class = class_create(THIS_MODULE, "at24c02");
/*判断返回的这个类结构是否是错误的*/
if (IS_ERR(at24cxx_class))
return  -1;
/*creates a device and registers it with sysfs
*/
device_create(at24cxx_class, NULL, MKDEV(at24c02_major,0), NULL, "at24c02");

return 0;

fail_malloc: 
	 /*This function will unregister a range of @count device numbers,*/
unregister_chrdev_region(devnum,1);  
#if DEBUG  
printk(KERN_NOTICE"fail_malloc\n");  
#endif  
return ret;  
}		


 
static int __devexit at24cxx_remove(struct i2c_client *client)
{
	/*removes a device that was created with device_create()*/
device_destroy(at24cxx_class,MKDEV(at24c02_major,0));
/*destroys a struct class structure*/
class_destroy(at24cxx_class);
/*remove a cdev from the system*/
cdev_del(&at24c02_devp->cdev);  
/*free previously allocated memory
Don't free memory not originally allocated by kmalloc()
or you will run into trouble.
*/
kfree(at24c02_devp);  
/*This function will unregister a range of @count device numbers,
 * starting with @from. 
 */
unregister_chrdev_region(MKDEV(at24c02_major,0),1);
return 0;
}
/*由于一个i2c驱动可以用于多个设备,所以建一个设备表
驱动会根据这个表与适配器上挂载的设备名进行匹配
*/
static const struct i2c_device_id at24cxx_id[] = {
	{ "at24c02", 0 },
	{ }
};
/*一般在声明这种表时,都会加这一句
*/
MODULE_DEVICE_TABLE(i2c,at24cxx_id); 
static struct i2c_driver at24c02_driver = {
	.driver = {
		.name	= "at24cxx",
                .owner =THIS_MODULE,
	},
	.probe		= at24cxx_probe,
	.remove		=  __devexit_p(at24cxx_remove),
	.id_table	= at24cxx_id,

	/*.detect		= at24cxx_detect,
	.address_data	= &addr_data,  */
};
/*模块加载函数,,可能需要加__init标记为特殊函数
有待于研究*/
static  int __init at24cxx_init(void)
{
 
#if DEBUG  
printk(KERN_NOTICE"at24c02  is insmod\n");  
#endif  
/*  There
 * are two models for binding the driver to its device:  "new style" drivers
 * follow the standard Linux driver model and just respond to probe() calls
 * issued if the driver core sees they match(); "legacy" drivers create device
 * nodes themselves.*/
return i2c_add_driver(&at24c02_driver);

}
/*模块加载函数,,可能需要加__exit标记为特殊函数
有待于研究*/
static  void __exit at24cxx_exit(void)
{
	/*i2c_del_driver - unregister I2C driver*/
i2c_del_driver(&at24c02_driver);  
#if DEBUG  
printk(KERN_NOTICE"at24c02 is rmmod\n");  
#endif  
return ;
}
module_init(at24cxx_init);
module_exit(at24cxx_exit);
MODULE_LICENSE("GPL");

有了驱动程序后还需要注册设备,,,注册设备据说有两种方法,,第一种,,在板级文件中添加
static struct i2c_board_info i2c_devices[]  __initdata={
{
I2C_BOARD_INFO("at24c02",0x50),
},
};
smdk2440_machine_init(void)
{
.......................................
i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices));
}
我的不知道怎么回事这样做不行,,,现在还没弄懂为什么不行,,求教大师,,,,
第二种方法,,再写一个模块程序,注册设备到i2c总线,代码如下
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/kdev_t.h>
#include <linux/notifier.h>
#include <linux/genhd.h>
#include <linux/kallsyms.h>
#include <linux/semaphore.h>
#include <linux/mutex.h>
#include <linux/i2c.h>

static struct i2c_board_info at24cxx_info = {	
	I2C_BOARD_INFO("at24c02", 0x50),
};

static struct i2c_client *at24cxx_client;

static int at24cxx_dev_init(void)
{
	struct i2c_adapter *i2c_adap;
    printk(KERN_NOTICE"at24c02 device is insmod\n"); 
	i2c_adap = i2c_get_adapter(0);
	at24cxx_client = i2c_new_device(i2c_adap, &at24cxx_info);
	i2c_put_adapter(i2c_adap);
	
	return 0;
}

static void at24cxx_dev_exit(void)
{
    printk(KERN_NOTICE"at24c02 device is rmmod\n"); 
	i2c_unregister_device(at24cxx_client);
}
module_init(at24cxx_dev_init);
module_exit(at24cxx_dev_exit);
MODULE_LICENSE("GPL");

编译后,,加载两个模块即可

测试程序
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>
/*at24cxx_app r addr
*at24cxx_app w addr val
*/

void print_usage(char *file)
{
printf("%s r addr\n",file);
printf("%s w addr val \n",file);
}
int main(int argc,char **argv)
{
int fd;
unsigned char buf[2];
if((argc!=3)&&(argc!=4))
{
print_usage(argv[0]);
return -1;
}
fd =open("/dev/at24c02",O_RDWR);

if(fd<0)
{
printf("can't open /dev/at24cxx\n");
return -1;
}
if((strcmp(argv[1],"r"))==0)
{
buf[0]=strtoul(argv[2],NULL,0);
read(fd,buf,1);
printf("data:%c,%d,0x%2x\n",buf[0],buf[0],buf[0]);
}
else if((strcmp(argv[1],"w"))==0)
{
buf[0]=strtoul(argv[2],NULL,0);
buf[1]=strtoul(argv[3],NULL,0);
write(fd,buf,2);

}
else
{

printf("it is wrong");
}
return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值