platform之led驱动分析及测试程序

Linux驱动:用platform平台总线驱动编写一个led驱动 文章目录1、平台总线1.1 简介1.2 相关API函数1.2.1 平台设备1.2.2 平台驱动1.3 驱动程序框架1.3.1 平台设备1.3.2 平台驱动3、平台驱动和平台设备老式写法(不使用设备树写法)3.1 平台设备3.2 平台驱动4、平台驱动和平台设备新式写法(使用设备树写法)4.1 平台设备(设备树节点)4.2 平台驱动(驱动代码)5、测试程序6、内核中的led驱动 1、平台总线 1.1 简介   platform平台总线并不是像usb、i2c那些物理的总线,它是在软件上实现的一种“虚拟”总线。它的 阅读详情

什么是paltform总线:

一个现实的linux设备和驱动通常都需要挂接在一种总线上,比较常见的总线有USB、PCI总线等。但是,在嵌入式系统里面,SoC系统中集成的独立的外设控制器、挂接在SoC内存空间的外设却不依附与此类总线。基于这样的背景下,2.6内核加入了platform虚拟总线。platform机制将设备本身的资源注册进内核,有内核统一管理,在驱动程序使用这些资源时使用统一的接口,这样提高了程序的可移植性。



在platform总线上注册设备和驱动,只要定义指定的结构体后调用platform给出的注册函数就可以了


linux在系统启动时就注册了platform总线,看内核代码:

/*drivers/base/platform.c*/
 static int platform_match(struct device *dev, struct device_driver *drv)
 {
     struct platform_device *pdev;

     pdev = container_of(dev, struct platform_device, dev);
     return (strcmp(pdev->name, drv->name) == 0); //配对函数检验名字是否一致
 }
。。。。。
 struct bus_type platform_bus_type = {
     .name = "platform", //定义了总线名字为platform,总线注册后新建目录sys/bus/platform
    .dev_attrs = platform_dev_attrs,
     .match = platform_match, //指定配对函数
     .uevent = platform_uevent,
     .pm = PLATFORM_PM_OPS_PTR,
 };


总线中定义了成员名字和match函数,当有总线或者设备注册到platform总线时,内核自动调用match函数


platform设备对应的结构体paltform_device:

/*linux/platform_device.h*/
 struct platform_device {
    const char * name; //设备的名字,这将代替device->dev_id,用作sys/device下显示的目录名
    int id; //设备id,用于给插入给该总线并且具有相同name的设备编号,如果只有一个设备的话填-1。
     struct device dev; //结构体中内嵌的device结构体。
     u32 num_resources; //资源数。
    struct resource * resource; //用于存放资源的数组。
 };



platform_device的注册和注销使用以下函数:

/*drivers/base/platform.c*/
 int platform_device_register(struct platform_device *pdev) //同样的,需要判断返回值
。。。
 void platform_device_unregister(struct platform_device *pdev)


会在/sys/device/目录下创建一个以name命名的目录,并且创建软连接到/sys/bus/platform/device下。


platform驱动对应的结构体paltform_driver:

/*linux/platform_device.h*/
 struct platform_driver {
    int (*probe)(struct platform_device *);
    int (*remove)(struct platform_device *);
    void (*shutdown)(struct platform_device *);
     int (*suspend)(struct platform_device *, pm_message_t state);
     int (*suspend_late)(struct platform_device *, pm_message_t state);
     int (*resume_early)(struct platform_device *);
    int (*resume)(struct platform_device *);
     struct device_driver driver;
 };



platform_driver结构体内嵌了device_driver,并且实现了prob、remove等操作。其实,当内核需要调用probe函数时,它会调用driver->probe,在dricer->probe中再调用platform_driver->probe。


platform_driver的注册和注销使用以下函数:

/*drivers/base/platform.c*/
 int platform_driver_register(struct platform_driver *drv)
。。。。。
 void platform_driver_unregister(struct platform_driver *drv)


注册成功后内核会在/sys/bus/platform/driver/目录下创建一个名字为driver->name的目录。


更多详细的关于platform或者platled的了解可以参考

http://blog.chinaunix.net/uid-25014876-id-111745.html

http://blog.youkuaiyun.com/zouleideboke/article/details/68969544

platform_LED驱动的代码:

#include "s3c_driver.h"  
  
#define DRV_AUTHOR                "fanmaolin <fanmaolinn@gmail.com>"  
#define DRV_DESC                  "S3C24XX LED driver"  
  
/* Driver version*/  
#define DRV_MAJOR_VER             1  
#define DRV_MINOR_VER             0  
#define DRV_REVER_VER             0  
  
#define DEV_NAME                  DEV_LED_NAME  
#ifndef DEV_MAJOR  
#define DEV_MAJOR                 0 /*  dynamic major by default */   
#endif  
  
#define TIMER_TIMEOUT             40  
  
static int debug = DISABLE;  
static int dev_major = DEV_MAJOR;  
static int dev_minor = 0;  
  
  
/* ============================ Platform Device part ===============================*/  
/*  LED hardware informtation structure*/  
struct s3c_led_info  
{  
    unsigned char           num;              /* The LED number  */  
    unsigned int            gpio;             /* Which GPIO the LED used */    
    unsigned char           active_level;     /* The GPIO pin level(HIGHLEVEL or LOWLEVEL) to turn on or off  */  
    unsigned char           status;           /* Current LED status: OFF/ON */  
    unsigned char           blink;            /* Blink or not */             
};  
  
