第一步:my74hc595.cnode
#include <linux/module.h> //模塊所需的大量符號和函數定義
#include <linux/init.h> //指定初始化和清除函數
#include <linux/fs.h> //文件系統相關的函數和頭文件
#include <linux/cdev.h> //cdev結構的頭文件
#include <asm/uaccess.h> //在內核和用戶空間中移動數據的函數
#include <linux/slab.h>
#include <linux/device.h>
MODULE_LICENSE("GPL"); //指定代碼使用的許可證
//文件操做函數的聲明
int my74hc595_open(struct inode *, struct file *);
int my74hc595_release(struct inode *, struct file *);
ssize_t my74hc595_read(struct file *, char *, size_t, loff_t *);
ssize_t my74hc595_write(struct file *, const char *, size_t, loff_t *);
int dev_major = 1253; //指定主設備號
int dev_minor = 0; //指定次設備號linux
static struct class *firstdrv_class;
static struct device *firstdrv_class_dev;shell
struct cdev *my74hc595_cdev; //內核中表示字符設備的結構
int *gp_testdata;//測試用數據
struct file_operations my74hc595_fops= //將文件操做與分配的設備號相連
{
owner: THIS_MODULE, //指向擁有該模塊結構的指針
open: my74hc595_open,
release: my74hc595_release,
read: my74hc595_read,
write: my74hc595_write,
};
static void __exit my74hc595_exit(void) //退出模塊時的操做
{
dev_t devno=MKDEV(dev_major, dev_minor); //dev_t是用來表示設備編號的結構
cdev_del(my74hc595_cdev); //從系統中移除一個字符設備
kfree(my74hc595_cdev); //釋放自定義的設備結構
kfree(gp_testdata);
unregister_chrdev_region(devno, 1); //註銷已註冊的驅動程序函數
device_unregister(firstdrv_class_dev); //刪除/dev下對應的字符設備節點
class_destroy(firstdrv_class);
printk("my74hc595 unregister success\n");
}
static int __init my74hc595_init(void) //初始化模塊的操做
{
int ret, err;
dev_t devno;
#if 1
//動態分配設備號,次設備號已經指定
ret=alloc_chrdev_region(&devno, dev_minor, 1, "my74hc595");
//保存動態分配的主設備號
dev_major=MAJOR(devno);
#else
//根據指望值分配設備號
devno=MKDEV(dev_major, dev_minor);
ret=register_chrdev_region(devno, 1, "my74hc595");
#endif
if(ret<0)
{
printk("my74hc595 register failure\n");
//my74hc595_exit(); //若是註冊設備號失敗就退出系統
return ret;
}
else
{
printk("my74hc595 register success\n");
}
gp_testdata = kmalloc(sizeof(int), GFP_KERNEL);
#if 0//兩種初始化字符設備信息的方法
my74hc595_cdev = cdev_alloc();//調試時,此中方法在rmmod後會出現異常,緣由未知
my74hc595_cdev->ops = &my74hc595_fops;
#else
my74hc595_cdev = kmalloc(sizeof(struct cdev), GFP_KERNEL);
cdev_init(my74hc595_cdev, &my74hc595_fops);
#endif測試
my74hc595_cdev->owner = THIS_MODULE; //初始化cdev中的全部者字段
err=cdev_add(my74hc595_cdev, devno, 1); //向內核添加這個cdev結構的信息
if(err<0)
printk("add device failure\n"); //若是添加失敗打印錯誤消息
firstdrv_class = class_create(THIS_MODULE, "my74hc595");
firstdrv_class_dev = device_create(firstdrv_class, NULL, MKDEV(dev_major, 0), NULL,"my74hc595-%d", 0);//在/dev下建立節點
printk("register my74hc595 dev OK\n");
return 0;
}
//打開設備文件系統調用對應的操做
int my74hc595_open(struct inode *inode, struct file *filp)
{
//將file結構中的private_data字段指向已分配的設備結構
filp->private_data = gp_testdata;
printk("open my74hc595 dev OK\n");
return 0;
}
//關閉設備文件系統調用對應的操做
int my74hc595_release(struct inode *inode, struct file *filp)
{
printk("close my74hc595 dev OK\n");
return 0;
}
//讀設備文件系統調用對應的操做
ssize_t my74hc595_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
//獲取指向已分配數據的指針
unsigned int *p_testdata = filp->private_data;
//將設備變量值複製到用戶空間
if(copy_to_user(buf, p_testdata, sizeof(int)))
{
return -EFAULT;
}
printk("read my74hc595 dev OK\n");
return sizeof(int); //返回讀取數據的大小
}
//寫設備文件系統調用對應的操做
ssize_t my74hc595_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
//獲取指向已分配數據的指針
unsigned int *p_testdata = filp->private_data;
//從用戶空間複製數據到內核中的設備變量
if(copy_from_user(p_testdata, buf, sizeof(int)))
{
return -EFAULT;
}
printk("write my74hc595 dev OK\n");
return sizeof(int); //返回寫數據的大小
}
module_init(my74hc595_init); //模塊被裝載時調用my74hc595_init
module_exit(my74hc595_exit); //模塊被卸載時調用my74hc595_exitspa
第二步:Makefile指針
按以下內容編寫一個Makefile文件,而後輸入make就能夠開始自動編譯了。編譯以後獲得了一個名爲my74hc595.ko的模塊文件,這就是咱們須要的設備驅動文件。調試
#Makefile
CROSS_COMPILE=arm-linux-
ARCH:=arm
CC:=$(CROSS_COMPILE)gcc
LD:=$(CROSS_COMPILE)ld
obj-m = my74hc595.o
module-objs = my74hc595.oinput
KDIR = /home/zhang/at91/linux-at91
PWD = $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -rf *.o *.ko *~it
接下來運行以下代碼,將驅動加入內核。
insmod my74hc595.ko
將自動在/dev目錄下建立設備節點
rmmod my74hc595.ko
將自動刪除節點
第三步:CharDevTest.c
#include <sys/types.h>#include <sys/stat.h>#include <stdio.h>#include <fcntl.h> main(){ int fd, num; // fd=open("/dev/my74hc595", O_RDWR, S_IRUSR|S_IWUSR); //可讀寫方式打開設備文件 fd=open("/dev/my74hc595-0", O_RDWR); //可讀寫方式打開設備文件 if(fd!=-1) { read(fd, &num, sizeof(int)); //讀取設備變量 printf("The my74hc595 is %d\n", num); printf("Please input the num written to my74hc595\n"); scanf("%d", &num); write(fd, &num, sizeof(int)); //寫設備變量 read(fd, &num, sizeof(int)); //再次讀取剛纔寫的值 printf("The my74hc595 is %d\n", num); close(fd); //關閉設備文件 } else { printf("Device open failure\n"); perror("open my74hc595"); }}