S5PV210之beep-bus模型 linux3.0.8驱动

时间:2023-03-09 12:54:45
S5PV210之beep-bus模型 linux3.0.8驱动

目录: 一. bus-driver-device模型

    二. 运行结果,及错误解决

    三. 怎样利用以有的driver device驱动来写自已的beep-driver-device 驱动

        四. 总结

  怎样解决编译时出现内核提供的函数或变量没有定义,使用source insight搜索功能找到声明的头文件,然后包含该头件就行了:

  比如: error: implicit declaration of function 'copy_from_user'

  解决:使用source insight搜索功能,可以找到copy_from_user函数是在linux/uaccess.h 头文件中定义,所以包含此头文件就行了。

一. bus-driver-device模型:

  S5PV210之beep-bus模型 linux3.0.8驱动

二. 运行结果,及错误解决

步骤一:驱动运行结果:

S5PV210之beep-bus模型 linux3.0.8驱动

从上图红色线可知,卸载led_dev失败原因是因为led_dev.c  platform_device中没有加release()函数;所以正确的方法如下:在led_dev.c 中:

static struct platform_device led_dev = {
    .name = "mini210_led",
    .id = 0,
    .dev = {
        .release = led_release,    //必须在.dev中加入
        //.platform_data = &smsc911x_config,
    },
    .num_resources = ARRAY_SIZE(led_resources),
    .resource = led_resources,
};

步骤二:改正步骤一的问题后,重新编译,下载到板上,又出现下面情况

错误:

通过开发板串口返回的错:[root@FriendlyARM driver]# rmmod led_dev
rmmod: remove 'led_dev': Device or resource busy

再查看编译出现的警告:

S5PV210之beep-bus模型 linux3.0.8驱动

上图说led_dev_exit定义了,但没有使用,所以原来是modele_exit(led_dev_exit); //这里错了,会导致rmmod 失败:Device or resource busy;

正确写法:module_exit(led_dev_exit);

解决上面2个步骤后,这驱动程序问题就解决了。

三. 怎样利用以有的driver device驱动来写自已的beep-driver-device 驱动

  新建beep_dev.c  与 beep_drv.c文件

  1) 用source insight软件打开beep_dev.c:

  搜索platform_device 找到有platform_device 类型定义的变量,这里我找到的是3ds_debugboard.c参考此文件来编写自己的驱动,打开此文件并找到以下内容并复制到beep_dev.c文件中:

static struct resource smsc911x_resources[] = {
    {
        .flags = IORESOURCE_MEM,
    } , {
        .start = EXPIO_INT_ENET,
        .end = EXPIO_INT_ENET,
        .flags = IORESOURCE_IRQ,
    },
};static struct platform_device smsc_lan9217_device = {
    .name = "smsc911x",
    .id = 0,
    .dev = {
        .platform_data = &smsc911x_config,
    },
    .num_resources = ARRAY_SIZE(smsc911x_resources),
    .resource = smsc911x_resources,
};

beep_dev.c完整代码:

/*分配,设置,注册一个platform_device*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/serial_core.h>

/*分配,设置,注册一个platform_device*/

static struct resource beep_resources[] = {
    [0] = {
        /*.start = 0xE0200280, //0xE02000A0;
        .end = 0xE0200280 + 8 - 1,
        .flags = IORESOURCE_MEM,*/
        .start = 0xE02000A0, //;
        .end = 0xE02000A0 + 8 - 1,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = 0,
        .start = 0,
        .flags = IORESOURCE_IRQ,
    }
};

static void beep_release(struct device *dev)
{
    printk("beep_release\n");
}

static struct platform_device beep_dev = {
    .name = "mini210_beep",
    .id = 0,
    .dev = {
        .release = beep_release,
        //.platform_data = &smsc911x_config,
    },
    .num_resources = ARRAY_SIZE(beep_resources),
    .resource = beep_resources,
};

static int beep_dev_init(void)
{
    platform_device_register(&beep_dev);
    return 0;
}

static void beep_dev_exit(void)
{
    platform_device_unregister(&beep_dev);
}

module_init(beep_dev_init);
//modele_exit(beep_dev_exit);  //这里错了,会导致rmmod 失败:Device or resource busy
module_exit(beep_dev_exit);

MODULE_LICENSE("GPL");

2) 用source insight软件打开beep_drv.c:

搜索platform_driver 找到有platform_driver 类型定义的变量,这里我使用的是88pm8607.c参考此文件来编写自己的驱动,打开此文件并找到以下内容并复制到beep_drv.c文件中:

