08 Linux字符驱动---信号量
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了08 Linux字符驱动---信号量相关的知识,希望对你有一定的参考价值。
1. mycdev.c
1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/cdev.h> 4 #include <linux/fs.h> 5 #include <linux/device.h> 6 #include <linux/err.h> 7 #include <linux/uaccess.h> 8 #include <asm-generic/ioctl.h> 9 #include <linux/semaphore.h> 10 #include "cmd.h" 11 12 #define MAX 1024 13 14 struct mycdev 15 { 16 int len; 17 char kbuf[MAX]; 18 struct cdev cdev; 19 struct semaphore sem; 20 }; 21 22 struct mycdev mycdev; 23 struct class *cls; 24 25 int mycdev_open(struct inode *inode, struct file *file) 26 { 27 printk("Call mycdev_open()\n"); 28 return 0; 29 } 30 31 ssize_t mycdev_read(struct file *file,char __user *ubuf,size_t size,loff_t *offset) 32 { 33 int len; 34 35 printk("Call mycdev_read()\n"); 36 37 if(down_interruptible(&mycdev.sem)) 38 { 39 return -ERESTARTSYS; 40 } 41 42 if(size >= mycdev.len) 43 len = mycdev.len; 44 else 45 len = size; 46 47 if(copy_to_user(ubuf,mycdev.kbuf,len) != 0) 48 { 49 printk("copy_to_user() error\n"); 50 return -EFAULT; 51 } 52 53 up(&mycdev.sem); 54 55 return len; 56 } 57 58 ssize_t mycdev_write(struct file *file,const char __user *ubuf,size_t size,loff_t *offset) 59 { 60 printk("call mycdev_write()\n"); 61 62 if(down_interruptible(&mycdev.sem)) 63 { 64 return -ERESTARTSYS; 65 } 66 67 if(size >= MAX) 68 return -1; 69 70 if(copy_from_user(mycdev.kbuf,ubuf,size) != 0) 71 { 72 printk("Fail to copy_from_user()"); 73 return -EFAULT; 74 } 75 76 mycdev.len = size; 77 mycdev.kbuf[size] = ‘\0‘; 78 printk("write : %s\n",mycdev.kbuf); 79 80 up(&mycdev.sem); 81 82 return size; 83 } 84 85 long mycdev_unlocked_ioctl(struct file *file,unsigned int cmd, unsigned long arg) 86 { 87 int ret = 0; 88 89 switch(cmd) 90 { 91 case CMD_CDEV_CLEAN: 92 memset(mycdev.kbuf,0,MAX); 93 printk("CMD_CLEN\n"); 94 break; 95 96 case CMD_SET_CDEV_LEN: 97 mycdev.len = arg; 98 printk("CMD_SET\n"); 99 break; 100 101 case CMD_GET_CDEV_LEN: 102 put_user(mycdev.len,(unsigned long *)arg); 103 printk("CMD_GET\n"); 104 break; 105 106 default: 107 printk("INvalid\n"); 108 ret = -EINVAL; 109 break; 110 } 111 112 return ret; 113 } 114 115 struct file_operations fops = { 116 .owner = THIS_MODULE, 117 .open = mycdev_open, 118 .read = mycdev_read, 119 .write = mycdev_write, 120 .unlocked_ioctl = mycdev_unlocked_ioctl, 121 }; 122 123 int mycdev_init(void) 124 { 125 int ret = 0; 126 dev_t dev; 127 struct device *device; 128 129 ret = alloc_chrdev_region(&dev, 0, 1, "mycdev"); 130 if (ret != 0) 131 { 132 printk("alloc_chrdev_region() error\n"); 133 goto err_alloc_chrdev_region; 134 } 135 136 cdev_init(&(mycdev.cdev), &fops); 137 138 ret = cdev_add(&(mycdev.cdev), dev, 1); 139 if (ret != 0) 140 { 141 printk("cdev_add() error\n"); 142 goto err_cdev_add; 143 } 144 145 cls = class_create(THIS_MODULE, "mycdev"); 146 if (IS_ERR(cls)) 147 { 148 ret = PTR_ERR(cls); 149 printk("class_create() error\n"); 150 goto err_class_create; 151 } 152 153 device = device_create(cls, NULL, dev, NULL, "mycdev"); 154 if (IS_ERR(device)) 155 { 156 ret = PTR_ERR(device); 157 printk("device_create() error\n"); 158 goto err_device_create; 159 } 160 161 sema_init(&mycdev.sem, 1); 162 163 printk("mycdev_init()\n"); 164 return 0; 165 166 err_device_create: 167 class_destroy(cls); 168 169 err_class_create: 170 cdev_del(&(mycdev.cdev)); 171 172 err_cdev_add: 173 unregister_chrdev_region(dev, 1); 174 175 err_alloc_chrdev_region: 176 return ret; 177 } 178 179 void mycdev_exit(void) 180 { 181 dev_t dev = mycdev.cdev.dev; 182 183 device_destroy(cls, dev); 184 class_destroy(cls); 185 cdev_del(&(mycdev.cdev)); 186 cdev_del(&(mycdev.cdev)); 187 unregister_chrdev_region(dev, 1); 188 189 printk("mycdev_exit()\n"); 190 return; 191 } 192 193 module_init(mycdev_init); 194 module_exit(mycdev_exit); 195 196 MODULE_LICENSE("GPL"); 197 MODULE_AUTHOR("GNB");
2. cmd.h
1 #ifndef _CMD_H_ 2 #define _CMD_H_ 3 4 #define CMD_TYPE ‘k‘ 5 #define CMD_CDEV_CLEAN _IO(CMD_TYPE,0x10) 6 #define CMD_SET_CDEV_LEN _IOW(CMD_TYPE,0x11,int) 7 #define CMD_GET_CDEV_LEN _IOR(CMD_TYPE,0x12,int) 8 9 #endif
3. Makefile
1 KERNEL_DIR = /lib/modules/$(shell uname -r)/build 2 PWD = $(shell pwd) 3 4 ifneq ($(KERNELRELEASE),) 5 6 obj-m := mycdev.o 7 8 else 9 10 .PHONY:default clean 11 12 default: 13 $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules 14 15 clean: 16 $(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean 17 18 endif
以上是关于08 Linux字符驱动---信号量的主要内容,如果未能解决你的问题,请参考以下文章
linux驱动程序中的并发控制-5(信号量(semaphore))-47
linux驱动程序中的并发控制-5(信号量(semaphore))-47