第一部分 字符设备驱动程序
1.1 函数scull_open()
int scull_open(struct inode *inode,struct file *filp) {
MOD_INC_USE_COUNT; // 增加该模块的用户数目
printk(“This chrdev is in open\n”);
return 0;
}
1.2 函数scull_write()
int scull_write(struct inode *inode,struct file *filp,const char *buffer,int count) {
if(count < 0)
return –EINVAL;
if(scull.usage || scull.new_msg)
return –EBUSY;
scull.usage = 1;
kfree(scull.data);
data = kmalloc(sizeof(char)*(count+1),GFP_KERNEL);
if(!scull.data) {
return –ENOMEM;
}
copy_from_user(scull.data,buffer,count + 1);
scull.usage = 0;
scull.new_msg = 1;
return count;
}
1.3 函数scull_read()
int scull_read(struct inode *inode,struct file *filp,char *buffer,int count) {
int length;
if(count < 0)
return –EINVAL;
if(scull.usage)
return –EBUSY;
scull.usage = 1;
if(scull.data == 0)
return 0;
length = strlen(scull.data);
if(length < count)
count = length;
copy_to_user(buf,scull.data,count + 1);
scull.new_msg = 0;
scull.usage = 0;
return count;
}
1.4 函数scull_ioctl()
#include
#define SCULL_MAJOR 0
#define SCULL_MAGIC SCULL_MAJOR
#define SCULL_RESET _IO(SCULL_MAGIC,0) // reset the data
#define SCULL_QUERY_NEW_MSG _IO(SCULL_MAGIC,1) // check for new message
#define SCULL_QUERY_MSG_LENGTH _IO(SCULL_MAGIC,2) //get message length
#define IOC_NEW_MSG 1
static int usage,new_msg; // control flags
static char *data;
int scull_ioctl(struct inode *inode,struct file *filp,unsigned long int cmd,unsigned long arg) {
int ret=0;
switch(cmd) {
case SCULL_RESET:
kfree(data);
data = NULL;
usage = 0;
new_msg = 0;
break;
case SCULL_QUERY_NEW_MSG:
if(new_msg)
return IOC_NEW_MSG;
break;
case SCULL_QUERY_MSG_LENGTH:
if(data == NULL){
return 0;
}
else {
return strlen(data);
}
break;
default:
return –ENOTTY;
}
return ret;
}
1.5 函数scull_release()
void scull_release(struct inode *inode,struct file *filp) {
MOD_DEC_USE_COUNT; // 该模块的用户数目减1
printk(“This chrdev is in release\n”);
return 0;
#ifdef DEBUG
printk(“scull_release(%p,%p)\n”,inode,filp);
#endif
}
1.6 测试函数
在该字符设备驱动程序编译加载后,再在/dev目录下创建字符设备文件chrdev,使用命令: #mknod /dev/chrdev c major minor ,其中“c”表示chrdev是字符设备,“major”是chrdev的主设备号。(该字符设备驱动程序编译加载后,可在/proc/devices文件中获得主设备号,或者使用命令: #cat /proc/devices | awk ”\\$2==”chrdev\”{ print\\$1}” 获得主设备号)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include “chardev.h” // 见后面定义
void write_proc(void);
void read_proc(void);
main(int argc,char **argv) {
if(argc == 1) {
puts(“syntax: testprog[write|read]\n”);
exit(0);
}
if(!strcmp(argv[1],“write”)) {
write_porc();
}
else if(!strcmp(argv[1],“read”)) {
read_proc();
}
else {
puts(“testprog: invalid command!\n”);
}
return 0;
}
void write_proc() {
int fd,len,quit = 0;
char buf[100];
fd = open(“/dev/chrdev”,O_WRONLY);
if(fd <= 0) {
printf(“Error opening device for writing!\n”);
exit(1);
}
while(!quit) {
printf(“\n Please write into:”);
gets(buf);
if(!strcmp(buf,“exit”))
quit = 1;
while(ioctl(fd,DYNCHAR_QUERY_NEW_MSG))
usleep(100);
len = write(fd,buf,strlen(buf));
if(len < 0) {
printf(“Error writing to device!\n”);
close(fd);
exit(1);
}
printf(“\n There are %d bytes written to device!\n”,len);
}
close(fd);
}
void read_proc() {
int fd,len,quit = 0;
char *buf = NULL;
fd=open(“/dev/chrdev”,O_RDONLY);
if(fd < 0) {
printf(“Error opening device for reading!\n”);
exit(1);
}
while(!quit) {
printf(“\n Please read out:”);
while(!ioctl(fd,DYNCHAR_QUERY_NEW_MSG))
usleep(100);
// get the msg length
len = ioctl(fd,DYNCHAR_QUERY_MSG_LENGTH,NULL);
if(len) {
if(buf != NULL)
free(buf);
buf = malloc(sizeof(char)*(len+1));
len = read(fd,buf,len);
if(len < 0) {
printf(“Error reading from device!\n”);
}
else {
if(!strcmp(buf,“exit”) {
ioctl(fd,DYNCHAR_RESET); // reset
quit = 1;
}
else
printf(“%s\n”,buf);
}
}
}
free(buf);
close(fd);
}
// 以下为chrdev.h定义
#ifndef _DYNCHAR_DEVICE_H
#define _DYNCHAR_DEVICE_H
#include
#define DYNCHAR_MAJOR 42
#define DYNCHAR_MAGIC DYNCHAR_MAJOR
#define DYNCHAR_RESET _IO(DYNCHAR_MAGIC,0) // reset the data
#define DYNCHAR_QUERY_NEW_MSG _IO(DYNCHAR_MAGIC,1) // check for new message
#define DYNCHAR_QUERY_MSG_LENGTH _IO(DYNCHAR_MAGIC,2) // get message length
#define IOC_NEW_MSG 1
#endif