static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
{
    struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
    struct pm8607_regulator_info *info = NULL;
    struct regulator_init_data *pdata = pdev->dev.platform_data;
    struct resource *res;
    int i;

res = platform_get_resource(pdev, IORESOURCE_IO, 0);
    if (res == NULL) {
        dev_err(&pdev->dev, "No I/O resource!\n");
        return -EINVAL;
    }
    for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
        info = &pm8607_regulator_info[i];
        if (info->desc.id == res->start)
            break;
    }
    if ((i < 0) || (i > PM8607_ID_RG_MAX)) {
        dev_err(&pdev->dev, "Failed to find regulator %llu\n",
            (unsigned long long)res->start);
        return -EINVAL;
    }
    info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
    info->chip = chip;

/* check DVC ramp slope double */
    if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
        info->slope_double = 1;

/* replace driver_data with info */
    info->regulator = regulator_register(&info->desc, &pdev->dev,
                         pdata, info);
    if (IS_ERR(info->regulator)) {
        dev_err(&pdev->dev, "failed to register regulator %s\n",
            info->desc.name);
        return PTR_ERR(info->regulator);
    }

platform_set_drvdata(pdev, info);
    return 0;
}

static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
{
    struct pm8607_regulator_info *info = platform_get_drvdata(pdev);

platform_set_drvdata(pdev, NULL);
    regulator_unregister(info->regulator);
    return 0;
}

static struct platform_driver pm8607_regulator_driver = {
    .driver        = {
        .name    = "88pm860x-regulator",
        .owner    = THIS_MODULE,
    },
    .probe        = pm8607_regulator_probe,
    .remove        = __devexit_p(pm8607_regulator_remove),
};

beep_drv.c完整代码:

  #include <linux/module.h>

#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/uaccess.h>

#include <asm/io.h>

static int major;

static struct class *cls;  //可加可不加,作用: 系统自动帮我们创建设备节点
static volatile unsigned long *GPIOCON;
static volatile unsigned long *GPIODAT;
static int pin;

static int beep_open(struct inode *inode, struct file *file)
{
    /* 配制为输出*/
    *GPIOCON &= ~(0xf<<(pin*4));
    *GPIOCON |= (0x1<<(pin*4));
    return 0;
}

static ssize_t beep_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    int val;
    copy_from_user(&val, buf, count);
    printk("beep_write: val:%d, pin:%d\n", val, pin);
    //val = 0;
    if (val == 1) {
        //off beep
        *GPIODAT &= ~(1<<pin);
    }else {
        //on beep
        *GPIODAT |= (1<<pin);
    }
    return 0;
}

static struct file_operations beep_fops = {
    .owner = THIS_MODULE,
    .open  = beep_open,
    .write = beep_write,
};

static int beep_probe(struct platform_device *pdev)
{
    struct resource *res;
    /* 根据platform_device的资源进行ioremap*/

  /* 这里res将获取beep_dev中beep_resources*/
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    GPIOCON = ioremap(res->start, res->end - res->start + 1);
    GPIODAT = GPIOCON + 1;

res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    pin = res->start;    //获取.start 的内容
    
    /* 注册字符设备驱动程序*/
    printk("beep_probel, found beep\n");
    major = register_chrdev(0, "mini210_beep", &beep_fops);
    cls = class_create(THIS_MODULE, "mini210_beep");  //
    device_create(cls, NULL, MKDEV(major, 0), NULL, "mini210_beep");

        /* 在开发板上建立/dev/mini210_beep 系统节点*/
    //register_chrdev_region(,unsigned count,const char * name);
    //*GPIODAT = 1;
    return 0;
}

static int beep_remove(struct platform_device *pdev)
{
    /*卸载字符设备驱动程序*/
    /* iounmap */
    printk("beep_remove, remove beep\n");

device_destroy(cls, MKDEV(major, 0));

class_destroy(cls);
    unregister_chrdev(major, "mini210_beep");
    iounmap(GPIOCON);
    
    return 0;
}

static struct platform_driver beep_drv = {
    .probe        = beep_probe,
    .remove        = __devexit_p(beep_remove),
    .driver        = {
        .name    = "mini210_beep",   //用来与beep_dev文件中:.name来匹配;因为bus是使          // 用.name搜索并匹配,才能对应。
        .owner    = THIS_MODULE,
/*#ifdef CONFIG_PM
        .pm    = &gpio_keys_pm_ops,
#endif*/
    }
};

static int beep_drv_init(void)
{
    platform_driver_register(&beep_drv);
    return 0;
}

static void beep_drv_exit(void)
{
    platform_driver_unregister(&beep_drv);    
}

module_init(beep_drv_init);
module_exit(beep_drv_exit);

MODULE_LICENSE("GPL");