Smart210学习记录(五) 之beep字符设备驱动


 
 
 

前言

  今天搞定了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

  在网上查询可知,这是因为驱动中出现了空指针。可是作为一个初学者,看了好几篇解决办法,感觉像是对牛弹琴,还是不会。只能在驱动中慢慢找,不过还是被我给找到了,哈哈。
  一个解决办法的网址:http://mengren425.blog.163.com/blog/static/56903931201525502222/

 

二、驱动程序

beep驱动程序跟led一样,基本只要弄清楚字符设备驱动的结构和开发板上的端口就可以编写了。所以就直接上驱动程序了。我的开发板是Smart210。

#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;
}

 

四、测试

测试已OK。

 
 
 
 
 
 
 
关注公众号"小败日记",搬砖过程遇到的问题,大家一起探讨,资源共享

小败日记公众号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值