涉及函数与结构体
struct platform_device
struct platform_driver
platform_device_register()
platform_device_unregister()
struct file_operations
kmalloc()
register_chrdev()
class_create()
device_create()
MKDEV()
platform_get_resource()
ioremap()
resource_size()
device_destroy()
class_destroy()
unregister_chrdev()
kfree()
platform_driver_register()
platform_driver_unregister()
readl()
writel()
[1] >> 平台总线
-->>平台总线结构如下
-----------------------------------------------------------------------------------------------------------------------------------
← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ←← ← ← ← ← ← ← ← ← ← ← ← 逻辑注册链表
↓ ↑ ↗
[platform_driver1.ko] --> [platform_driver2.ko] --> [platform_driver3.ko] --> [platform_driver4.ko]
-----------------------------------------------------------------------------------------------------------------------------------
platform_bus总线
-----------------------------------------------------------------------------------------------------------------------------------
[platform_device1.ko] --> [platform_device2.ko] --> [platform_device3.ko] --> [platform_device4.ko] 硬件注册链表 resourse
↑ ↓
← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ←
-----------------------------------------------------------------------------------------------------------------------------------
struct platform_device{
const char*name;
int id;
struct device dev;
u32 num_resources;
struct resource *resource;
}
struct platform_driver {
int(* probe)( struct platform device*);
int(* remove)( struct platform device*);
struct device_driver driver:
const struct platform_device id* id_table://如果 driver支持多个平台,在列表中写出来
}
平台总线实验(利用平台总线驱动字符设备LED)
platform_device.c
#include<linux/init.h>
#include<linux/module.h>
#include<linux/platform_device.h>
#define FUNC_IN(FILE,FUNCTION) (printk("\n>>kerner:=======%s:%s IN========\n",(FILE),(FUNCTION)))
#define FUNC_OUT(FILE,FUNCTION) (printk("\n>>kerner:=======%s:%s OUT========\n",(FILE),(FUNCTION)))
MODULE_LICENSE("GPL");
void pdev_release(struct device *);
static void platform_device_exit(void);
static int platform_device_init(void);
module_init(platform_device_init);
module_exit(platform_device_exit);
struct resource pdev_resource[] =
{
{
.start = 0x11000100,
.end = 0x11000108,
.name = "pdev_resource1",
.flags = IORESOURCE_MEM
},
{
.start = 0x11000060,
.end = 0x11000068,
.name = "pdev_resource2",
.flags = IORESOURCE_MEM
}
};
struct platform_device pdev =
{
.name = "ARM_dev",
.id = -1,
.num_resources = ARRAY_SIZE(pdev_resource),
.resource = &pdev_resource,
.dev =
{
.release = pdev_release,
}
};
static int platform_device_init(void)
{
FUNC_IN(__FILE__,__FUNCTION__);
platform_device_register(&pdev);
FUNC_OUT(__FILE__,__FUNCTION__);
return 0;
}
static void platform_device_exit(void)
{
FUNC_IN(__FILE__,__FUNCTION__);
platform_device_unregister(&pdev);
FUNC_OUT(__FILE__,__FUNCTION__);
}
void pdev_release(struct device *dev)
{
}
platform_driver.c
#include<linux/init.h>
#include<linux/module.h>
#include<linux/platform_device.h>
#include<linux/fs.h>
#include<linux/kdev_t.h>
#include<linux/io.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#define FUNC_IN(FILE,FUNCTION) (printk("\n>>kerner:=======%s:%s IN========\n",(FILE),(FUNCTION)))
#define FUNC_OUT(FILE,FUNCTION) (printk("\n>>kerner:=======%s:%s OUT========\n",(FILE),(FUNCTION)))
ssize_t cdev_led1_read (struct file *, char __user *, size_t , loff_t *);
ssize_t cdev_led1_write (struct file *, const char __user *, size_t , loff_t *);
int cdev_led1_open (struct inode *, struct file *);
int cdev_led1_close (struct inode *, struct file *);
int pdrv_probe(struct platform_device *);
int pdrv_remove(struct platform_device *);
int pdrv_resume(struct platform_device *);
static int platform_driver_init(void);
static void platform_driver_exit(void);
MODULE_LICENSE("GPL");
struct CLED {
unsigned int major;
struct class *class_cled;
struct device *cdevice;
struct resource * cresource;
unsigned long *addr_start;
};
struct CLED *cled;
const struct file_operations cled_fops =
{
.read = cdev_led1_read,
.write= cdev_led1_write,
.open= cdev_led1_open,
.release = cdev_led1_close,
};
const struct platform_device_id id_table[] =
{
{
.name = "ARM_dev",
.driver_data = 1111,
},
{
.name = "cortex-A8_dev",
.driver_data = 2222,
},
{
.name = "cortex-A9_dev",
.driver_data = 333,
},
};
int pdrv_probe(struct platform_device * pdev)
{
FUNC_IN(__FILE__,__FUNCTION__);
cled = kmalloc(sizeof(struct CLED),GFP_KERNEL);
if(cled == NULL)
{
printk("\n >>%s:kmalloc error",__FUNCTION__);
}
cled->major = register_chrdev(0,"LED01",&cled_fops);
if(cled->major == 0)
{
printk("\n >>%s:register_chrdev error",__FUNCTION__);
goto error01;
}
cled->class_cled = class_create(THIS_MODULE, "class_yqj");
if(cled->class_cled == NULL)
{
printk("\n >>%s:class_create error",__FUNCTION__);
goto error02;
}
cled->cdevice = device_create(cled->class_cled,NULL,MKDEV(cled->major,01),NULL,"cdev01_node");
if(cled->cdevice <0)
{
printk("\n >>%s:device_create error",__FUNCTION__);
goto error03;
}
cled->cresource = platform_get_resource(pdev,IORESOURCE_MEM, 0);
if(cled->cdevice == NULL)
{
printk("\n >>%s:platform_get_resource error",__FUNCTION__);
}
cled->addr_start = ioremap(cled->cresource->start,resource_size(cled->cresource));
if(cled->addr_start == NULL)
{
printk("\n >>%s:ioremap error",__FUNCTION__);
goto error04;
}
printk("\n cled->cresource->start is %x",cled->cresource->start);
printk("\n cled->cresource->end is %x",cled->cresource->end);
printk("\n cled->cresource->name is %s",cled->cresource->name);
printk("\n cled->cresource->flags is %x",cled->cresource->flags);
FUNC_OUT(__FILE__,__FUNCTION__);
return 0;
error04://销毁设备节点
device_destroy(cled->class_cled,MKDEV(cled->major,01));
error03://类销毁
class_destroy(cled->class_cled);
error02://注销设备
unregister_chrdev(cled->major,"cled1");
error01://释放kmalloc内存
kfree(cled);
}
int pdrv_remove(struct platform_device * pdev)
{
FUNC_IN(__FILE__,__FUNCTION__);
iounmap(cled->addr_start);
device_destroy(cled->class_cled,MKDEV(cled->major,01));
class_destroy(cled->class_cled);
unregister_chrdev(cled->major,"cled1");
kfree(cled);
FUNC_OUT(__FILE__,__FUNCTION__);
return 0;
}
int pdrv_resume(struct platform_device *pdev)
{
}
struct platform_driver pdrv =
{
.probe = pdrv_probe,
.remove = pdrv_remove,
.driver =
{
.name = "ARM_dev",
},
.resume = pdrv_resume,
};
static int platform_driver_init(void)
{
FUNC_IN(__FILE__,__FUNCTION__);
platform_driver_register(&pdrv);
FUNC_OUT(__FILE__,__FUNCTION__);
return 0;
}
static void platform_driver_exit(void)
{
FUNC_IN(__FILE__,__FUNCTION__);
platform_driver_unregister(&pdrv);
FUNC_OUT(__FILE__,__FUNCTION__);
}
ssize_t cdev_led1_read (struct file *cdev1_file, char __user *cdev1_buf,size_t N, loff_t *offset)
{
return 0;
}
ssize_t cdev_led1_write (struct file *cdev1_file, const char __user *cdev1_buf, size_t N, loff_t *offset)
{
printk("\n=====__kernel__ :%s in=====\n",__FUNCTION__);
unsigned int reg_vlu = 0;
char tem = ' ';
__copy_from_user(&tem, cdev1_buf,1);
printk("\n__kernel__ :cdev_led1_write() is %c\n",tem);
if(tem == '0')
{
reg_vlu = readl(cled->addr_start);
reg_vlu |= (0x1 << 0);
writel(reg_vlu,cled->addr_start);
reg_vlu = readl((cled->addr_start)+1);
reg_vlu &= ~(0x1<<0);
writel(reg_vlu,(cled->addr_start)+1);
printk("\n__kernel__ :%s:close led\n",__FUNCTION__);
}
if(tem == '1')
{
reg_vlu = readl(cled->addr_start);
reg_vlu |= (0x1 << 0);
writel(reg_vlu,cled->addr_start);
reg_vlu = readl((cled->addr_start)+1);
reg_vlu |= (0x1<<0);
writel(reg_vlu,(cled->addr_start)+1);
}
printk("\n=====__kernel__ :%s out=====\n",__FUNCTION__);
return 0;
}
int cdev_led1_open (struct inode *cdev1_inode, struct file *cdev1_file)
{
printk("\n=====__kernel__ :%s in=====\n",__FUNCTION__);
printk("\n=====__kernel__ :%s out=====\n",__FUNCTION__);
return 0;
}
int cdev_led1_close (struct inode *cdev1_inode, struct file *cdev1_file)
{
printk("\n=====__kernel__ :%s in=====\n",__FUNCTION__);
printk("\n=====__kernel__ :%s out=====\n",__FUNCTION__);
return 0;
}
module_init(platform_driver_init);
module_exit(platform_driver_exit);
app.c (这个应用层的测试文件与字符驱动那个是同一个)
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
void main(int argc,char*argv[])
{
printf("%s",argv[1]);
printf("\n=====__app__:in=====\n");
int ret,tem,fd = 0;
char ledstate;
ledstate = *(char*)argv[1];
fd = open("/dev/cdev01_node",O_RDWR);
if(fd == -1)
{
perror("\nopen error\n");
}
ret = write(fd,&ledstate,1);
if(ret == -1)
{
perror("\nwrite error\n");
}
close(fd);
printf("\n=====__app__:out=====\n");
}
Makefile文件
obj-m += platform_device.o
obj-m += platform_driver.o
name1 = platform_device
name2 = platform_driver
KERNEL = /home/topeet/iTop4412_Kernel_3.0 #内核源码路径
EXE = app
PWD = $(shell pwd) #当前路径
GCC = /home/topeet/arm-2009q3/bin/arm-none-linux-gnueabi-gcc
all:
make -C $(KERNEL) M=$(PWD) modules #生成驱动模块
$(GCC) app.c -o $(EXE)
install:
cp $(name1).ko $(name2).ko $(EXE) /home/topeet/minilinux/yqj_file/modul_pro4/
下面是运行结果
[root@iTOP-4412]# insmod platform_device.ko
[ 1254.993846]
[ 1254.993850] >>kerner:=======/home/topeet/share/platform_text/platform_device.c:platform_device_init IN========
[ 1255.007022]
[ 1255.007025] >>kerner:=======/home/topeet/share/platform_text/platform_device.c:platform_device_init OUT=======
[root@iTOP-4412]# insmod platform_driver.ko
[ 1259.642814]
[ 1259.642833] >>kerner:=======/home/topeet/share/platform_text/platform_driver.c:platform_driver_init IN========
[ 1259.700550]
[ 1259.700567] >>kerner:=======/home/topeet/share/platform_text/platform_driver.c:pdrv_probe IN========
[ 1259.765283]
[ 1259.765298] cled->cresource->start is 11000100
[ 1259.769907] cled->cresource->end is 11000108
[ 1259.785121] cled->cresource->name is pdev_resource1
[ 1259.788638] cled->cresource->flags is 200
[ 1259.805098] >>kerner:=======/home/topeet/share/platform_text/platform_driver.c:pdrv_probe OUT========
[ 1259.834241]
[ 1259.834259] >>kerner:=======/home/topeet/share/platform_text/platform_driver.c:platform_driver_init OUT=======
[root@iTOP-4412]# ./app 0
0
=====__app__:i[ 1270.924756]
[ 1270.924760] =====__kernel__ :cdev_led1_open in=====
[ 1270.931073]
[ 1270.931076] =====__kernel__ :cdev_led1_open out=====
[ 1270.937485]
[ 1270.937488] =====__kernel__ :cdev_led1_write in=====
[ 1270.943893]
[ 1270.943896] __kernel__ :cdev_led1_write() is 0
[ 1270.949827]
[ 1270.949829] __kernel__ :cdev_led1_write:close led
[ 1270.955959]
[ 1270.955961] =====__kernel__ :cdev_led1_write out=====
[ 1270.962506]
[ 1270.962509] =====__kernel__ :cdev_led1_close in=====
[ 1270.968920]
[ 1270.968922] =====__kernel__ :cdev_led1_close out=====
n=====
=====__app__:out=====
[root@iTOP-4412]# ./app 1
1
=====__app__:in[ 1273.486600]
[ 1273.486619] =====__kernel__ :cdev_led1_open in=====
[ 1273.492929]
[ 1273.492943] =====__kernel__ :cdev_led1_open out=====
[ 1273.499320]
[ 1273.499334] =====__kernel__ :cdev_led1_write in=====
[ 1273.505699]
[ 1273.505712] __kernel__ :cdev_led1_write() is 1
[ 1273.511705]
[ 1273.511719] =====__kernel__ :cdev_led1_write out=====
[ 1273.518125]
[ 1273.518138] =====__kernel__ :cdev_led1_close in=====
[ 1273.524524]
[ 1273.524537] =====__kernel__ :cdev_led1_close out=====
=====
=====__app__:out=====
[root@iTOP-4412]# cat /proc/devices
Character devices:
1 mem
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
10 misc
13 input
21 sg
29 fb
81 video4linux
89 i2c
108 ppp
116 alsa
128 ptm
136 pts
153 rc522_test
166 ttyACM
180 usb
188 ttyUSB
189 usb_device
204 ttySAC
216 rfcomm
243 ump
244 mali
248 LED01 <<<<<<<-------我们注册的字符设备-----------
249 mt3326-gps
250 roccat
251 BaseRemoteCtl
252 media
253 ttyGS
254 rtc
[root@iTOP-4412]# ls /sys/class/
android_usb gpsdrv kovaplus net scsi_device ump
arvo graphics lcd power_supply scsi_disk usb_device
backlight i2c-adapter lirc ppp scsi_generic video4linux
bdi i2c-dev mali pyra scsi_host
block ieee80211 mdio_bus rc sound
bluetooth input mem rc522 spi_master
class_yqj <<<<<------我们分配的class类------- kone misc regulator switch
firmware koneplus mmc_host rtc tty
[root@iTOP-4412]# ls /sys/class/class_yqj/
cdev01_node <<<<<<我们的设备节点
[root@iTOP-4412]# ls /dev/
AGPS i2c-7 ptmx tty3
HPD input pts tty4
adc ion ram0 ttyGS0
alarm keychord ram1 ttyGS1
android_adb kmem ram10 ttyGS2
ashmem kmsg ram11 ttyGS3
buzzer_ctl leds ram12 ttyS0
cdev01_node <<<<我们的设备节点 log ram13 ttyS1
[root@iTOP-4412]# rmmod platform_driver
[ 2395.918188]
[ 2395.918192] >>kerner:=======/home/topeet/share/platform_text/platform_driver.c:platform_driver_exit IN========
[ 2395.928243]
[ 2395.928246] >>kerner:=======/home/topeet/share/platform_text/platform_driver.c:pdrv_remove IN========
[ 2395.943227]
[ 2395.943230] >>kerner:=======/home/topeet/share/platform_text/platform_driver.c:pdrv_remove OUT========
[ 2395.955736]
[ 2395.955739] >>kerner:=======/home/topeet/share/platform_text/platform_driver.c:platform_driver_exit OUT========
[root@iTOP-4412]# rmmod platform_device
[ 2404.360685]
[ 2404.360702] >>kerner:=======/home/topeet/share/platform_text/platform_device.c:platform_device_exit IN========
[ 2404.373720]
[ 2404.373738] >>kerner:=======/home/topeet/share/platform_text/platform_device.c:platform_device_exit OUT========
结束