platform总线:是由许多AX2,AHB,APB等总线的总称,是相对于linux操作系统来说的
makefile
自动挂在驱动文件节点mknod
/dev/xx查看
而AHB,APB,AX2那些是相对于硬件底层来说。
实例:
pdev.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <linux/platform_device.h>
void led_dev_release(struct device *dev)
{
printk("led device release\n");
}
//设备基础资源信息
static struct resource s3c_led_resource[] = {
[0] = {
.start = 0xe0200280,
.end = 0xe0200280 + 0x1000,
.flags = IORESOURCE_MEM,
},
};
//平台设备结构体
struct platform_device led_platdev ={
.name = "led-dev-drv",
.dev = {
.release = led_dev_release,
},
.num_resources = ARRAY_SIZE(s3c_led_resource),
.resource = s3c_led_resource,
};
int __init led_platdev_init()
{
printk("usb dev mouse init \n");
platform_device_register(&led_platdev);
return 0;
}
void __exit led_platdev_exit()
{
printk("usb dev mouse exit \n");
platform_device_unregister(&led_platdev);
}
module_init(led_platdev_init);
module_exit(led_platdev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("GEC210");
MODULE_DESCRIPTION("just a driver test,134xxxxx;qq:3455..");
pdrv.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <asm/uaccess.h> // copy_to_user/copy_form_user
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/delay.h>
#define LED_ON 0
#define LED_OFF 1
struct resource *ptr = NULL;
unsigned long *gpj2con = NULL;
static dev_t dev_num;
static struct cdev *cdev_p;
static struct class *myclass = NULL;
struct device *mydev = NULL;
//led初始化定义
int led_open(struct inode *inode, struct file *file)
{
printk("led init ....\n");
int val;
/* led init */
val = ioread32(gpj2con);
val &=~(0xF<<0);
val |=(0x1<<0);
iowrite32(val,gpj2con);
val = ioread32(gpj2con+1);
val |=(0x1<<0);
iowrite32(val,gpj2con+1);
printk("debug_001\n");
return 0;
}
int led_close(struct inode *inode, struct file *file)
{
printk("led close ....\n");
return 0;
}
void led_on()
{
int val;
val = ioread32(gpj2con+1);
val &=~(0x1<<0);
iowrite32(val,gpj2con+1);
}
void led_off()
{
int val;
val = ioread32(gpj2con+1);
val |=(0x1<<0);
iowrite32(val,gpj2con+1);
}
//led操作
int led_ioctl(struct inode *inode,struct file *file,int cmd,int arg)
{
switch(cmd){
case LED_ON:
led_on();
break;
case LED_OFF:
led_off();
break;
}
}
//led表
struct file_operations led_fops ={
.open = led_open,
.release = led_close,
.ioctl = led_ioctl,
};
//设备名匹配成功后
int led_platdev_probe(struct platform_device *pdev)
{
printk("led driver entry>>>>>>>\n");
int val;
//从pdev.c传过来的*dev指针里resource获取基本的资源信息
int phys_addr = pdev->resource[0].start; // =0xe0200280
//端口申请
ptr = request_mem_region(phys_addr,0x1000,"led-drv");
if(ptr == NULL)
{
printk("request_mem_region\n");
return -1;
}
//端口绑定
gpj2con = (unsigned long*)ioremap(phys_addr,0x1000);
if(gpj2con == NULL)
{
printk("ioremap fail\n");
return -1;
}
//设备号动态分配
val = alloc_chrdev_region(&dev_num,0,1,"led-drv");
if(val < 0)
{
printk("all chrdev num fail\n");
return -1;
}
printk("dev number = %d ; major = %d ; minor = %d\n",dev_num,MAJOR(dev_num),MINOR(dev_num));
// 动态内存定义申请初始化
cdev_p = cdev_alloc();
cdev_init(cdev_p,&led_fops);
val = cdev_add(cdev_p,dev_num,1);
if(val)
{
printk("cdev add fail\n");
return -1;
}
//类创建
myclass = class_create(THIS_MODULE,"my-class");
if(myclass == NULL)
{
printk("cleate class fail\n");
return -1;
}
//设备创建和,这里也就不需要mknod挂设备节点了,insmod之后直接可以运行app应用程序
mydev = device_create(myclass,NULL,dev_num,NULL,"my-drv");
if(mydev == NULL)
{
printk("cleate device fail\n");
return -1;
}
return 0;
}
int led_platdev_remove(struct platform_device *pdev)
{
printk("led driver exit\n");
device_destroy(myclass,dev_num);
class_destroy(myclass);
cdev_del(cdev_p);
unregister_chrdev_region(dev_num,1);
iounmap(gpj2con);
release_mem_region(0xe0200280,0x1000);
return 0;
}
//注册的设备信息
struct platform_driver led_platdrv ={
.driver = {
.name = "led-dev-drv",
},
.probe = led_platdev_probe,
.remove = led_platdev_remove,
};
int __init led_platdrv_init()
{
printk("led plat drv init \n");
//平台设备注册
platform_driver_register(&led_platdrv);
return 0;
}
void __exit led_platdrv_exit()
{
printk("usb drv mouse exit \n");
platform_driver_unregister(&led_platdrv);
}
module_init(led_platdrv_init);
module_exit(led_platdrv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("GEC210");
MODULE_DESCRIPTION("just a driver test,134xxxxx;qq:3455..");
//平台设备注册platform_driver_register
//定义设备结构体struct platform_driver led_platdrv ={
//结构体里写好要match的设备名,退出等,然后写退出对应函数,释放掉端口映射,设备卸装等
//匹配成功后的函数int led_platdev_probe()
//probe函数里定义动态分配设备号,端口映射、绑定等。
//也可以创建类class_create(
app.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define LED_ON 0
#define LED_OFF 1
int main()
{
int fd = open("/dev/my-drv",O_RDWR);
if(fd < 0)
{
printf("open fail\n");
return -1;
}
ioctl(fd,LED_OFF);
sleep(1);
ioctl(fd,LED_ON);
close(fd);
return 0;
}
makefile
obj-m += pdev.o pdrv.o
KERNEL_DIR := /usr/mkdrv/src/android-kernel-samsung-dev
all:
make modules -C $(KERNEL_DIR) M=`pwd`
arm-linux-gcc app.c -o app
cp pdev.ko pdrv.ko app /nfs
make clean
clean:
make modules clean -C $(KERNEL_DIR) M=`pwd`
rm -rf app
由于这里还使用了类,所以不需要mknod。
加载完设备和驱动之后,就可以运行app应用程序测试。
也可以把设备动态注册platform-device改成静态注册
在内核里对应的修改,让他启动的时候自动注册pdev.c设备。
参考:
http://blog.chinaunix.net/uid-27664726-id-3334981.html
附:
类的创建
class.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <asm/uaccess.h> // copy_to_user/copy_form_user
#include <linux/device.h>
static struct class *myclass = NULL;
struct device *mydev = NULL;
static dev_t dev_num;
int __init class_init()
{
printk("usb dev mouse init \n");
int val;
myclass = class_create(THIS_MODULE,"my-class");
if(myclass == NULL)
{
printk("cleate class fail\n");
return -1;
}
val = alloc_chrdev_region(&dev_num,0,1,"led-drv");
if(val < 0)
{
printk("all chrdev num fail\n");
return -1;
}
printk("dev number = %d ; major = %d ; minor = %d\n",dev_num,MAJOR(dev_num),MINOR(dev_num));
mydev = device_create(myclass,NULL,dev_num,NULL,"my-drv");
if(mydev == NULL)
{
printk("cleate device fail\n");
return -1;
}
return 0;
}
void __exit class_exit()
{
printk("usb dev mouse exit \n");
device_destroy(myclass,dev_num);
class_destroy(myclass);
}
module_init(class_init);
module_exit(class_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("GEC210");
MODULE_DESCRIPTION("just a driver test,134xxxxx;qq:3455..");
cat /sys/class查看创建的类
自动挂在驱动文件节点mknod
/dev/xx查看