/*  The LED platform device private data structure */  
struct s3c_led_platform_data  
{  
    struct s3c_led_info    *leds;  
    int                     nleds;  
};  
  
  
/*  LED hardware informtation data*/   
static struct s3c_led_info  s3c_leds[] = {  
    [0] = {  
        .num = 1,  
        .gpio = S3C2410_GPB(5),  
        .active_level = LOWLEVEL,  
        .status = OFF,  
        .blink = ENABLE,  
    },  
    [1] = {  
        .num = 2,  
        .gpio = S3C2410_GPB(6),  
        .active_level = LOWLEVEL,  
        .status = OFF,  
        .blink = DISABLE,  
    },  
    [2] = {  
        .num = 3,  
        .gpio = S3C2410_GPB(8),  
        .active_level = LOWLEVEL,  
        .status = OFF,  
        .blink = DISABLE,  
    },  
    [3] = {   
        .num = 4,  
        .gpio = S3C2410_GPB(10),  
        .active_level = LOWLEVEL,  
        .status = OFF,  
        .blink = DISABLE,  
    },   
};  
  
/*  The LED platform device private data */  
static struct s3c_led_platform_data s3c_led_data = {  			//定义LED灯的结构体信息  
    .leds = s3c_leds,  //LED灯的每条信息 
    .nleds = ARRAY_SIZE(s3c_leds),  //灯数
};  
  
struct led_device  
{  
    struct s3c_led_platform_data    *data;  
    struct cdev                     cdev;  
    struct class                    *dev_class;  
    struct timer_list               blink_timer;  
} led_device;  
  
static void platform_led_release(struct device * dev)  //撤销LED灯的函数  
{  
    int i;  
    struct s3c_led_platform_data *pdata = dev->platform_data;   
  
    dbg_print("%s():%d\n", __FUNCTION__,__LINE__);  
  
    /* Turn all LED off */  
    for(i=0; i<pdata->nleds; i++)  
    {  
         s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);   
    }  
}  
  
static struct platform_device s3c_led_device = { 							//定义设备结构体 
    .name    = "s3c_led",  
    .id      = 1,  
    .dev     =   
    {  
        .platform_data = &s3c_led_data,   
        .release = platform_led_release,  
    },  
};  
  
  
  
/* ===================== led device driver part ===========================*/  
  
void led_timer_handler(unsigned long data)  
{   
    int  i;   
    struct s3c_led_platform_data *pdata = (struct s3c_led_platform_data *)data;  
  
    for(i=0; i<pdata->nleds; i++)   
    {   
        if(ON == pdata->leds[i].status)  
        {  
              s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level);   
        }  
        else  
        {  
              s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);   
        }  
  
        if(ENABLE == pdata->leds[i].blink )  /* LED should blink */  
        {  
            /* Switch status between 0 and 1 to turn LED ON or off */  
            pdata->leds[i].status = pdata->leds[i].status ^ 0x01;    
        }  
  
        mod_timer(&(led_device.blink_timer), jiffies + TIMER_TIMEOUT);  //闪烁时间设置
    }  
}  
  
  
static int led_open(struct inode *inode, struct file *file)  //LED开启函数 
{   
    struct led_device *pdev ;  
    struct s3c_led_platform_data *pdata;  
  
    pdev = container_of(inode->i_cdev,struct led_device, cdev);  
	 /*container_of 在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针, 
就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址*/ 
    pdata = pdev->data;  
  
    file->private_data = pdata;  
  
    return 0;  
}  
  
  
static int led_release(struct inode *inode, struct file *file)  //关闭led
{   
    return 0;  
}  
  
static void print_led_help(void)  //help信息
{  
    printk("Follow is the ioctl() command for LED driver:\n");  
    printk("Enable Driver debug command: %u\n", SET_DRV_DEBUG);  
    printk("Get Driver verion  command : %u\n", GET_DRV_VER);  
    printk("Turn LED on command        : %u\n", LED_ON);  
    printk("Turn LED off command       : %u\n", LED_OFF);  
    printk("Turn LED blink command     : %u\n", LED_BLINK);  
}  
  
