编写一个简单的字符设备驱动程序。要求该字符设备包括scull_open() scull_write() scull_read() scull_i

linux ubuntu 貌似这是平台环境
2024-11-06 18:31:37
推荐回答(1个)
回答1:

第一部分 字符设备驱动程序

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