平台设备驱动之平台驱动

2023-06-07  

驱动层需要实现的结构体是struct platform_driver,它用来描述一个设备的驱动信息。


结构如下 (includelinuxplatform_device.h)


1 struct platform_driver {

2     int (*probe)(struct platform_device *);//探测

3     int (*remove)(struct platform_device *);//移除

4     void (*shutdown)(struct platform_device *);//关闭

5     int (*suspend)(struct platform_device *, pm_message_t state);//挂起

6     int (*resume)(struct platform_device *);//唤醒

7     struct device_driver driver;

8     struct platform_device_id *id_table;

9 };


其中probe和remove是必需实现的,跟在设备层提到的注册和注销函数有关。其他函数根据需要,自行实现。


struct device_driver中的name成员很重要,必须要和设备层struct platform_device中的name成员相同,这样才能实现驱动层和设备层的绑定。


结构如下   (includelinuxdevice.h)


struct device_driver {

    const char        *name;

    struct bus_type        *bus;


    struct module        *owner;

    const char        *mod_name;    /* used for built-in modules */


    bool suppress_bind_attrs;    /* disables bind/unbind via sysfs */


    int (*probe) (struct device *dev);

    int (*remove) (struct device *dev);

    void (*shutdown) (struct device *dev);

    int (*suspend) (struct device *dev, pm_message_t state);

    int (*resume) (struct device *dev);

    const struct attribute_group **groups;


    const struct dev_pm_ops *pm;


    struct driver_private *p;

};

平台驱动层核心API

int platform_driver_register(struct platform_driver *drv)                  ( driversbaseplatform.c)

void platform_driver_unregister(struct platform_driver *drv)            ( driversbaseplatform.c)

struct resource *platform_get_resource( struct platform_device *dev, unsigned int type, unsigned int num)     ( driversbaseplatform.c)

int platform_get_irq( struct platform_device *dev, unsigned int num)     ( driversbaseplatform.c)

 

 

平台驱动的实现步骤:

1.编写probe函数

2.编写remove函数

3.定义struct platform_drv结构,并填充这个结构(注,此结构是自己定义的,结构中包含的内容也是自己定义的;这个结构其实是将驱动函数中用到的变量,写到了一起,定义成此结构,方便了其它函数的调用) 

4.在模块的初始化函数中调用platform_driver_register(struct platform_driver *drv), 以注册

5.在模块卸载函数中调用platform_driver_unregister(struct platform_driver *drv), 以注销

 

