易网时代-编程资源站
Welcome
微信登录
编程资源
图片资源库
蚂蚁家优选
PDF转换器
软件资源
软件开发
、
小程序制作
、
系统集成与运维
、
空间租用
、
硬件开发
、
视频监控
、
技术咨询与支持
——联系电话:0311-88999002/88999003
首页
/
操作系统
/
Linux
/
字符设备驱动模块 之 基本通用模块
字符设备驱动模块 之 基本通用模块
#include
<linux
/module.h
>
#include
<linux
/types.h
>
#include
<linux
/fs.h
>
#include
<linux
/errno.h
>
#include
<linux
/mm.h
>
#include
<linux
/sched.h
>
#include
<linux
/init.h
>
#include
<linux
/cdev.h
>
#include
<asm
/io.h
>
#include
<asm
/system.h
>
#include
<asm
/uaccess.h
>
#include
<linux
/device.h
>
/* device_create()*/
#define ADC_SIZE 0x1000 /*全局内存最大4K字节*/
#define MEM_CLEAR 0x1 /*清0全局内存*/
#define ADC_MAJOR 250 /*预设的adc的主设备号*/
static int
adc_major
=
ADC_MAJOR
;
/*adc设备结构体*/
struct adc_dev {
struct cdev cdev; /*cdev结构体*/
unsigned char mem[ADC_SIZE]; /*全局内存*/
};
struct adc_dev *adc_devp; /*设备结构体指针*/
/*文件打开函数*/
int adc_open(struct inode *inode, struct file *filp)
{
/*将设备结构体指针赋值给文件私有数据指针*/
filp-
>
private_data
=
adc_devp
;
return 0;
}
/*文件释放函数*/
int adc_release(struct inode *inode, struct file *filp)
{
return 0;
}
/* ioctl设备控制函数 */
static int adc_ioctl(struct inode *inodep, struct file *filp, unsigned
int cmd, unsigned long arg)
{
struct adc_dev *
dev
=
filp
-
>
private_data;/*获得设备结构体指针*/
switch (cmd) {
case MEM_CLEAR:
memset(dev-
>
mem, 0, ADC_SIZE);
printk(KERN_INFO "adc is set to zero ");
break;
default:
return - EINVAL;
}
return 0;
}
/*读函数*/
static ssize_t adc_read(struct file *filp, char __user *buf, size_t size,
loff_t *ppos)
{
unsigned long
p
= *ppos;
unsigned int
count
=
size
;
int
ret
=
0
;
struct adc_dev *
dev
=
filp
-
>
private_data; /*获得设备结构体指针*/
/*分析和获取有效的写长度*/
if (p
>
= ADC_SIZE)
return 0;
if (count
>
ADC_SIZE - p)
count
=
ADC_SIZE
- p;
/*内核空间-
>
用户空间*/
if (copy_to_user(buf, (void *)(dev-
>
mem + p), count)) {
ret
= - EFAULT;
} else {
*ppos += count;
ret
=
count
;
printk(KERN_INFO "read %u bytes(s) from %lu ", count, p);
}
return ret;
}
/*写函数*/
static ssize_t adc_write(struct file *filp, const char __user *buf,
size_t size, loff_t *ppos)
{
unsigned long
p
= *ppos;
unsigned int
count
=
size
;
int
ret
=
0
;
struct adc_dev *
dev
=
filp
-
>
private_data; /*获得设备结构体指针*/
/*分析和获取有效的写长度*/
if (p
>
= ADC_SIZE)
return 0;
if (count
>
ADC_SIZE - p)
count
=
ADC_SIZE
- p;
/*用户空间-
>
内核空间*/
if (copy_from_user(dev-
>
mem + p, buf, count))
ret
= - EFAULT;
else {
*ppos += count;
ret
=
count
;
printk(KERN_INFO "written %u bytes(s) from %lu ", count, p);
}
return ret;
}
/* seek文件定位函数 */
static loff_t adc_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
>
ADC_SIZE) {
ret
= - EINVAL;
break;
}
filp-
>
f_pos
= (unsigned int)offset;
ret
=
filp
-
>
f_pos;
break;
case 1: /*相对文件当前位置偏移*/
if ((filp-
>
f_pos + offset)
>
ADC_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
adc_fops
= {
.owner
=
THIS_MODULE
,
.llseek
=
adc_llseek
,
.read
=
adc_read
,
.write
=
adc_write
,
.ioctl
=
adc_ioctl
,
.open
=
adc_open
,
.release
=
adc_release
,
};
/*初始化并注册cdev*/
static void adc_setup_cdev(struct adc_dev *dev, int index)
{
int err,
devno
=
MKDEV
(adc_major, index);
cdev_init(&dev-
>
cdev, &adc_fops);
dev-
>
cdev.owner
=
THIS_MODULE
;
err
=
cdev_add
(&dev-
>
cdev, devno, 1);
if (err)
printk(KERN_NOTICE "Error %d adding LED%d", err, index);
}
struct class *myclass;
/*设备驱动模块加载函数*/
int adc_init(void)
{
int result;
dev_t
devno
=
MKDEV
(adc_major, 0);
/* 申请设备号*/
if (adc_major)
result
=
register_chrdev_region
(devno, 1, "adc");
else { /* 动态申请设备号 */
result
=
alloc_chrdev_region
(&devno, 0, 1, "adc");
adc_major
=
MAJOR
(devno);
}
if (result
<
0
)
return result;
/* 动态申请设备结构体的内存*/
adc_devp
=
kmalloc
(sizeof(struct adc_dev), GFP_KERNEL);
if (!adc_devp) { /*申请失败*/
result
= - ENOMEM;
goto fail_malloc;
}
memset(adc_devp, 0, sizeof(struct adc_dev));
adc_setup_cdev(adc_devp, 0);
/*自动创建设备文件*/
myclass
=
class_create
(THIS_MODULE,"test_char"); /*在sys下创建类目录/sys/class/test_char*/
device_create(myclass, NULL, MKDEV(adc_major,0), NULL, "adc");
return 0;
fail_malloc:
unregister_chrdev_region(devno, 1);
return result;
}
/*模块卸载函数*/
void adc_exit(void)
{
cdev_del(&adc_devp-
>
cdev); /*注销cdev*/
kfree(adc_devp); /*释放设备结构体内存*/
unregister_chrdev_region(MKDEV(adc_major, 0), 1); /*释放设备号*/
class_destroy(myclass);
device_destroy(myclass,MKDEV(adc_major,0));
}
MODULE_AUTHOR("Barry Song
<21cnbao
@gmail.com
>
");
MODULE_LICENSE("Dual BSD/GPL");
module_param(adc_major, int, S_IRUGO);
module_init(adc_init);
module_exit(adc_exit);
用户程序:
#include
<stdio.h>
#include
<stdlib.h>
#include
<fcntl.h>
#include
<unistd.h>
#include
<string.h>
int main()
{
int fd;
char buf[4096];
strcpy(buf,"Mem is char dev!");
printf("Buf: %s ",buf);
fd
=
open
("/dev/adc",O_RDWR);
if(fd
<0
)
{
printf("open failed! ");
return -1;
}
else
printf("open /dev/adc is success! ");
if(write(fd,buf,sizeof(buf))
<0
)
{
printf("write failed! ");
return -1;
}
else
printf("write: %s ",buf);
lseek(fd,0,SEEK_SET);
strcpy(buf,"Buf is NULL! ");
printf("Buf: %s ",buf);
read(fd,buf,sizeof(buf));
printf("Buf: %s ",buf);
return 0;
收藏该网址
版权所有©石家庄振强科技有限公司2024
冀ICP备08103738号-5
网站地图