平台总线(三)

来源:互联网 发布:java自动代码生成器 编辑:程序博客网 时间:2024/04/26 09:26
平台总线:用于平台升级的
三星: 
s3c2410  --------------- s3c6410 ----------- s5pv210
gpio控制器            gpio控制器gpio控制器
 uart 
 i2c
 spi

控制逻辑方法相同:1,配置gpio寄存器
    2.读写数据

地址会不同


三元素:
总线: 开机的时候就已经创建了,不需要我们创建
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};


device对象:
struct platform_device {//是一个名字,描述设备属性
const char * name; //用于匹配
int id;
struct device dev; //继承父类
u32 num_resources;
struct resource* resource; // 描述设备的资源---地址和中断
};


struct resource {
resource_size_t start; //起始位置
resource_size_t end; //结束位置
const char *name; //自定义
unsigned long flags;//区分是地址还是中断资源:IORESOURCE_IRQ, IORESOURCE_MEM
}


driver对象
struct platform_driver {
int (*probe)(struct platform_device *);//表示匹配成功之后被调用
int (*remove)(struct platform_device *);
struct device_driver driver;//继承父类
const struct platform_device_id *id_table;//用于匹配
};


pdrv中获取资源:
/**
* 参数1: pdev
* 参数2: 获取的是中断资源还是内存资源 
* 参数3: 同种资源中第几个
*/
struct resource * platform_get_resource(struct platform_device * dev,unsigned int type,unsigned int num)


在probe方法中:
1,申请主设备号  register_chrdev_region (与内核相关)
2,注册字符设备驱动 cdev_alloc  cdev_init  cdev_add (与内核相关)
3,利用udev/mdev机制创建设备文件(节点) class_create, device_create (与内核相关)
4,实现操作硬件方法  xxx_open,xxx_read,xxxx_write...(与硬件相关)
5,硬件初始化
最重要的:

获取到资源,利用资源进行硬件初始化

/* led_test.c */#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>int main(void){int fd;int on;fd = open("/dev/led0", O_RDWR);while (1) {on = 1;write(fd,&on, 4);sleep(1);on = 0;write(fd,&on, 4);sleep(1);}close(fd);return 0;}

/* plat_led_dev.c */#include <linux/init.h>#include <linux/module.h>#include <linux/platform_device.h>#define GPC0CON 0xE0200060#define GPC_SIZE 24//用于演示,没有实际设备对应#define GPA0CON 0xE0200000#define GPA_SIZE 24struct resource led_res[] = {/*实际所用到的*/[0] = {.start = GPC0CON,.end = GPC0CON + GPC_SIZE - 1,.flags = IORESOURCE_MEM,},/*假如有其他的资源,比如有中断*/[1] = {.start = 888,.end = 1212,.flags = IORESOURCE_IRQ,},[2] = {.start = GPA0CON,.end = GPA0CON + GPC_SIZE - 1,.flags = IORESOURCE_MEM,},};struct platform_device led_pdev = {.name = "s5pv210_led",.id = -1,.num_resources = ARRAY_SIZE(led_res),.resource = led_res,};static int __init plat_led_dev_init(void){/*注册一个平台设备*/ printk("------*_^%s--------\n",__FUNCTION__);    return platform_device_register(&led_pdev);}static void __exit plat_led_dev_exit(void){/*注销平台设备*/platform_device_unregister(&led_pdev);    printk("------*_^%s--------\n",__FUNCTION__);}module_init(plat_led_dev_init);module_exit(plat_led_dev_exit);MODULE_LICENSE("GPL");