实现代码如下:leds_platform_driver.c

  1 #include

  2 #include

  3 #include

  4 

  5 #include

  6 #include

  7 #include

  8 #include

  9 #include

 10 #include

 11 #include

 12 #include

 13 #include

 14 #include

 15 #include

 16 

 17 

 18 #define uint unsigned int

 19 #define uchar unsigned char

 20 

 21 struct led_info

 22 {

 23     unsigned int pin_bit;

 24 };

 25 

 26 struct gpioreg

 27 {

 28     volatile unsigned long vr_gpbcon;

 29     volatile unsigned long vr_gpbdat;

 30     volatile unsigned long vr_gpbup;

 31 };

 32 

 33 //自己定义的struct platform_drv结构

 34 struct s3c2440_leds_drv{

 35     dev_t dev_nr;

 36     struct cdev *cdev_led;

 37     struct class *led_class;

 38     struct resource *ledres;

 39     struct led_info *led_pdata;

 40     struct device *this_device;

 41     struct gpioreg *vr_gpioreg;

 42     struct file_operations leds_ops;

 43 };

 44 

 45 #define DEVICE_NAME "s3c2440leds"

 46 #define LED_ON 1

 47 #define LED_OFF 0

 48 

 49 static struct s3c2440_leds_drv s3c2440_leds_drv_data;

 50 static int leds_open(struct inode *inode, struct file *file)

 51 {

 52     unsigned int tmp=0, up=0, dat=0;

 53     unsigned int i=0;

 54     uint pin_bit=s3c2440_leds_drv_data.led_pdata->pin_bit;

 55     

 56     tmp=s3c2440_leds_drv_data.vr_gpioreg->vr_gpbcon;

 57     up=s3c2440_leds_drv_data.vr_gpioreg->vr_gpbcon;

 58     dat=s3c2440_leds_drv_data.vr_gpioreg->vr_gpbup;

 59     printk("leds_open:1111rn");

 60 

 61     for(;i<16;i++)

 62     {

 63         if((1< 64         {                          //tmp的2i位置1,2i+1位置0,其他位不变,

 65             tmp&=~(3< 66             tmp|=(1< 67             up|=(1< 68             dat|=(1< 69         }

 70     }

 71     

 72     s3c2440_leds_drv_data.vr_gpioreg->vr_gpbcon=tmp;

 73     s3c2440_leds_drv_data.vr_gpioreg->vr_gpbup=up;

 74     s3c2440_leds_drv_data.vr_gpioreg->vr_gpbdat=dat;

 75     return 0;

 76 }

 77 

 78 static long leds_ioctl(struct file *filp, uint cmd, unsigned long arg)

 79 {

 80     uint tmp=0,i=0,j=0;

 81     uint ledbit[16]={0};

 82     uint pin_bit=s3c2440_leds_drv_data.led_pdata->pin_bit;

 83 

 84     for(i=0;i<16;i++)

 85     {

 86         if((1< 87         {

 88             ledbit[j]=i;

 89             //printk("ledbit[%d]:%drn",j,i)

 90             j++;

 91         }

 92     }

 93     //检查传入的led的编号是否大于led总数

 94     if(arg>=j)

 95         return -EINVAL;

 96     mb();//防止编译器对下面的代码进行优化

 97     tmp=s3c2440_leds_drv_data.vr_gpioreg->vr_gpbdat;

 98     mb();

 99 

100     printk("cmd:%d  tmp:%drn",cmd,tmp);

101     

102     switch(cmd)

103     {

104     case LED_ON:

105         tmp &=~(1<106         s3c2440_leds_drv_data.vr_gpioreg->vr_gpbdat=tmp;

107         return 0;

108 

109     case LED_OFF:

110         tmp|=1<111         s3c2440_leds_drv_data.vr_gpioreg->vr_gpbdat=tmp;

112         return 0;

113 

114     default:

115         printk("ioctl() cmd is errrn");

116         return -EINVAL;

117     }

118 }

119 

120 static int  led_probe(struct platform_device *pdev)

121 {

122     int msize,val,err;

123 //    printk("%s is callrn",_FUNCTION_);

124     printk("led_probe is callrn");

125 

126     //获取平台数据

127     s3c2440_leds_drv_data.led_pdata=pdev->dev.platform_data;

128     

129     if(!s3c2440_leds_drv_data.led_pdata)

130     {

131         printk("get platform_data errorn");

132         return -1;

133     }

134     

135     s3c2440_leds_drv_data.ledres=platform_get_resource(pdev,IORESOURCE_MEM,0);

136     if(!s3c2440_leds_drv_data.ledres)

137     {

138         printk("get resource errorn");

139         return -1;

140     }

141 //

142     msize=s3c2440_leds_drv_data.ledres->end-s3c2440_leds_drv_data.ledres->start+1;

143 //向内核申请资源

144     s3c2440_leds_drv_data.ledres=request_mem_region(

145             s3c2440_leds_drv_data.ledres->start,msize,DEVICE_NAME);

146     if(!s3c2440_leds_drv_data.ledres)

147     {

148         printk("request resource errorn");

149         return -1;

150     }

151 

152     s3c2440_leds_drv_data.vr_gpioreg=ioremap_nocache(

153                 s3c2440_leds_drv_data.ledres->start,msize);

154     if(!s3c2440_leds_drv_data.vr_gpioreg)

155     {

156         printk("ioremap_nocache errorn");

157         release_region(    s3c2440_leds_drv_data.ledres->start,msize);

158         return -1;

159     }

160     memset(    s3c2440_leds_drv_data.vr_gpioreg,0,sizeof(struct gpioreg));

161 //申请设备号

162     val=alloc_chrdev_region(&s3c2440_leds_drv_data.dev_nr,0,1,DEVICE_NAME);

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。