/* compatible with kernel version >=2.6.38*/  
static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  
{   
    struct s3c_led_platform_data *pdata = file->private_data;  
  
    switch (cmd)  
    {  
        case SET_DRV_DEBUG:  
            dbg_print("%s driver debug now.\n", DISABLE == arg ? "Disable" : "Enable");  
            debug = (0==arg) ? DISABLE : ENABLE;  
            break;  
        case GET_DRV_VER:  
            print_version(DRV_VERSION);  
            return DRV_VERSION;  
  
        case LED_OFF:  
            if(pdata->nleds <= arg)  
            {  
               printk("LED%ld doesn't exist\n", arg);    
               return -ENOTTY;  
            }  
            pdata->leds[arg].status = OFF;  
            pdata->leds[arg].blink = DISABLE;  
            break;  
  
        case LED_ON:  
            if(pdata->nleds <= arg)  
            {  
               printk("LED%ld doesn't exist\n", arg);    
               return -ENOTTY;  
            }  
            pdata->leds[arg].status = ON;  
            pdata->leds[arg].blink = DISABLE;  
            break;  
  
        case LED_BLINK:  
            if(pdata->nleds <= arg)  
            {  
               printk("LED%ld doesn't exist\n", arg);    
               return -ENOTTY;  
            }  
            pdata->leds[arg].blink = ENABLE;  
            pdata->leds[arg].status = ON;  
            break;  
  
        default:   
            dbg_print("%s driver don't support ioctl command=%d\n", DEV_NAME, cmd);   
            print_led_help();  
            return -EINVAL;  
  
    }  
    return 0;  
}  
  
  
static struct file_operations led_fops = {   
    .owner = THIS_MODULE,   
    .open = led_open,   
    .release = led_release,   
    .unlocked_ioctl = led_ioctl, /* compatible with kernel version >=2.6.38*/  
};  
  
  
static int s3c_led_probe(struct platform_device *dev) //设备和驱动相互识别是调用由内核把platform_device传到probe函数  
{  
    struct s3c_led_platform_data *pdata = dev->dev.platform_data;   
    int result = 0;  
    int i;  
    dev_t devno;  
  
    /* Initialize the LED status */  
    for(i=0; i<pdata->nleds; i++)  
    {  
         s3c2410_gpio_cfgpin(pdata->leds[i].gpio, S3C2410_GPIO_OUTPUT);  
         if(ON == pdata->leds[i].status)  
         {  
            s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level);   
         }  
         else  
         {  
            s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);   
         }  
    }  
  
    /*  Alloc the device for driver */  
    if (0 != dev_major)   
    {   
        devno = MKDEV(dev_major, dev_minor);   
        result = register_chrdev_region(devno, 1, DEV_NAME);   
    }   
    else   //动态分配主次设备号 
    {   
        result = alloc_chrdev_region(&devno, dev_minor, 1, DEV_NAME);   
        dev_major = MAJOR(devno);   
    }  
  
    /* Alloc for device major failure */   
    if (result < 0)   
    {   
        printk("%s driver can't get major %d\n", DEV_NAME, dev_major);   
        return result;   
    }  
  
    /* Initialize button structure and register cdev*/  
    memset(&led_device, 0, sizeof(led_device));  
    led_device.data = dev->dev.platform_data;  
    cdev_init (&(led_device.cdev), &led_fops);  
    led_device.cdev.owner  = THIS_MODULE;  
  
    result = cdev_add (&(led_device.cdev), devno , 1);   
    if (result)   
    {   
        printk (KERN_NOTICE "error %d add %s device", result, DEV_NAME);   
        goto ERROR;   
    }   
      
    led_device.dev_class = class_create(THIS_MODULE, DEV_NAME);   
    if(IS_ERR(led_device.dev_class))   
    {   
        printk("%s driver create class failture\n",DEV_NAME);   
        result =  -ENOMEM;   
        goto ERROR;   
    }  
  
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)       
   
  
    device_create(led_device.dev_class, NULL, MKDEV(dev_major,0), NULL, DEV_NAME);  
  
#else  
    device_create (led_device.dev_class, NULL, MKDEV(dev_major,0), DEV_NAME);  