/* plat_led_drv.c */#include <linux/init.h>#include <linux/module.h>#include <linux/platform_device.h>#include <linux/fs.h>#include <linux/slab.h>#include <asm/uaccess.h>#include <asm/io.h>/*设计一个对象,表示一个全局的设备对象*/struct samsung_led{int dev_major;struct class *cls;struct device *dev;struct resource *res;void *reg_addr; //虚拟地址};struct samsung_led * led_dev;int led_pdrv_open(struct inode *inode, struct file *filp){printk("-------^_*  %s-----------\n", __FUNCTION__);return 0;}ssize_t led_pdrv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos){int value;int ret;ret  = copy_from_user(&value, buf, count);if (ret > 0) {printk("copy_from_user error\n");return -EFAULT;}if (value) {//点灯__raw_writel(__raw_readl(led_dev->reg_addr + 4) | (0x3<<3), led_dev->reg_addr + 4);}else{__raw_writel(__raw_readl(led_dev->reg_addr + 4) & ~(0x3<<3), led_dev->reg_addr + 4);}return count;}int led_pdrv_close(struct inode *inode, struct file *filp){printk("-------^_*  %s-----------\n", __FUNCTION__);return 0;}struct file_operations led_fops = {.open = led_pdrv_open,.write = led_pdrv_write,.release = led_pdrv_close,};int led_pdrv_probe(struct platform_device *pdev){/*需要向应用空间提供接口1,申请设备号2,创建文件*/printk("-------^_*  %s-----------\n", __FUNCTION__);/*申请空间*/led_dev = kzalloc(sizeof(struct samsung_led), GFP_KERNEL); /*动态申请设备*/led_dev->dev_major = register_chrdev(0, "led_drv", &led_fops);/*创建设备类*/led_dev->cls = class_create(THIS_MODULE, "led_cls");/*创建字符设备*/led_dev->dev = device_create(led_dev->cls,NULL, MKDEV(led_dev->dev_major, 0), NULL, "led%d", 0);led_dev->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//可以进行映射led_dev->reg_addr = ioremap(led_dev->res->start, resource_size(led_dev->res));//获取中断int irqno = platform_get_irq(pdev, 0);printk("irqno  = %d\n", irqno );// 配置gpio为输出unsigned int temp = __raw_readl(led_dev->reg_addr);temp &= ~(0xff<<12);temp |= (0x11<<12);__raw_writel(temp,led_dev->reg_addr);return 0;}int led_pdrv_remove(struct platform_device *pdev){iounmap(led_dev->reg_addr);device_destroy(led_dev->cls,MKDEV(led_dev->dev_major, 0));class_destroy(led_dev->cls);unregister_chrdev(led_dev->dev_major,"led_drv");kfree(led_dev);return 0;}/*用于匹配*/const struct platform_device_id led_id_table[] = {{"s3c2410_led", 1111},{"s3c6410_led", 2222},{"s5pv210_led", 3333},};struct platform_driver led_drv = {.probe = led_pdrv_probe,.remove = led_pdrv_remove,.driver = {.name = "s5pv210_led"// 随便写,用于匹配,/sys/bus/platform/drivers/samsung_led_drv},.id_table = led_id_table,//优先匹配列表中的名字,如果没有列表,就匹配父类中name};static int __init plat_led_drv_init(void){/*注册一个平台驱动*/ printk("------*_^%s--------\n",__FUNCTION__);    return platform_driver_register(&led_drv);}static void __exit plat_led_drv_exit(void){/*注销平台驱动*/platform_driver_unregister(&led_drv);printk("------*_^%s--------\n",__FUNCTION__);}module_init(plat_led_drv_init);module_exit(plat_led_drv_exit);MODULE_LICENSE("GPL");

# MakefileROOTFS_DIR = /opt/filesystemMODULE_NAME = plat_led_devMODULE_NAME2 = plat_led_drvAPP_NAME = led_testCROSS_COMPILE = arm-cortex_a8-linux-gnueabi-CC = $(CROSS_COMPILE)gccifeq ($(KERNELRELEASE), )KERNEL_DIR = /home/linux-3.0.8CUR_DIR = $(shell pwd)all :make -C $(KERNEL_DIR) M=$(CUR_DIR) modules$(CC) $(APP_NAME).c -o $(APP_NAME)clean :make -C $(KERNEL_DIR) M=$(CUR_DIR) cleanrm -rf $(APP_NAME)install:cp -raf *.ko  $(APP_NAME) $(ROOTFS_DIR)/drv_moduleelseobj-m = $(MODULE_NAME).oobj-m += $(MODULE_NAME2).oendif


0 0
原创粉丝点击