台部落
註冊
登錄
寫文章
請輸入正確的登錄賬號或密碼
註冊
忘記密碼
首頁
Linux Device Driver
正文
linux2.6字符設備驅動編程第一例:globalmem
原創
yylklshmyt20090217
2018-08-24 01:20
/*====================================================================== A globalmem driver as an example of char device drivers This example is to introduce how to use locks to avoid race conditions The initial developer of the original code is Baohua Song <author@linuxdriver.cn>. All Rights Reserved. ======================================================================*/ #include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/cdev.h> #include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h> #define GLOBALMEM_SIZE 0x1000 /*全局內存最大4K字節*/ #define MEM_CLEAR 0x1 /*清0全局內存*/ #define GLOBALMEM_MAJOR 254 /*預設的globalmem的主設備號*/ static int globalmem_major = GLOBALMEM_MAJOR; /*globalmem設備結構體*/ struct globalmem_dev { struct cdev cdev; /*cdev結構體*/ unsigned char mem[GLOBALMEM_SIZE]; /*全局內存*/ struct semaphore sem; /*併發控制用的信號量*/ }; 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) { return 0; } /* ioctl設備控制函數 */ static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg) { struct globalmem_dev *dev = filp->private_data; /*獲得設備結構體指針*/ switch (cmd) { case MEM_CLEAR: if (down_interruptible(&dev->sem)) { return - ERESTARTSYS; } memset(dev->mem, 0, GLOBALMEM_SIZE); up(&dev->sem); //釋放信號量 printk(KERN_INFO "globalmem is set to zero/n"); break; default: return - EINVAL; } return 0; } /*讀函數*/ static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) { unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct globalmem_dev *dev = filp->private_data; /*獲得設備結構體指針*/ /*分析和獲取有效的寫長度*/ if (p >= GLOBALMEM_SIZE) return count ? - ENXIO: 0; if (count > GLOBALMEM_SIZE - p) count = GLOBALMEM_SIZE - p; if (down_interruptible(&dev->sem)) { return - ERESTARTSYS; } /*內核空間->用戶空間*/ if (copy_to_user(buf, (void*)(dev->mem + p), count)) { ret = - EFAULT; } else { *ppos += count; ret = count; printk(KERN_INFO "read %d bytes(s) from %d/n", count, p); } up(&dev->sem); //釋放信號量 return ret; } /*寫函數*/ static ssize_t globalmem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos) { unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct globalmem_dev *dev = filp->private_data; /*獲得設備結構體指針*/ /*分析和獲取有效的寫長度*/ if (p >= GLOBALMEM_SIZE) return count ? - ENXIO: 0; if (count > GLOBALMEM_SIZE - p) count = GLOBALMEM_SIZE - p; if (down_interruptible(&dev->sem))//獲得信號量 { return - ERESTARTSYS; } /*用戶空間->內核空間*/ if (copy_from_user(dev->mem + p, buf, count)) ret = - EFAULT; else { *ppos += count; ret = count; printk(KERN_INFO "written %d bytes(s) from %d/n", count, p); } up(&dev->sem); //釋放信號量 return ret; } /* seek文件定位函數 */ static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig) { loff_t ret = 0; switch (orig) { case 0: /*相對文件開始位置偏移*/ if (offset < 0) { ret = - EINVAL; break; } if ((unsigned int)offset > GLOBALMEM_SIZE) { ret = - EINVAL; break; } filp->f_pos = (unsigned int)offset; ret = filp->f_pos; break; case 1: /*相對文件當前位置偏移*/ if ((filp->f_pos + offset) > GLOBALMEM_SIZE) { ret = - EINVAL; break; } if ((filp->f_pos + offset) < 0) { ret = - EINVAL; break; } filp->f_pos += offset; ret = filp->f_pos; break; default: ret = - EINVAL; break; } return ret; } /*文件操作結構體*/ static const struct file_operations globalmem_fops = { .owner = THIS_MODULE, .llseek = globalmem_llseek, .read = globalmem_read, .write = globalmem_write, .ioctl = globalmem_ioctl, .open = globalmem_open, .release = globalmem_release, }; /*初始化並註冊cdev*/ static void globalmem_setup_cdev(struct globalmem_dev *dev, int index) { int err, devno = MKDEV(globalmem_major, index); cdev_init(&dev->cdev, &globalmem_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &globalmem_fops; err = cdev_add(&dev->cdev, devno, 1); if (err) printk(KERN_NOTICE "Error %d adding LED%d", err, index); } /*設備驅動模塊加載函數*/ int globalmem_init(void) { int result; dev_t devno = MKDEV(globalmem_major, 0); /* 申請設備號*/ if (globalmem_major) result = register_chrdev_region(devno, 1, "globalmem"); else /* 動態申請設備號 */ { result = alloc_chrdev_region(&devno, 0, 1, "globalmem"); globalmem_major = MAJOR(devno); } if (result < 0) return result; /* 動態申請設備結構體的內存*/ globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL); if (!globalmem_devp) /*申請失敗*/ { result = - ENOMEM; goto fail_malloc; } memset(globalmem_devp, 0, sizeof(struct globalmem_dev)); globalmem_setup_cdev(globalmem_devp, 0); init_MUTEX(&globalmem_devp->sem); /*初始化信號量*/ return 0; fail_malloc: unregister_chrdev_region(devno, 1); return result; } /*模塊卸載函數*/ void globalmem_exit(void) { cdev_del(&globalmem_devp->cdev); /*註銷cdev*/ kfree(globalmem_devp); /*釋放設備結構體內存*/ unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*釋放設備號*/ } MODULE_AUTHOR("Song Baohua"); MODULE_LICENSE("Dual BSD/GPL"); module_param(globalmem_major, int, S_IRUGO); module_init(globalmem_init); module_exit(globalmem_exit);
發表評論
登录
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章
Linux Device Driver - first Module
sueway
2018-08-27 08:02:37
【Linux Device Driver】—(2)—Concurrency and Race Conditions——代碼
LonlyCorner
2018-08-25 11:30:16
【Linux Device Driver】—(1)—Char Drivers——原理
LonlyCorner
2018-08-25 11:30:16
【Linux Device Driver】—(2)—Concurrency and Race Conditions——原理
LonlyCorner
2018-08-25 11:30:16
【Linux Device Driver】—(3.1)—ioctl——代碼
LonlyCorner
2018-08-25 11:30:16
【Linux Device Driver】—(1)—Char Drivers——代碼
LonlyCorner
2018-08-25 11:30:14
【Linux Device Driver】—(3.1)—ioctl——原理
LonlyCorner
2018-08-25 11:30:14
linux驅動實踐(三)--不大一般的LED驅動
dndxhej
2018-08-24 12:46:24
linux驅動實踐(五)--linux下的按鍵驅動之查詢方式
dndxhej
2018-08-24 12:46:21
linux驅動實踐(四)--linux下讀寫寄存器
dndxhej
2018-08-24 12:46:21
V4L2編程 轉
haoranzhong
2018-08-24 03:42:39
linux 網絡編程
haoranzhong
2018-08-24 03:42:39
ARM僞指令集
haoranzhong
2018-08-24 03:42:39
grep 命令
haoranzhong
2018-08-24 03:42:39
qt移植問題
haoranzhong
2018-08-24 03:42:39
Y
yylklshmyt20090217
24小時熱門文章
最新文章
nfs配置方法
2009年世界大學排行
批處理FTP上傳文件到服務器
字節對齊
Linux2.6中斷下半部分的三種實現機制---工作隊列
最新評論文章
https://yachay.unat.edu.pe/blog/index.php?comment_area=format_blog&comment_component=blog&comment_co
linux以太網驅動總結