#endif  
  
    /*  Initial the LED blink timer 初始化闪烁定时器 */  
    init_timer(&(led_device.blink_timer));  
    led_device.blink_timer.function = led_timer_handler;  
    led_device.blink_timer.data = (unsigned long)pdata;  
    led_device.blink_timer.expires  = jiffies + TIMER_TIMEOUT;//jiffies为当前时间  
    add_timer(&(led_device.blink_timer));   
  
    printk("S3C %s driver version %d.%d.%d initiliazed.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);   
  
    return 0;  
                 
  
ERROR:   
    printk("S3C %s driver version %d.%d.%d install failure.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);   
    cdev_del(&(led_device.cdev));   
  
    unregister_chrdev_region(devno, 1);   
    return result;  
  
}  
  
static int s3c_led_remove(struct platform_device *dev)  //释放主次设备号给Linux内核
{  
    dev_t devno = MKDEV(dev_major, dev_minor);  
  
    del_timer(&(led_device.blink_timer));  
  
    cdev_del(&(led_device.cdev));   
    //for()  
    device_destroy(led_device.dev_class, devno);   
    class_destroy(led_device.dev_class);   
      
    unregister_chrdev_region(devno, 1);   
    printk("S3C %s driver removed\n", DEV_NAME);  
  
    return 0;  
}  
  
  
static struct platform_driver s3c_led_driver = {   //定义总线驱动结构体 
    .probe      = s3c_led_probe,   //注册设备主次设备号
    .remove     = s3c_led_remove,   
    .driver     = {   
        .name       = "s3c_led",   
        .owner      = THIS_MODULE,   
    },  
};  
  
  
static int __init s3c_led_init(void)  
{  
   int       ret = 0;  
  
   ret = platform_device_register(&s3c_led_device);  
   if(ret)  
   {  
        printk(KERN_ERR "%s:%d: Can't register platform device %d\n", __FUNCTION__,__LINE__, ret);   
        goto fail_reg_plat_dev;  
   }  
   dbg_print("Regist S3C LED Platform Device successfully.\n");  
  
   ret = platform_driver_register(&s3c_led_driver);  
   if(ret)  
   {  
        printk(KERN_ERR "%s:%d: Can't register platform driver %d\n", __FUNCTION__,__LINE__, ret);   
        goto fail_reg_plat_drv;  
   }  
   dbg_print("Regist S3C LED Platform Driver successfully.\n");  
  
   return 0;  
  
fail_reg_plat_drv:  
   platform_driver_unregister(&s3c_led_driver);  
fail_reg_plat_dev:  
   return ret;  
}  
  
  
static void s3c_led_exit(void)  
{  
    dbg_print("%s():%d remove LED platform drvier\n", __FUNCTION__,__LINE__);  
    platform_driver_unregister(&s3c_led_driver);  
    dbg_print("%s():%d remove LED platform device\n", __FUNCTION__,__LINE__);  
    platform_device_unregister(&s3c_led_device);  
}  
  
module_init(s3c_led_init);  
module_exit(s3c_led_exit);  
  
module_param(debug, int, S_IRUGO);  
module_param(dev_major, int, S_IRUGO);  
module_param(dev_minor, int, S_IRUGO);  
  
MODULE_AUTHOR(DRV_AUTHOR);  
MODULE_DESCRIPTION(DRV_DESC);  
MODULE_LICENSE("GPL");  
MODULE_ALIAS("platform:S3C24XX_led");  

Makefile:

obj-m:=plat_led.c  
C=/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gcc  
KDIR?=/home/fanmaolin/fl2440/kernel/linux-3.0  
obj-m:=plat_led.o  
   
default:  
        $(MAKE) -C $(KDIR) M=`pwd` modules  
        make clean  
   
clean:  
        rm -f *.o *mod.c *.order *.symvers  


make


测试程序vim plat_ioctl.c:

 1 /*********************************************************************************
  2  *      Copyright:  (C) 2017 fanmaolin<fanmaolinn@gmail.com>
  3  *                  All rights reserved.
  4  *
  5  *       Filename:  plat_testled.c
  6  *    Description:  This file 
  7  *                 
  8  *        Version:  1.0.0(03/25/2017)
  9  *         Author:  fanmaolin <fanmaolinn@gmail.com>
        
 10  *      ChangeLog:  1, Release initial version on "03/25/2017 05:24:09 PM"
 11  *                 
 12  ********************************************************************************/
 13 
 14 #include <stdio.h>
 15 #include <stdarg.h>
 16 #include <fcntl.h>
 17 #include <sys/types.h>
 18 #include <errno.h>
 19 #include <sys/ioctl.h>
 20 #include <sys/stat.h>
 21 #include <unistd.h>
 22 #include <stdlib.h>
 23 #define PLATDRV_MAGIC             0x60  
 24 #define LED_OFF                   _IO (PLATDRV_MAGIC, 0x18)  
 25 #define LED_ON                    _IO (PLATDRV_MAGIC, 0x19)  
 26 #define LED_BLINK                 _IO (PLATDRV_MAGIC, 0x1A)  
 27 #define  DEVNAMELEN 10  
 28 int main (int argc,char **argv)
 29 {
 30         int fd;
 31         fd=open("dev/led",O_RDWR);
 32         ioctl(fd,LED_ON,0);
 33         ioctl(fd,LED_BLINK,1);
 34         ioctl(fd,LED_ON,2);
 35         ioctl(fd,LED_BLINK,4);
 36         close(fd);
 37         return 0;
 38 }


[fanmaolin@Centeros platform]$ /opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gcc plat_testled.c 

编译后在开发板上操作,与之前不同的是这一次程序中有了自动挂载的代码:

   
    led_device.dev_class = class_create(THIS_MODULE, DEV_NAME);   
    if(IS_ERR(led_device.dev_class))   
    {   
        printk("%s driver create class failture\n",DEV_NAME);   
        result =  -ENOMEM;   
        goto ERROR;   
    }  
  
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)       
   
  
    device_create(led_device.dev_class, NULL, MKDEV(dev_major,0), NULL, DEV_NAME);  
  
#else  
    device_create (led_device.dev_class, NULL, MKDEV(dev_major,0), DEV_NAME);  
#endif  
  



>: tftp -gr a.out 192.168.1.2
a.out                100% |*******************************|  5139   0:00:00 ETA

>: insmod plat_led.ko 
S3C led driver version 1.0.0 initiliazed.
>: ./a.out 

你会看到1、3灯常亮,2、4灯闪烁

问题总结分析:

[fanmaolin@Centeros platform]$ make
make -C /home/fanmaolin/fl2440/kernel/linux-3.0   M=`pwd` modules 
make[1]: Entering directory `/home/fanmaolin/fl2440/kernel/linux-3.0'
  CC [M]  /home/fanmaolin/fl2440/driver/led/platform/plat_led.o
/home/fanmaolin/fl2440/driver/led/platform/plat_led.c:1:26: fatal error: s3c_driver.h: No such file or directory
compilation terminated.
make[2]: *** [/home/fanmaolin/fl2440/driver/led/platform/plat_led.o] Error 1
make[1]: *** [_module_/home/fanmaolin/fl2440/driver/led/platform] Error 2
make[1]: Leaving directory `/home/fanmaolin/fl2440/kernel/linux-3.0'
make: *** [default] Error 2
缺少部分头文件,加在当前目录下即可参考http://blueshaw.blog.163.com/blog/static/21633118120138249298645/头文件的有关知识

s3c_drive.h:

#ifndef __S3C_DRIVER_H  
#define __S3C_DRIVER_H  
  
