驱动层需要实现的结构体是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< 107 return 0; 108 109 case LED_OFF: 110 tmp|=1< 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);
相关文章