- #include <Linux/init.h>
- #include <Linux/module.h>
- #include <Linux/platform_device.h>
- #include <Linux/fs.h>
- #include <Linux/device.h>
- #include <Linux/miscdevice.h>
- #include <asm/io.h>
- #include <asm/uaccess.h>
- static void *led_reg_base;
- static struct miscdevice led_misc;
- // 实现设备操作接口
- int led_plat_drv_open(struct inode *inode, struct file *filp)
- {
- printk("--------^_^ %s------------\n",__FUNCTION__);
- // 对寄存器进行初始化
- unsigned long value = __raw_readl(led_reg_base);
- value &= ~(0xff<<12);
- value |= (0x11<<12); // 配置成输出功能
- __raw_writel(value, led_reg_base);
- return 0;
- }
- ssize_t led_plat_drv_write(struct file *filp, const char __user *buf, size_t size, loff_t *flags)
- {
- int ret;
- printk("--------^_^ %s------------\n",__FUNCTION__);
- unsigned int value;
- // 应用空间数据转换为内核空间数据
- ret = copy_from_user(&value, buf, size);
- if(ret != 0){
- printk("copy_from_user error!\n");
- return -EFAULT;
- }
- if(value)
- {
- // 将 led 亮起来
- __raw_writel(__raw_readl(led_reg_base + 4) | (0x3<<3), led_reg_base + 4);
- }else
- {
- __raw_writel(__raw_readl(led_reg_base + 4) &~(0x3<<3), led_reg_base + 4);
- }
- return size;
- }
- int led_plat_drv_close(struct inode *inode, struct file *filp)
- {
- printk("--------^_^ %s------------\n",__FUNCTION__);
- __raw_writel(__raw_readl(led_reg_base + 4) &~(0x3<<3), led_reg_base + 4);
- return 0;
- }
- const struct file_operations plat_led_fops = {
- .open = led_plat_drv_open,
- .write = led_plat_drv_write,
- .release = led_plat_drv_close,
- };
- int led_pdrv_probe(struct platform_device *pdev)
- {
- printk("-----------%s-----------\n", __FUNCTION__);
- // 任务 1--- 与应用交互
- // register_chrdev() , class_create, device_create, fops
- // 或一种写法 --- 用一个函数搞定上面所有函数
- led_misc.name = "plat_led"; // /dev/plat_led
- led_misc.minor = 120; // 主设备号默认为 10, 次设备自由定义 --MISC_DYNAMIC_MINOR(255) 由系统分配
- led_misc.fops = &plat_led_fops;
- misc_register(&led_misc);
- // 任务 2--- 与硬件交互 --- 先要获取资源, ioremap/request_irq()
- // 参数 1-- 从哪个 pdev 中获取
- // 参数 2-- 资源的类型
- // 参数 3-- 同种资源的第几个
- struct resource *mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- // 获取地址资源就需要进行地址映射
- led_reg_base = ioremap(mem_res->start, resource_size(mem_res));
- return 0;
- }
- int led_pdrv_remove(struct platform_device *pdev)
- {
- printk("-----------%s-----------\n", __FUNCTION__);
- iounmap(led_reg_base);
- misc_deregister(&led_misc);
- return 0;
- }
- const struct platform_device_id led_id_table[] = {
- {"s5pv210_led", 0x123}, // 第二个值随便写
- {"exynos4_led", 0x124},
- {"s5p6818_led", 0x444},
- };
- struct platform_driver led_pdrv = {
- .probe = led_pdrv_probe,
- .remove = led_pdrv_remove,
- .driver = { // 父类一定要初始化
- .name = "samsung_led_drv", // 一定要初始化 -- 自定义
- },
- .id_table = led_id_table,
- };
- static int __init plat_led_drv_init(void)
- {
- // 注册一个 pdrv
- return platform_driver_register(&led_pdrv);
- }
- static void __exit plat_led_drv_exit(void)
- {
- platform_driver_unregister(&led_pdrv);
- }
- module_init(plat_led_drv_init);
- module_exit(plat_led_drv_exit);
- MODULE_LICENSE("GPL");
- #include <Linux/init.h>
- #include <Linux/module.h>
- #include <Linux/platform_device.h>
- #define GPC0_REG_BASE 0xE0200060
- #define GPC0_SIZE 8
- struct resource led_res[] = {
- [0] = {
- .start = GPC0_REG_BASE,
- .end = GPC0_REG_BASE + GPC0_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- // 以下代码为演示如何定义多个资源 --led 硬件实际没有
- [1] = {
- .start = 0x666,
- .end = 0x666,
- .name = "fake_irq",
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = 0x12345678,
- .end = 0x12345678 + 0x8 - 1,
- .name = "fake_mem",
- .flags = IORESOURCE_MEM,
- },
- };
- // 主要用于解决 rmmod 的有警告
- void led_pdev_release(struct device *dev) //pdev 从总线移除系统自动调用
- {
- }
- struct platform_device led_pdev = {
- .name = "s5pv210_led",
- .id = -1,
- .dev = {
- .release = led_pdev_release,
- },
- .num_resources = ARRAY_SIZE(led_res),
- .resource = led_res,
- };
- static int __init plat_led_dev_init(void)
- {
- // 注册一个 pdev
- return platform_device_register(&led_pdev);
- }
- static void __exit plat_led_dev_exit(void)
- {
- platform_device_unregister(&led_pdev);
- }
- module_init(plat_led_dev_init);
- module_exit(plat_led_dev_exit);
- MODULE_LICENSE("GPL");
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- int main(void)
- {
- int fd;
- int on;
- fd = open("/dev/plat_led",O_RDWR);
- if(fd < 0)
- {
- perror("open");
- exit(1);
- }
- while(1)
- {
- on = 1;
- write(fd,&on,sizeof(on));
- sleep(1);
- on = 0;
- write(fd,&on,sizeof(on));
- sleep(1);
- }
- close(fd);
- return 0;
- }
- CROSS_COMPILE = ARM-none-Linux-gnueabi-
- CC = $(CROSS_COMPILE)gcc
- #指定内核源码路径
- KERNEL_DIR = /home/farsight/s5pv210/kernel/driver/Linux-3.0.8
- CUR_DIR = $(shell pwd)
- MYAPP = plat_led_app
- MODULE = plat_led_dev
- MODULE2 = plat_led_drv
- all:
- #让 make 进入内核源码编译, 同时将当前目录中的 c 程序作为内核模块一起编译
- make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
- ifneq ($(MYAPP), )
- $(CC) -o $(MYAPP) $(MYAPP).c
- endif
- clean:
- #删除上面编译生成的文件
- make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
- rm -rf $(MYAPP)
- install:
- cp *.ko $(MYAPP) /opt/rootfs/drv_module
- #指定当前目录下哪个文件作为内核模块编
- obj-m += $(MODULE).o
- obj-m += $(MODULE2).o
来源: http://www.bubuko.com/infodetail-3087223.html