#include <linux/version.h>  
#include <linux/kernel.h>  
#include <linux/errno.h>  
#include <linux/init.h>  
#include <linux/slab.h>  
#include <linux/module.h>  
#include <linux/kref.h>  
#include <linux/spinlock.h>  
#include <asm/uaccess.h>  
#include <linux/mutex.h>  
#include <linux/delay.h>  
#include <linux/fs.h>  
#include <linux/device.h>  
#include <linux/i2c.h>  
#include <linux/string.h>  
#include <linux/bcd.h>  
#include <linux/miscdevice.h>  
#include <linux/poll.h>  
#include <linux/irq.h>  
#include <linux/interrupt.h>  
#include <linux/sysfs.h>  
#include <linux/proc_fs.h>  
#include <linux/rtc.h>  
#include <linux/spinlock.h>  
#include <linux/usb.h>  
#include <asm/uaccess.h>  
#include <asm/delay.h>  
#include <linux/syscalls.h>  /* For sys_access*/  
#include <linux/platform_device.h>  
#include <linux/unistd.h>  
#include <linux/tty.h>  
#include <linux/tty_flip.h>  
#include <linux/serial.h>  
#include <linux/serial_core.h>  
#include <linux/irq.h>  
#include <mach/regs-gpio.h>  
  
  
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)  
#include <mach/hardware.h>  
#include <mach/gpio.h>  
#include <asm/irq.h>  
#else  
#include <asm-arm/irq.h>  
#include <asm/arch/gpio.h>  
#include <asm/arch/hardware.h>  
#endif  
#include "plat_ioctl.h"  
  
/* =========================================================================== 
 *  *         S3C24XX device driver common macro definition 
 *   *===========================================================================*/  
  
#define ENPULLUP                    1  
#define DISPULLUP                   0  
  
#define HIGHLEVEL                   1  
#define LOWLEVEL                    0  
  
#define INPUT                       1  
#define OUTPUT                      0  
  
#define OFF                         0  
#define ON                          1  
  
#define ENABLE                      1  
#define DISABLE                     0  
  
#define TRUE                        1  
#define FALSE                       0  
  
/* =========================================================================== 
 *  *         S3C24XX device driver name and Major number define 
 *   *===========================================================================*/  
  
  
#define DEV_LED_NAME                "led"  
#define DEV_LED_MAJOR               203  
  
#define DEV_BUTTON_NAME             "button"  
#define DEV_BUTTON_MAJOR            "211"  
  
#define DEV_ADC_NAME                "adc"  
#define DEV_ADC_MAJOR               "212"  
  
/*  ***** Bit Operate Define *****/  
#define SET_BIT(data, i)   ((data) |=  (1 << (i)))    /*   Set the bit "i" in "data" to 1  */  
#define CLR_BIT(data, i)   ((data) &= ~(1 << (i)))    /*   Clear the bit "i" in "data" to 0 */  
#define NOT_BIT(data, i)   ((data) ^=  (1 << (i)))    /*   Inverse the bit "i" in "data"  */  
#define GET_BIT(data, i)   ((data) >> (i) & 1)        /*   Get the value of bit "i"  in "data" */  
#define L_SHIFT(data, i)   ((data) << (i))            /*   Shift "data" left for "i" bit  */  
#define R_SHIFT(data, i)   ((data) >> (i))            /*   Shift "data" Right for "i" bit  */  
  
  
/* =========================================================================== 
 *  *         S3C24XX device driver common function definition 
 *   *===========================================================================*/  
  
#define SLEEP(x)    {DECLARE_WAIT_QUEUE_HEAD (stSleep); if (10 > x) mdelay ((x * 1000)); \  
                        else wait_event_interruptible_timeout (stSleep, 0, (x / 10));}  
  
#define VERSION_CODE(a,b,c)       ( ((a)<<16) + ((b)<<8) + (c))  
#define DRV_VERSION               VERSION_CODE(DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER)  
#define MAJOR_VER(a)              ((a)>>16&0xFF)  
#define MINOR_VER(a)              ((a)>>8&0xFF)  
#define REVER_VER(a)              ((a)&0xFF)  
  
