linux版本 ubuntu12.04LTS
//驅動部分
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/vmalloc.h>
#include <linux/version.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
MODULE_LICENSE("Dual BSD/GPL");
static struct hello_dev{
dev_t devno;
struct cdev cdev;
};
struct hello_dev *hello =NULL;
static int hello_open(struct inode *inode, struct file *file)
{
printk(KERN_ALERT "hello open\n");
return 0;
}
static int hello_close(struct inode *inode, struct file *file)
{
printk(KERN_ALERT "hello close\n");
return 0;
}
static long hello_ioctl(struct file *file,unsigned int cmd, unsigned long arg)
{
int i;
i=cmd;
printk("ioctl in driver::cmd=%d.\n", cmd);
switch(i)
{
case 1:printk("ioctl command1 successfully\n");break;
case 2:printk("ioctl command2 successfully\n");break;
default:
{
printk("ioctl fail\n");
return -1;
}
}
return 0;
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.open = hello_open,
.unlocked_ioctl = hello_ioctl,
.release = hello_close,
};
static int hello_init(void)
{
int ret;
dev_t devno;
devno=MKDEV(235,0);//靜态獲得裝置号,注意不要和原來的裝置号沖突
//ret=alloc_chrdev_region(&devno,0,1,"hello");//動态獲得裝置号
ret= register_chrdev_region(devno,1,"hello");
if(ret<0)
{
printk(KERN_WARNING "HEHE\n");
return 0;
}
hello = kmalloc(sizeof(struct hello_dev),GFP_KERNEL);
memset(hello,0,sizeof(struct hello_dev));
hello->devno = devno;
cdev_init(&hello->cdev,&dev_fops);//把獲得的裝置号與驅動的方法關聯起來
hello->cdev.owner = THIS_MODULE;
ret =cdev_add(&hello->cdev,devno,1);//這句我的了解是,把裝置号與驅動方法關聯到核心中
if(ret)
{
printk(KERN_NOTICE "Error %d.\n",ret);
return 0;
}
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
dev_t devno =hello->devno;
cdev_del(&hello->cdev);
if(hello)
{
kfree(hello);
}
unregister_chrdev_region(devno,1);
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
下面是調試代碼:就是調試一下驅動寫的方法有沒有實作。
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
#include<linux/rtc.h>
#include<linux/ioctl.h>
#include<stdio.h>
#include<stdlib.h>
#define TEXT 2
int main()
{
int fd;
int i;
unsigned int j;
int retval;
fd=open("/dev/hello",O_RDWR);
if(fd==-1)
{
perror("error open\n");
exit(-1);
}
printf("open success\n");
j=1;
retval=ioctl(fd,j,0);
if(retval==-1)
{
perror("ioctl error\n");
exit(-1);
}
printf("send command1 successfully\n");
retval=ioctl(fd,2,0);
if(retval==-1)
{
perror("ioctl error\n");
exit(-1);
}
printf("send command2 successfully\n");
close(fd);
}
在本機調試,驅動的makefile如下:
ifneq ($(KERNELRELEASE),)
obj-m += char_hello.o //這個與你的檔案名有關
else
KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean
endif
加載驅動,首先要編譯生成.ko檔案
insmod char_hello.ko
通過lsmod就能看到加載了核心 或者 dmesg | tail -10可以看到加載了驅動中_init函數printk的資訊
然後用mknod -m 0666(權限) /dev/hello c 235 0 //c代表字元裝置 235 是主裝置号,0是此裝置号 這裡我用了靜态指定裝置号,如果用動态的話,就先在終端執行cat /proc/devices檢視
删除驅動就用rmmod char_hello
測試程式直接用gcc編譯執行就行了。
編者在學習期間遇到一個奇怪的問題,在PC機測試過程中,驅動中的ioctl函數裡面,當驅動收到cmd=2的話,是不會進入函數體的,終端會顯示位址錯誤的提示,編者更改測試程式中傳的值,嘗試過10個左右不同的數字,除了“2”,其他都是正常的。編者忽略這個問題,直接把代碼移植到開發闆上。發覺絲毫沒有問題。
我和我的小夥伴都驚呆了。
這問題,編者一直沒想出個是以然。