Smart210学习记录----beep linux字符设备驱动
今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈。。。但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,,
还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决方法,但是我还是没看懂,只能慢慢找,,,
我在insmod字符设备是,出现了一下提示信息
这里只列出主要部分:
Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = c0004000 [00000000] *pgd=00000000 Internal error: Oops: 7 [#2] Modules linked in: cirrus CPU: 0 PC is at dequeue_task+0xc/0x78 LR is at deactivate_task+0x38/0x44 pc : [ <c0039c44>] lr : [ <c003a02c>] Not tainted sp : c0205cc4 ip : c0205cd4 fp : c0205cd0 r10: 0000038d r9 : 72b90480 r8 : c020719c r7 : c0206998 r6 : 0000000a r5 : c0204000 r4 : c0206998 r3 : 00000001 r2 : 00000000 r1 : 00000000 r0 : c0206998 Flags: nZCv IRQs off FIQs on Mode SVC_32 Segment kernel Control: C000717F Table: 33B84000 DAC: 0000001D Process swapper (pid: 0, stack limit = 0xc0204190) Stack: (0xc0205cc4 to 0xc0206000) 5cc0: c0205ce4 c0205cd4 c003a02c c0039c48 0000038d c0205d20 c0205ce8 5ce0: c01d52c4 c003a004 c0205d84 c02069cc 01312d00 c0206b40 0005f5d6 c0204000 5d00: 0000000a c0205d24 c020719c 00000048 00000000 c0205d60 c0205d24 c01d5b24
在网上查询可知,这是因为驱动中出现了空指针,,,,可是作为一个初学者,看了好几篇解决办法,感觉像是对牛弹琴,,,还是不会,,只能在驱动中慢慢找,不过还是被我给找到了,O(∩_∩)O
一个解决办法的网址:http://mengren425.blog.163.com/blog/static/56903931201525502222/
以下是beep驱动程序:
#include <linux/kernel.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/ioctl.h> #include <linux/cdev.h> #include <linux/delay.h> #include <linux/device.h> #include <mach/gpio.h> #include <mach/regs-gpio.h> #include <plat/gpio-cfg.h> #define BEEPNAME "mybeep" static int beepmajor = 0; #define BEEPON 1 #define BEEPOFF 0 static struct class* my_beep_class; static struct device* my_beep_device; struct beep_device { struct cdev beep_dev; unsigned char value; }; struct beep_device* beep_device; static int my_beep_open(struct inode *node, struct file *filep) { gpio_request(S5PV210_GPD0(0),BEEPNAME); s3c_gpio_cfgpin(S5PV210_GPD0(0), S3C_GPIO_OUTPUT); gpio_set_value(S5PV210_GPD0(0), 0); return 0; } static int my_beep_close(struct inode * inode,struct file * file) { return 0; } static long my_beep_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { switch(cmd) { case BEEPON: printk("beep on\n"); beep_device->value = 1; gpio_set_value(S5PV210_GPD0(0), 1); break; case BEEPOFF: printk("beep off\n"); beep_device->value = 0; gpio_set_value(S5PV210_GPD0(0), 0); break; default: return -EUNATCH; } return 0; } struct file_operations beep_ops = { .owner = THIS_MODULE, .unlocked_ioctl = my_beep_ioctl, .open = my_beep_open, .release = my_beep_close, }; static void beep_setup_cdev(struct cdev *dev, int minor,struct file_operations *fops) { int err; dev_t deno; deno = MKDEV(beepmajor, minor); cdev_init(&beep_device->beep_dev, &beep_ops); beep_device->beep_dev.owner = THIS_MODULE; beep_device->beep_dev.ops = &beep_ops; err = cdev_add(&beep_device->beep_dev, deno, 1); if(err) { printk("beep cdev_add error"); } } static int __init mybeep_init(void) { dev_t deno; deno = MKDEV(beepmajor, 0); if(beepmajor) { register_chrdev_region(deno, 1, BEEPNAME); printk(KERN_EMERG"beep major is %d\n", beepmajor); } else { if (alloc_chrdev_region(&deno, 0, 1, BEEPNAME)) printk(KERN_EMERG"alloc_chrdev_region error\n"); beepmajor = MAJOR(deno); printk("beep major is %d\n", beepmajor); } beep_device = kmalloc(sizeof(struct beep_device), GFP_KERNEL); if(!beep_device) { printk("beep kmalloc error\n"); } memset(beep_device, 0, sizeof(struct beep_device)); beep_setup_cdev(&beep_device->beep_dev, 0, &beep_ops); my_beep_class= class_create(THIS_MODULE, BEEPNAME); if(IS_ERR(my_beep_class)) { printk(KERN_EMERG"class_create error\n"); } my_beep_device= device_create(my_beep_class, NULL, deno, NULL, "mybeep"); if(IS_ERR(my_beep_device)) { printk(KERN_EMERG"device_create error\n"); } return 0; } static void __exit mybeep_exit(void) { unregister_chrdev_region(MKDEV(beepmajor, 0), 1); cdev_del(&beep_device->beep_dev); device_unregister(my_beep_device); class_destroy(my_beep_class); } MODULE_LICENSE("Dual BSD/GPL"); module_init(mybeep_init); module_exit(mybeep_exit);
测试程序:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define BEEPON 1 #define BEEPOFF 0 int main(void) { int dev_fd; int i ; dev_fd = open("/dev/mybeep", O_RDWR | O_NONBLOCK); if (dev_fd == -1) { printf ("Can't open /dev/mybeep\n"); exit(1); } ioctl(dev_fd, BEEPON, 0); for(i = 500000; i > 0; i ++); ioctl(dev_fd, BEEPOFF, 0); close(dev_fd); return 0; }