#define dbg_print(format,args...) if(DISABLE!=debug) \  
        {printk("[kernel] ");printk(format, ##args);}  
  
static inline void print_version(int version)  
{  
#ifdef __KERNEL__  
        printk("%d.%d.%d\n", MAJOR_VER(version), MINOR_VER(version), REVER_VER(version));  
#else  
        printf("%d.%d.%d\n", MAJOR_VER(version), MINOR_VER(version), REVER_VER(version));  
#endif  
}  
  
  
#endif /* __S3C_DRIVER_H */  

plat_ioctl.h:

  1. #ifndef __PLAT_IOCTL_H  
  2. #define __PLAT_IOCTL_H  
  3.   
  4. #include <asm/ioctl.h>  
  5.   
  6. /*=========================================================================== 
  7.  *  *                Common ioctl command definition 
  8.  *   *===========================================================================*/  
  9.   
  10. #define PLATDRV_MAGIC           0x60  
  11.   
  12. /*=========================================================================== 
  13.  *  *                 ioctl command for all the drivers 0x01~0x0F 
  14.  *   *===========================================================================*/  
  15.   
  16. /*args is enable or disable*/  
  17. #define SET_DRV_DEBUG               _IO (PLATDRV_MAGIC, 0x01)  
  18. #define GET_DRV_VER                 _IO (PLATDRV_MAGIC, 0x02)  
  19.   
  20. /*=========================================================================== 
  21.  *  *                 ioctl command for few ioctl() cmd driver 0x10~0x2F 
  22.  *   *===========================================================================*/  
  23.   
  24. /* LED driver */  
  25. #define LED_OFF                     _IO (PLATDRV_MAGIC, 0x18)  
  26. #define LED_ON                      _IO (PLATDRV_MAGIC, 0x19)  
  27. #define LED_BLINK                   _IO (PLATDRV_MAGIC, 0x1A)  
  28. #define ADC_SET_CHANNEL             _IO (PLATDRV_MAGIC, 0x1B)  
  29.   
  30. /*=========================================================================== 
  31.  *  *                   ioctl command for GPRS driver 0x30~0x4F 
  32.  *   *===========================================================================*/  
  33. #define GPRS_POWERDOWN              _IO (PLATDRV_MAGIC, 0x30)  
  34. #define GPRS_POWERON                _IO (PLATDRV_MAGIC, 0x31)  
  35. #define GPRS_RESET                  _IO (PLATDRV_MAGIC, 0x32)  
  36. #define GPRS_POWERMON               _IO (PLATDRV_MAGIC, 0x33)  
  37. #define GPRS_CHK_SIMDOOR            _IO (PLATDRV_MAGIC, 0x36)  
  38. #define GPRS_SET_DTR                _IO (PLATDRV_MAGIC, 0x37)  
  39. #define GPRS_SET_RTS                _IO (PLATDRV_MAGIC, 0x38)  
  40. #define GPRS_GET_RING               _IO (PLATDRV_MAGIC, 0x39)  
  41. #define SET_PWUP_TIME               _IO (PLATDRV_MAGIC, 0x3A)  
  42. #define SET_PWDOWN_TIME             _IO (PLATDRV_MAGIC, 0x3B)  
  43. #define SET_RESET_TIME              _IO (PLATDRV_MAGIC, 0x3C)  
  44. #define GPRS_CHK_MODEL              _IO (PLATDRV_MAGIC, 0x3E)  
  45.   
  46. /*=========================================================================== 
  47.  *  *                   ioctl command for EEPROM driver 0x50~0x5F 
  48.  *   *===========================================================================*/  
  49. #define LL_POWEROFF                 _IO (PLATDRV_MAGIC, 0x50)  
  50. #define LL_POWERON                  _IO (PLATDRV_MAGIC, 0x51)  
  51. #define LL_STOP                     _IO (PLATDRV_MAGIC, 0x52)  
  52. #define LL_START                    _IO (PLATDRV_MAGIC, 0x53)  
  53. #define LL_READ                     _IO (PLATDRV_MAGIC, 0x54)  
  54. #define LL_WRITE                    _IO (PLATDRV_MAGIC, 0x55)  
  55. #define LL_DATALOW                  _IO (PLATDRV_MAGIC, 0x56)  
  56. #define LL_ACKNAK                   _IO (PLATDRV_MAGIC, 0x57)  
  57.   
  58.   
  59. #endif                          /* __PLAT_IOCTL_H */  







S-function入门及案例详解(3)——S-function进阶案例 目录1.案例描述2.案例详解3.输出波形4.对输入参数进行Mask打包 1.案例描述 设计一个蹦极系统 h为离地面高度,输入参数为长度、质量、离地面高度。 2.案例详解 步骤1.可以修改sfuntmpl函数的名称(这里修改为bengji),并在括号内增加输入参数 参数len,weight,dist分别表示长度、质量、离地面高度;长度用来初始化x0,质量用来初始化m,离地面高度用来初始化h。 function [sys,x0,str,ts,simStateCompliance] = bengji(t,x,u 阅读详情

相关推荐

SO逆向入门实战教程一:OASIS

文章目录一、前言二、准备三、Unidbg模拟执行四、ExAndroidNativeEmu 模拟执行五、算法分析六、尾声 一、前言 这是SO逆向入门实战教程的第一篇,总共会有十三篇,十三个实战。有以下几个注意点: 主打入门级的实战,适合有一定基础但缺少实战的朋友(了解JNI,也上过一些Native层逆向的课,但感觉实战匮乏,想要壮壮胆,入入门)。 侧重新工具、新思路、新方法的使用,算法分析的常见路子是Frida Hook + IDA ,在本系列中,会淡化Frida 的作用,采用Unidbg Hook + .

lilac的博客 2万+

ZYNQ SPI测试

ZYNQ平台下的SPI开发,以自发自收为例子。

北京菜刀 1万+

5GCPE与4G物联网卡兼容实战:通过AT指令修改IMEI实现设备迁移

本文详细介绍了如何通过AT指令修改5GCPE设备的IMEI,实现4G物联网卡的设备迁移。从硬件准备、驱动安装到串口工具配置,再到具体的AT指令操作步骤,提供了全面的实战指南。文章还包含信号优化、APN设置等实用技巧,帮助用户顺利完成设备迁移并提升网络性能。

weixin_28684757的博客 633

linux的SPI设备驱动程序

串行外设接口(SPI)是四线总线:MOSI、MISO、串行时钟SCK和片选CS。它常用于连接闪存、AD/DA转换器。主设备生成时钟和管理片选CS,速度可达80MB,远超I2C总线。

Icewaver的专栏 2744

电力抄表协议DL/T645和698.45到底有啥区别?一张图帮你选对协议

本文深入对比了电力抄表协议DL/T645和DL/T698.45的技术差异,从协议架构、报文结构、功能覆盖到实施成本进行全面分析。通过实际案例和数据,揭示698.45协议在通信效率、业务扩展性和长期成本上的优势,并提供清晰的选型决策流程图,帮助工程师根据具体需求选择最适合的电力抄表协议。

weixin_38168696的博客 401

SQL Server 内存占用高分析及解决办法(超详细)

如果想让 Sql Server 主动释放 占用并空闲的内存空间,可以设置Sql Server占用内存的上限,就会让Sql server在。如执行存储过程,自定函数时,SQL Server 需要先二进制编译再运行,编译后的结果也会缓存起来,再次调用时就无需再次编译。才会释放一点占用的内存,所以很多时候,我们会发现运行SQL Server的系统内存往往居高不下这些内存一般都。缓存,以便于再次请求此页的数据的时候,直接从内存返回,就无需读取磁盘了,大大提高了速度。最后文章有啥不对,欢迎大佬在评论区指点!

2301_79080944的博客 3952

Linux Platform总线+SPI总线分析

本文以MPC8308(powerpc架构),HX软件包为依据,详细内容可参考源码 CPU: e300c3MPC8308 400MHz BOARD: Freescale MPC8308ERDB DRAM: 256M NAND: 1024M

风之伤 2864

Python+Selenium实战:5分钟搞定快手评论区数据采集(附完整代码)

本文详细介绍了如何使用Python和Selenium快速采集快手评论区数据,提供完整的代码实现和优化方案。通过动态加载处理和智能等待策略,5分钟内即可构建高效的评论采集工具,适用于用户行为分析和内容挖掘等场景。

weixin_30415113的博客 344

spi的platform_device

在dev-spi.c中 /* SPI (0) */ static struct resource s3c_spi0_resource[] = { [0] = { .start = S3C_PA_SPI0, .end   = S3C_PA_SPI0 + S3C_S

prothes 的专栏 1493

RK3568平台开发系列讲解:内核启动流程

第 493 行的 ENTRY 指明了了 Linux 内核入口,入口为stext,stext 定义在文件arch/arm/kernel/head.S 中 , 因此要分析Linux 内核的启动流程,就得先从文件arch/arm/kernel/head.S 的 stext 处开始分析。_mmap_switched 定义在文件 arch/arm/kernel/head-common.S,__mmap_switched 最终会调用 start_kernel 函数。⑥、r2=atags 或者设备树(dtb)首地址。

内核笔记 217

14、5G物理层的灵活解决方案:广义频分复用(GFDM)

广义频分复用(GFDM)作为一种高度灵活的5G物理层多载波调制方案,能够满足多样化应用场景的需求,包括高吞吐量的比特管道通信、低功耗高连接数的物联网、超低延迟的触觉互联网以及广覆盖的无线区域网。通过参数化配置,GFDM可适配LTE资源网格,实现与现有系统的兼容与共存。其支持多种解调方式、干扰消除技术、OQAM映射及预编码机制,兼具低带外发射、高频谱效率和强鲁棒性。GFDM还能统一描述OFDM、FBMC、FTN等多种经典与先进波形,成为5G及未来通信系统中极具潜力的通用波形框架。

gold8的专栏 108

SPI设备驱动简单测试例子

内容如下:  /* test spi device driver add by zjh 2011-08-10 */ #include #include #include #include #include #include #include #include #define TEST_REG 0x08 static int read_reg(stru

3072

论文研读 Corundum: An Open-Source 100-Gbps NIC

Corundum 通过在 FPGA 上构建并行 pipeline、高效 DMA 通道、无阻塞队列结构、低延迟调度器,实现了在 PCIe Gen3 x16 接口上稳定跑满 100Gbps 吞吐量。

Double Galaxy 489

修改之前的代码使得利用设备树文件和Platform总线设备驱动实现对多个LED的驱动【只是假想对LED进行驱动,并没有实际的硬件操作】

<16GROUP_PIN是一个宏,用于计算某个引脚的编号。参数:g表示引脚组编号(group)。p表示组内的引脚编号(pin)。逻辑:(g << 16)将组号左移 16 位,将其放在 32 位整数的高 16 位。| (p)将组内引脚编号放在低 16 位。结果:宏返回一个 32 位的整数,高 16 位表示组号,低 16 位表示组内引脚号。例如,的结果是。/ {根节点是设备树的根节点,表示整个设备树的顶级结构。设备节点swh_led@0。

昊虹AI笔记 1022

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

利用设备树、Platform驱动总线、Linux的GPIO子系统和开发板的BSP(板级支持包)来实现LED的驱动程序

* 根据次设备号初始化LED */return 0;这个函数在设备文件打开时被调用,即内核函数open()调用的底层函数。函数是GPIO子系统中的一个函数,它通过调用BSP中的相关函数来实现对GPIO口的设置(关于BSP是如何编译进内核的,可以参考),这行代码的具体解释如下:这行代码的作用是设置一个 GPIO 引脚为输出模式,并初始化其输出电平。函数原型参数说明desc是一个 GPIO 描述符,表示要操作的 GPIO 引脚。这里的led_gpio是通过。

昊虹AI笔记 1169

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

c++mfc编写实验_「正点原子Linux连载」第五十四章 platform设备驱动实验(二)

1)实验平台:正点原子Linux开发板2)摘自《正点原子I.MX6U嵌入式Linux驱动开发指南》关注官方微信号公众号,获取更多资料:正点原子54.3硬件原理图分析本章实验我们只使用到IMX6U-ALPHA开发板上的LED灯,因此实验硬件原理图参考8.3小节即可。54.4试验程序编写本实验对应的例程路径为:开发板光盘->2、Linux驱动例程->17_platform。本章实验我们需要...

weixin_39686230的博客 207

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

利用Linux的Platform总线设备驱动实现对多个LED的驱动【只是假想对LED进行驱动,并没有实际的硬件操作】【Makefile如何书写能生成多个模块文件】【总线设备驱动的好处】

Platform 总线设备驱动是一种基于 Linux 驱动模型的驱动框架,专门用于管理片上系统 (SoC) 内部的硬件资源。这种框架非常适合开发嵌入式设备中与具体硬件总线无关的驱动程序,例如板载 LED、GPIO、按键等。1. Platform 总线设备驱动的基本概念Platform 总线 (Platform Bus)是一种虚拟总线,与硬件无关,用于匹配设备()和驱动(Platform 设备 (Platform Device)表示具体的硬件资源,例如板载的 LED、UART 控制器等。

昊虹AI笔记 917

Linux 下的 platform 驱动开发模板

platform设备驱动实验

安迪西_嵌入式攻城狮 1466

无设备树platform设备驱动实验:驱动加载测试

无设备树platform设备驱动实验:驱动功能加载测试

wojiaxiaohuang2014的博客 526

platform设备驱动实验

Linux系统内核使用bus_type结构体表示总线,此结构体定义在文件bus_type。

zzipeng的博客 745

实现一个platporm架构的LED驱动

目标:编写一个platporm架构的LED驱动 参考知识: 在Linux字符设备驱动编程模型中,只要应用程序open()了相应的设备文件,就可以使用ioctl通过驱动程序来控制我们的硬件,这种模型直观,但是从软件设计的角度看,却是一种十分糟糕的方式,它有一个致命的问题,就是设备信息和驱动代码冗余在一起,一旦硬件信息发生改变甚至设备已经不在了,就必须要修改驱动源码,非常的麻烦,为了解决这种驱动代码和设备信息耦合的问题,Linux提出了platform bus(平台总线)的概念,即使用虚拟总线将设备信息和驱

nucleare的博客 480

i.MX6ULL终结者Platform设备驱动实验程序

文章目录1 Platform设备和驱动程序2 应用测试程序 1 Platform设备和驱动程序 本实验例程路径:i.MX6UL终结者光盘资料/06_Linux驱动例程/14_gpioled_platform 我们先来看一下platform设备和驱动程序,创建led_device.c和led_driver.c两个文件,分别表示LED灯的platform设备和platform驱动文件。 led_device.c文件具体内容如下: 1 #include <linux/types.h> 2 #i

weixin_46635880的博客 184

嵌入式 Linux Platform 驱动模型测试

概念作用Platform 总线负责匹配设备和驱动,像“红娘”一样连接两者。Platform 设备描述硬件资源(寄存器、中断等),通常通过设备树定义。Platform 驱动实现设备操作逻辑,通过probe()初始化设备,通过remove()释放资源。

weixin_63577471的博客 1717

迅为i.MX6ULL终结者设备树下的Platform驱动实验程序编写

文章目录 1 修改设备树文件 2 platform驱动程序 3 应用测试程序 1 修改设备树文件 设备树文件可以直接使用第三十五章中添加的gpioled子节点即可,不用重复添加。 2 platform驱动程序 本实验例程路径:i.MX6UL终结者光盘资料/06_Linux驱动例程/15_gpioled_dts 创建led_driver.c文件,具体内容如下: 1 #include <linux/types.h> 2 #include <linux/ker..

mucheni的博客 123

迅为i.MX6ULL开发板Platform设备驱动运行测试

文章目录 1 编译驱动和设备程序 2 编译应用测试程序 3 运行测试 1 编译驱动和设备程序 和前面章节中驱动测试程序一样需要一个Makefile文件,只是将obj-m的值改为led_device.o led_driver.o,Makefile文件内容如下: 首先我们在终端输入两个命令(设置两个环境变量): 然后执行“make”命令编译模块,编译完成生成led_device.ko和led_driver.ko模块文件。 2 编译应用测试程序 输入如下命令编译应用测试程序: ...

mucheni的博客 180

Linux Platform设备驱动学习与小结

Platform 设备先被注册然后platfrom驱动加载时会调用驱动程序中的probe()入口函数,扫描系统中已注册的设备,通过。Name域找到匹配设备后将驱动和设备绑定。一个驱动可以对应多个设备,但是一个设备只对一个驱动。Linux下的虚拟总线platform对应设备platform_device,对应的驱动为platform_driver。一个很不恰当的例子:设备好比男人,驱动好比女人,pl

1926
上一篇: s3c2440-led驱动分析注释及一次跑马灯测试程序
下一篇: windows10 如何给应用程序设置快捷键及一些常用好玩快捷键
fml1997
博客等级 码龄10年 30粉丝 56原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值