標籤:字元驅動
學習完了字元驅動,是按照宋寶華的Linux裝置驅動開發講解學習的,代碼練習敲了一遍,自己也理解了。
字元驅動主要的就是一些open,close,read,write等操作
通過上層調用到自己寫的底層函數
這裡寫代碼片#include <linux/fs.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/cdev.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/init.h>#include <asm/io.h>#include <asm/system.h>#include <asm/uaccess.h>#define GLOBALMEM_SIZE 0x1000 /*全域記憶體4kb*/#define MEM_CLEAR 0x1 /*清除全域記憶體*/#define GLOBALMEM_MAJOR 250 /*主裝置號*/static int globalmem_major = GLOBALMEM_MAJOR;struct globalmem_dev{ struct cdev cdev; unsigned char mem[GLOBALMEM_SIZE];};struct globalmem_dev *globalmem_devp; /*全域結構體*/int globalmem_open(struct inode* inode, struct file* filp){ filp->private_data = globalmem_devp;//將裝置結構體指標值賦值給檔案私人資料指標 return 0;}int globalmem_release(struct inode* inode, struct file* filp){ struct globalmem_dev* dev = filp->private_data; return 0;}static int globalmem_ioctl(struct inode* inodep, struct file* filp, unsigned int cmd,unsigned long arg){ struct globalmem_dev* dev = filp->private_data; return 0;}static ssize_t globalmem_read(struct file* filp, char __user *buf, size_t count, loff_t *ppos){ struct globalmem_dev* dev = filp->private_data; unsigned long p = *ppos; int ret = 0; if (p >= GLOBALMEM_SIZE ) //位移量超過數組範圍 return 0; if (count > GLOBALMEM_SIZE - p) //讀的個數太大 count = GLOBALMEM_SIZE - p; //從核心讀到使用者 if(copy_to_user(buf,dev->mem + p,count)) ret = - EFAULT; //EFAULT 參數buf指向無效記憶體位址 else { *ppos += count; ret = count; printk(KERN_INFO "read %d bytes from %x\n",count,p); } return ret;}static ssize_t globalmem_write(struct file* filp, char __user *buf, size_t count, loff_t *ppos){ struct globalmem_dev* dev = filp->private_data; unsigned long p = *ppos; int ret = 0; if(p >= GLOBALMEM_SIZE) //位移量超過核心空間大小 return 0; if(count > GLOBALMEM_SIZE - p) //寫的個數超過現有的 count = GLOBALMEM_SIZE - p; //從使用者寫到核心 if(copy_from_user(dev->mem + p,(void*)buf,count)) ret = - EFAULT; else { *ppos += count; ret = count; printk(KERN_INFO "write %d bytes from %x\n", count,dev->mem + p); } return ret;}//filp是核心檔案結構體static loff_t globalmem_llseek(struct file* filp, loff_t offset, int orig){ struct globalmem_dev* dev = filp->private_data; int ret; //SEEK_SET 0 檔案開頭 //SEEK_CUR 1 當前位置 //SEEK_END 2 檔案尾 switch(orig){ case 0: if(offset < 0){ ret = - EINVAL; break; } if(offset > GLOBALMEM_SIZE){ ret = - EINVAL; break; } filp->f_pos = (unsigned int)offset; ret = filp->f_pos; break; case 1: if(offset > GLOBALMEM_SIZE){ ret = - EINVAL; break; } if(filp->f_pos + offset > GLOBALMEM_SIZE){ ret = - EINVAL; break; } filp->f_pos += offset; ret = filp->f_pos; break; case 2: if(offset > 0){ ret = - EINVAL; //在檔案末尾,只能位移賦值 break; } if(offset + GLOBALMEM_SIZE < 0){ ret = - EINVAL; break; } filp->f_pos += offset; ret = filp->f_pos; break; default: ; } return 0;}static const struct file_operations globalmem_fops = { .owner = THIS_MODULE, .open = globalmem_open, .read = globalmem_read, .write = globalmem_write, .release = globalmem_release, .llseek = globalmem_llseek, .compat_ioctl = globalmem_ioctl};static void globalmem_setup_dev(struct globalmem_dev* globalmem_dev,int index){ int err,devno; devno = MKDEV(globalmem_major,0); cdev_init(&globalmem_dev->cdev,&globalmem_fops); err = cdev_add(&globalmem_dev->cdev,devno,1); if(err) { printk(KERN_NOTICE "ERROR %d adding globalmem %d",err,index); }}static int __init globalmem_init(void){ printk(KERN_INFO "globalmem_init"); int result; dev_t devno = MKDEV(globalmem_major,0);//根據主裝置號,或得裝置號,一般次裝置號為0 if(globalmem_major != 0) register_chrdev_region(devno,1,"globalmem_dev"); else { result = alloc_chrdev_region(&devno,0,1,"globalmem_dev");//自動分配一個裝置號 globalmem_major = MAJOR(devno); } if(result < 0) return result; //動態申請結構體記憶體 globalmem_devp = kmalloc(sizeof(struct globalmem_dev),GFP_KERNEL); if(!globalmem_devp) goto fail_malloc; memset(globalmem_devp,0,sizeof(struct globalmem_dev)); globalmem_setup_dev(globalmem_devp,0); return 0;fail_malloc: unregister_chrdev_region(devno,1); return result;}static int __exit globalmem_exit(void){ printk(KERN_INFO "globalmem_exit..."); dev_t devno; devno = MKDEV(globalmem_major,0); cdev_del(&globalmem_devp->cdev); // 刪除cdev結構體 unregister_chrdev_region(devno,1);//登出裝置 kfree(globalmem_devp); return 0;}module_init(globalmem_init);module_exit(globalmem_exit);
Makefile
KVERS = $(shell uname -r)obj-m += globalmem_private.obuild:kernel_moduleskernel_modules: make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modulesinsmod: insmod globalmem.koclean: make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules clean
測試程式
#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#define path "/dev/globalmem_dev"int main(){ char buf[] = "Hello word!\n"; int fd = open(path,O_RDWR); if(fd == -1){ perror("open"); exit(1); } write(fd,buf,sizeof(buf)); close(fd);}
執行結果
Linux字元驅動