字符设备实例
字符设备实例
字符设备驱动程序:设计两个终端设备文件实现一个字符设备驱动程序,使一对进程之间利用该字符设备驱动程序能互相传递可变长度的信息。
要求:使用终端文件的基本操作,如init(),open(),release(),read(),write(),ioctl()。
/**************************************************************/
/***** chardev.c *****/
/**************************************************************/
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
#define WE_REALLY_WANT_TO_USE_A_BROKEN_INTERFACE
#define __NO_VERSION__
#include
#include
char kernel_version[]=UTS_RELEASE;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "chardev.h"
#define DEVICE_NAME "dynchar"
static int usage,new_msg; // control flags
static char *data;
// open the device
static int dynchar_open(struct inode *inode,struct file *filp) {
MOD_INC_USE_COUNT;
printk("This chrdev is in open!\n");
return 0;
}
// close the device
static int dynchar_release(struct inode *inode,struct file *filp) {
MOD_DEC_USE_COUNT;
printk("This chrdev is in release!\n");
return 0;
}
// write to device -transfer from user space to kernel space
static ssize_t dynchar_write(struct file *filp,const char *buf,
size_t count,loff_t *offset) {
if(count<0)
return -EINVAL;
if(usage || new_msg)
return -EBUSY;
usage=1;
kfree(data);
data=kmalloc(sizeof(char)*(count+1),GFP_KERNEL);
if(!data) {
return -ENOMEM;
}
copy_from_user(data,buf,count+1); // start transfering
usage=0;
new_msg=1;
return count;
}
// read from device -transfer from kernel space to user space
static ssize_t dynchar_read(struct file *filp,char *buf,size_t count,
loff_t *offset) {
int length;
if(count<0)
return -EINVAL;
if(usage)
return -EBUSY;
usage=1;
if(data==NULL)
return 0;
length=strlen(data);
if(length
#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
/************************************************************/
/***** testproc.c, this is a test program for chardev.c *****/
/************************************************************/
#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]!");
exit(0);
}
if(!strcmp(argv[1],"write")) {
write_porc();
}
else if(!strcmp(argv[1],"read")) {
read_proc();
}
else {
puts("testprog: invalid command!");
}
return 0;
}
void write_proc() {
int fd,len,quit=0;
int dbg;
char buf[100];
fd=open("cdev0",O_WRONLY);
if(fd<=0) {
printf("Error opening device for writing!\n");
exit(1);
}
while(!quit) {
printf("\n write>>");
gets(buf);
if(!strcmp(buf,"exit"))
quit=1;
while(ioctl(fd,DYNCHAR_QUERY_NEW_MSG))
usleep(1000);
len=write(fd,buf,strlen(buf));
if(len<0) {
;
printf("Error writing to device!\n");
close(fd);
exit(1);
}
printf("%d bytes written to device!\n",len);
}
close(fd);
}
void read_proc() {
int fd,len,quit=0;
char *buf=NULL;
fd=open("cdev1",O_RDONLY);
if(fd<0) {
printf("Error opening device for reading!\n");
exit(1);
}
while(!quit) {
printf("\n read>>");
while(!ioctl(fd,DYNCHAR_QUERY_NEW_MSG))
usleep(1000);
// 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!");
}
else {
if(!strcmp(buf,"exit")) {
;
ioctl(fd,DYNCHAR_RESET); // reset
quit=1;
}
else
printf("%s\n",buf);
}
}
}
free(buf);
close(fd);
}
- 4 -