?? globalmem_lock.c
字號:
/*====================================================================== 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);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -