刚开始学习宋的驱动详解,结合公司的板子原有的驱动程序,边学习边改造。
由于是具体的项目,没有采用标准的开发板,所以不多说了。
/* dm2016/saa7113.c
* 很多字符设备只是简单的open,close,read,write,需要添加函数使之更加安全
* add: private_date llseek() memory:kmalloc() fmalloc() verify_area() contain_of()
*/
/*
#ifdef MODULE
#include
#endif
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "hi_i2c.h"
#define EEPROM_ADDR_W 0xa4
#define EEPROM_ADDR_R 0xa5
unsigned char val[2];
unsigned char r_value[6];
#define EEPROM_SIZE 0x1000 /*全局内存最大4K字节*/
#define MEM_CLEAR 0x1 /*清0全局内存*/
#define EEPROM_MAJOR 254 /*预设的eeprom的主设备号*/
static eeprom_major = GLOBALMEM_MAJOR;
/*eeprom设备结构体*/
struct eeprom_dev
{
struct cdev cdev; /*cdev结构体*/
unsigned char mem[EEPROM_SIZE]; /*全局内存*/
};
struct eeprom_dev *eeprom_devp; /*设备结构体指针*/
/*文件打开函数*/
int eeprom_open(struct inode *inode, struct file *filp)
{
struct eeprom_dev *dev
/*获得设备结构体指针*/
dev = container_of(inode->i_dev,struct eeprom_dev,cdev);
/*将设备结构体指针赋值给文件私有数据指针*/
filp->private_data = eeprom_devp;
if(!try_module_get(THIS_MODULE)) return -ENODEV;
return 0;
}
/*文件释放函数*/
int eeprom_release(struct inode *inode, struct file *filp)
{
module_put(THIS_MODULE);
return 0;
}
/* ioctl设备控制函数 */
static int eeprom_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg)
{
struct eeprom_dev *dev = filp->private_data;/*获得设备结构体指针*/
switch (cmd)
{
case MEM_CLEAR:
memset(dev->mem, 0, EEPROM_SIZE);
printk(KERN_INFO "eeprom is set to zero\n");
break;
default:
return - EINVAL;
}
return 0;
}
/*读函数*/
/*ssize_t -- unsigned int*/
static ssize_t eeprom_read(struct file *filp, char __user *buf, size_t size, loff_t *offset)
{
r_value[0] = hi_i2c_read( EEPROM_ADDR_R, 0x00 );
r_value[1] = hi_i2c_read( EEPROM_ADDR_R, 0x01 );
r_value[2] = hi_i2c_read( EEPROM_ADDR_R, 0x02 );
r_value[3] = hi_i2c_read( EEPROM_ADDR_R, 0x03 );
r_value[4] = hi_i2c_read( EEPROM_ADDR_R, 0x04 );
r_value[5] = hi_i2c_read( EEPROM_ADDR_R, 0x05 );
unsigned long p = *offset;
unsigned int count = size;
int ret = 0;
struct eeprom_dev *dev = filp->private_data; /*获得设备结构体指针*/
/*分析和获取有效的写长度*/
if (p >= EEPROM_SIZE)
return count ? - ENXIO: 0;
if (count > EEPROM_SIZE - p)
count = EEPROM_SIZE - p;
/*判断用户空间的有效性*/
int err;
err = verify_area(VERIFY_WRITE,void(*) arg,size)
if(err < 0) return err;
/*内核空间->用户空间*/
if ( copy_to_user( buf, r_value, sizeof(r_value)))
{
printk(" copy to user error\n");
ret = - EFAULT;
return ret;
}
else
{
*offset += count;
ret = count;
printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
}
return ret;
}
/*写函数*/
static ssize_t eeprom_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset)
{
unsigned long p = *offset;
unsigned int count = size;
int ret = 0;
struct eeprom_dev *dev = filp->private_data; /*获得设备结构体指针*/
/*分析和获取有效的写长度*/
if (p >= EEPROM_SIZE)
return count ? - ENXIO: 0;
if (count > EEPROM_SIZE - p)
count = EEPROM_SIZE - p;
/*判断用户空间的有效性*/
int err;
err = verify_area(VERIFY_READ,void(*) arg,size)
if(err < 0) return err;
/*用户空间->内核空间*/
/*copy_from_user---- return 0: sucess ; return no zero: error*/
if (copy_from_user(val, buf, sizeof(buf)))
{
printk("\t Eeprom wrong cpy val is %0x, %0x\n",val[0],val[1]);
ret = - EFAULT;
}
else
{
*offset += count;
ret = count;
printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
}
printk("val[0]=%0x val[1]=%0x\n",val[0],val[1]);
if( hi_i2c_write( EEPROM_ADDR_W, val[0] ,val[1] ))
{
printk("i2c write error\n");
}
return ret;
}
/* seek文件定位函数 */
static loff_t eeprom_llseek(struct file *filp, loff_t offset, int orig)
{
loff_t ret = 0;
switch (orig)
{
case 0: /*相对文件开始位置偏移*/
if (offset < 0)
{
ret = - EINVAL;
break;
}
if ((unsigned int)offset > EEPROM_SIZE)
{
ret = - EINVAL;
break;
}
filp->f_pos = (unsigned int)offset;
ret = filp->f_pos;
break;
case 1: /*相对文件当前位置偏移*/
if ((filp->f_pos + offset) > EEPROM_SIZE)
{
ret = - EINVAL;
break;
}
if ((filp->f_pos + offset) < 0)
{
ret = - EINVAL;
break;
}
filp->f_pos += offset;
ret = filp->f_pos;
break;
default:
ret = - EINVAL;
break;
}
return ret;
}
/*文件操作结构体*/
static const struct file_operations eeprom_fops =
{
.owner = THIS_MODULE,
.llseek = eeprom_llseek,
.read = eeprom_read,
.write = eeprom_write,
.ioctl = eeprom_ioctl,
.open = eeprom_open,
.release = eeprom_release,
};
static int eeprom_device_init(void)
{
printk("into eeprom device init\n");
return 0;
}
/*初始化并注册cdev*/
static void eeprom_setup_cdev(struct eeprom_dev *dev, int index)
{
int err, devno = MKDEV(eeprom_major, index);
cdev_init(&dev->cdev, &eeprom_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &eeprom_fops;
err = cdev_add(&dev->cdev, devno, 1);
if (err)
printk(KERN_NOTICE "Error %d adding EEPROM%d", err, index);
}
/*设备驱动模块加载函数*/
static int __init eeprom_init(void)
{
int result = 0;
dev_t devno = MKDEV(eeprom_major, 0);
/* 申请设备号*/
if (eeprom_major)
result = register_chrdev_region(devno,1,"eeprom");
else /* 动态申请设备号 */
{
result = alloc_chrdev_region(&devno, 0, 1, "eeprom");
eeprom_major = MAJOR(devno);
}
if(result)
{
printk("could not register eeprom devices. \n");
return result;
}
if (result < 0)
return result;
/* 动态申请设备结构体的内存*/
eeprom_devp = kmalloc(sizeof(struct eeprom_dev), GFP_KERNEL);
if (!eeprom_devp) /*申请失败*/
{
result = - ENOMEM;
goto fail_malloc;
}
memset(eeprom_devp, 0, sizeof(struct eeprom_dev));
eeprom_setup_cdev(eeprom_devp, 0);
return 0;
fail_malloc: unregister_chrdev_region(devno, 1);
return result;
if(eeprom_device_init()!=0)
{
unregister_chrdev_region(MKDEV(eeprom,0),1)
printk("eeprom driver init fail for device init error!\n");
return -1;
}
printk("eeprom driver init successful!\n");
return ret;
}
/*模块卸载函数*/
static void __exit eeprom_exit(void)
{
cdev_del(&eeprom_devp->cdev); /*注销cdev*/
kfree(eeprom_devp); /*释放设备结构体内存*/
unregister_chrdev_region(MKDEV(eeprom,0),1);/*释放设备号*/
}
MODULE_INFO(build, UTS_VERSION);
MODULE_AUTHOR("yu chuan");
MODULE_LICENSE("Dual BSD/GPL");
module_param(eeprom_major, int, S_IRUGO);
module_init(eeprom_init);
module_exit(eeprom_exit);
这个和宋的模板很像吧,的确,其实本来驱动就是这样的,用宋的话:点面结合,框架学习更重要!
下一步增加并发处理