1-->修改板级文件arch/arm/mach-s3c2440/mach-mini2440.c
步骤: 1->添加引用 #include <linux/i2c.h> 2->添加IIC设备信息 static struct i2c_board_info i2c_devices[] __initdata = { {I2C_BOARD_INFO("at24c08", 0x50),}, /* 设备名称,设备地址 */ }; 3->在mini2440_machine_init(void)添加函数 i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); /* 注册板级设备:总线数量,设备信息,设备数量 */
2-->驱动文件at24c08.c
#include <linux/init.h> #include <linux/module.h> #include <linux/stat.h> #include <linux/device.h> #include <linux/kdev_t.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/i2c.h> #include <asm/uaccess.h> /* copy_to_user & copy_from_user */ #define AT24C08MAJOR 155 /* 预定义主设备号,如果有冲突,则使用alloc_devno */ static struct i2c_driver at24c08_driver; /* 设备驱动 */ /*static struct i2c_adapter *at24c08_adapter; 设备适配器 */ static struct i2c_client *at24c08_client; /* i2c设备 */ static unsigned short addr = 0x50; /* i2c设备地址 */ static dev_t alloc_devno; /* 动态申请的设备号 */ static struct class at24c08_class = { .name = "at24c08_class", }; /* at24c08读函数用户给出要读取的地址=args;读取数据后放到data中,再返回给用户 */ static ssize_t at24c08_read(struct file *filp, char __user *buffer, size_t size, loff_t *off) { struct i2c_msg msg[2]; /* 封装消息 */ unsigned char args; /* 参数和数据 */ unsigned char data; /* 要返回的数据 */ if(size != 1) { return -EINVAL; } /* 从用户空间读取一个参数赋值给args,也就是把要读取的地址传递给内核,args就是要读取的地址,由用户给出 */ copy_from_user(&args, buffer, 1); /* 封装消息->先写地址,再读取数据,一共2次通讯 */ msg[0].addr = addr; /* 设备地址 */ msg[0].buf = &args; /* 要读取的地址 */ msg[0].len = 1; /* 消息的长度 */ msg[0].flags = 0; /* 标志位,写0读1 */ /* 再读 */ msg[1].addr = addr; msg[1].buf = &data; /* 接收读取的数据 */ msg[1].len = 1; /* 要读取的数据长度 */ msg[1].flags = I2C_M_RD; /* 读 */ /* 与目标设备进行2次通讯 */ if(i2c_transfer(at24c08_client->adapter, msg, 2) == 2) { /* 返回2,表示成功通讯2次 */ copy_to_user(buffer, &data, 1); printk(KERN_INFO "at24c08_read succeedn"); return 1; } else { printk(KERN_INFO "at24c08_read failedn"); return -EIO; } } /* at24c08写函数 */ static ssize_t at24c081_write(struct file *filp, const char __user *buffer, size_t size, loff_t *off) { struct i2c_msg msg[1]; unsigned char args[2]; /* args:保存从用户空间过来的数据 *buffer:用户空间的数据,包含了要写入的地址和药写入的数据*2:字节数 */ printk(KERN_INFO "at24c08_write......n"); copy_from_user(&args, buffer, 2); /* 成功返回0;失败返回未完成字节数 */ printk(KERN_INFO "write parameters : args[0] = 0x%x, args[1] = 0x%xn", args[0], args[1]); /* args[0]:addr, args[1]:value */ msg[0].addr = addr; /* 设备地址 */ msg[0].buf = args; /* 写入的数据 */ msg[0].len = 2; /* 长度 */ msg[0].flags = at24c08_client->flags & I2C_M_TEN; /* 写标志 */ if(i2c_transfer(at24c08_client->adapter, msg, 1) == 1) { printk(KERN_INFO "at24c08_write succeedn"); return 2; } else { printk(KERN_INFO "at24c08_write failedn"); return -EIO; } } int at24c08_open(struct inode *inode, struct file *filp) { printk(KERN_INFO "at24c08 openn"); return 0; } /* at24c08操作集 */ static struct file_operations at24c08_fops = { .owner = THIS_MODULE, .read = at24c08_read, .write = at24c081_write, .open = at24c08_open, }; static struct cdev i2c_cdev; /* at24c08设备文件 */ /* 设备初始化 */ static int at24c08_probe(struct i2c_client *client, const struct i2c_device_id *i2c_device) { int result; result = register_chrdev_region(AT24C08MAJOR, 1, "at24c08"); /* 申请字符设备主设备号 */ if(result < 0) { printk(KERN_WARNING "register major number [%d] failed!n", AT24C08MAJOR); alloc_chrdev_region(&alloc_devno, 0, 1, "at24c08"); printk(KERN_INFO "alloc device number : major:[%d], minor:[%d] succeed!n", MAJOR(alloc_devno), MINOR(alloc_devno)); } else printk(KERN_INFO "register device number : major:[%d], minor:[0] succeed!n", AT24C08MAJOR); cdev_init(&i2c_cdev, &at24c08_fops); cdev_add(&i2c_cdev, MKDEV(AT24C08MAJOR, 0), 1); /* 向系统注册字符设备文件,此时还未创建 */ class_register(&at24c08_class); /* 设备总线类别 */ device_create(&at24c08_class, NULL, MKDEV(AT24C08MAJOR, 0), NULL, "at24c08"); /* 创建at24c08字符设备文件 */ printk(KERN_INFO "create device file 'at24c08' succeed!n"); at24c08_client = client; printk(KERN_INFO "get i2c_client, client name = %s, addr = 0x%xn", at24c08_client->name, at24c08_client->addr); printk(KERN_INFO "get i2c_adapter, adapter name = %sn", at24c08_client->adapter->name); printk(KERN_INFO "at24c08 probe()n"); return 0; } /* 移除设备 */ static int at24c08_remove(struct i2c_client *client) { device_destroy(&at24c08_class, MKDEV(AT24C08MAJOR, 0)); /* 删除设备 */ class_destroy(&at24c08_class); /* 移除设备类别 */ cdev_del(&i2c_cdev); unregister_chrdev_region(MKDEV(AT24C08MAJOR, 0), 1); printk(KERN_INFO "at24c08 remove()n"); return 0; } /* 设备检测函数 */ static int at24c08_detect(struct i2c_client *client, int kind, struct i2c_board_info *i2c_bd_info) { printk(KERN_INFO "do nothing, at24c08 detect()n"); return 0; } /* i2c设备id列表 */ static const struct i2c_device_id at24c08_id[] = { { "at24c08", 0 }, { } /* 最后一个必须为空,表示结束 */ }; static unsigned short ignore[] = { I2C_CLIENT_END }; static const unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END }; static const struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .probe = ignore, .ignore = ignore, }; static struct i2c_driver at24c08_driver = { .probe = at24c08_probe, .remove = at24c08_remove, .driver = { .name = "at24c08", /* 驱动名称 */ .owner = THIS_MODULE, }, .id_table = at24c08_id, /* id列表 */ .detect = at24c08_detect, .address_data = &addr_data, .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, /* 这些都是什么? */ }; static int __init at24c08_init(void) { i2c_add_driver(&at24c08_driver); /* 将i2c_driver注册到系统中去 */ printk(KERN_INFO "at24c08 i2c_driver was added into the system.n"); return 0; } static void __exit at24c08_exit(void) { i2c_del_driver(&at24c08_driver); printk(KERN_INFO "at24c08 i2c_driver was deleted from the system.n"); return ; } module_init(at24c08_init); module_exit(at24c08_exit); MODULE_AUTHOR("edison ren"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("at24c08 device driver, 2016-10-08");
3-->应用程序
/* 配套的应用程序app.c */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <sys/types.h> #include <sys/ioctl.h> #include <linux/i2c.h> #include <linux/i2c-dev.h> #include <linux/types.h> #define i2c_dev "/dev/at24c08" int main(void) { int fd, count = 0; fd = open(i2c_dev, O_RDWR); unsigned char rbuffer; /* 读取的数据:片内地址+1个数据 */ rbuffer = 0x08; /* 片内地址 */ unsigned char wbuffer[2]; /* 片内地址+h */ wbuffer[0] = 0x08; /* 片内地址 */ wbuffer[1] = 'h'; if(fd < 0) { printf("open %s failed!n", i2c_dev); exit(1); } else { printf("open %s succeed!n", i2c_dev); printf("#####################################"); count = read(fd, &rbuffer, 1); if(count > 0) printf("read data succeed, data = [%d].n", rbuffer); rbuffer = 0x08; printf("#####################################"); printf("write ...n"); count = write(fd, wbuffer, 2); if(count > 0) printf("write data succeed, write data count = %d.n", count); else { printf("write data failed, write data count = %d.n", count); exit(1); } printf("#####################################"); count = read(fd, &rbuffer, 1); printf("read ...n"); if(count > 0) printf("read data succeed, data = [%d].n", rbuffer); } } /* 连续读和写app2.c */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <sys/types.h> #include <sys/ioctl.h> #include <linux/i2c.h> #include <linux/i2c-dev.h> #include <linux/types.h> #define i2c_dev "/dev/at24c08" int main(void) { int fd, i = 0, count = 0; fd = open(i2c_dev, O_RDWR); unsigned char rbuffer; /* 读取的数据:片内地址+1个数据 */ unsigned char address[5]; address[0] = 0x05; address[1] = 0x06; address[2] = 0x07; address[3] = 0x08; address[4] = 0x09; unsigned char data[5] = {'h', 'e', 'l', 'l', 'o'}; unsigned char wbuffer[2]; /* 片内地址+h */ if(fd < 0) { printf("open %s failed!n", i2c_dev); exit(1); } else { printf("open %s succeed!n", i2c_dev); printf("n#####################################n"); for(i = 0; i < 5; i++) { rbuffer = address[i]; read(fd, &rbuffer, 1); printf("-0x[%x]-", rbuffer); } printf("n#####################################n"); for(i = 0; i < 5; i++) { wbuffer[0] = address[i]; wbuffer[1] = data[i]; write(fd, wbuffer, 2); } printf("n#####################################n"); for(i = 0; i < 5; i++) { rbuffer = address[i]; read(fd, &rbuffer, 1); printf("-0x[%x]-", rbuffer); } printf("n"); } }
4-->Makefile
ifneq ($(KERNELRELEASE),) obj-m := at24c08.o else #KDIR := /lib/modules/2.6.18-53.el5/build KDIR := /home/edison/linux-kernel/linux-2.6.32.2 all: make -C $(KDIR) M=$(PWD) modules arch=arm cross_compile=arm-linux- clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order *.ko.unsigned endif
当然也可以将驱动文件添加到对应的内核文件中,通过修改对应的KConfig和Makefile来将驱动编译到内核中
内容来源于网络如有侵权请私信删除
文章来源: 博客园
- 还没有人评论,欢迎说说您的想法!