今天首次接触Linux字符设备的编程,花了很长的时间,针对所发现的问题进行整理如下:
有以下注意点:
1,编译模块不需要编译内核。按照如下的Makefile的方式即可在ubuntu下进行设备模块编译
2,insmod后,需要使用mknod进行设备映射。此时,需要在cat /proc/devices中确认好主设备值
例如:mknod /dev/tfs 250 0
3,编写测试代码时,需要注意权限的使用,因为映射到/dev/tfs中的权限只有root权限才可以进行rw。其他的权限为只读。
先附上字符设备驱动的源码:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
MODULE_LICENSE("Dual BSG/GPL");
unsigned int fs_major = 0;
static char *data;
static ssize_t test_read(struct file *file, char *buf, size_t count, loff_t *f_pos);
static ssize_t test_write(struct file *file, const char *buffer, size_t count, loff_t *f_pos);
static int test_open(struct inode *inode, struct file *file);
static int test_release(struct inode *inode, struct file *file);
int init_module(void);
void cleanup_module(void);
static struct file_operations chr_fops = {
read: test_read,
write: test_write,
open: test_open,
release:test_release
};
static ssize_t test_read(struct file *file, char *buf, size_t count, loff_t *f_pos)
{
int len;
if (count<0)
return -EINVAL;
len = strlen(data);
if (len<count)
count = len;
copy_to_user(buf, data, count+1);
return count;
}
static ssize_t test_write(struct file *file, const char *buffer, size_t count, loff_t *f_pos)
{
if (count < 0 )
return -EINVAL;
kfree(data);
data = (char *) kmalloc(sizeof(char)*(count+1), GFP_KERNEL);
if (!data)
return -ENOMEM;
copy_from_user(data, buffer, count+1);
return count;
}
static int test_open(struct inode *inode, struct file *file)
{
try_module_get(THIS_MODULE);
printk("This is open \n");
return 0;
}
static int test_release(struct inode *inode, struct file *file)
{
module_put(THIS_MODULE);
printk("This is released\n");
return 0;
}
int init_module(void)
{
int res;
res = register_chrdev(0, "tfs", &chr_fops);
if (res<0)
{
printk("Can't get major name\n");
return 0;
}
if (fs_major == 0)
fs_major=res;
printk("Major name is %d", fs_major);
return 0;
}
void clean_module(void)
{
unregister_chrdev(fs_major, "tfs");
printk("tfs has removed");
}
附上Makefile的源码(注意Makefile的大小写,不能为makefile)
obj-m +=memrw_drv.o
all:
make -C /lib/modules/`uname -r`/build M=$(PWD) modules
clean:
make -C /lib/modules/`uname -r`/build M=$(PWD) clean
附上字符设备的测试源码:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#define DEVPATH "/dev/tfs"
int main(int argc, char **argv)
{
int fd, i, nwrite, nread, len;
char *buf = "String to Driver\n";
char read_buf[18] = { 0 };
fd = open(DEVPATH, O_RDWR);
if (fd<0)
{
perror("open");
exit(1);
}else
printf("device opened!\n");
fflush(stdout);
len = strlen(buf);
nwrite = write(fd, buf, len);
if(nwrite<0)
{
perror("write");
exit(1);
}
nread = read(fd, read_buf, 18);
if(nread<0)
{
perror("read");
exit(1);
}else
printf("Read String is from driver -> %s" , read_buf);
fflush(stdout);
close(fd);
return 0;
}