1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/platform_device.h> 4 #include <linux/fs.h> 5 #include <linux/device.h> 6 #include <linux/miscdevice.h> 7 8 #include <asm/io.h> 9 #include <asm/uaccess.h> 10 11 12 static void *led_reg_base; 13 static struct miscdevice led_misc; 14 15 //实现设备操作接口 16 int led_plat_drv_open(struct inode *inode, struct file *filp) 17 { 18 19 printk("--------^_^ %s------------ ",__FUNCTION__); 20 // 对寄存器进行初始化 21 unsigned long value = __raw_readl(led_reg_base); 22 value &= ~(0xff<<12); 23 value |= (0x11<<12); //配置成输出功能 24 __raw_writel(value, led_reg_base); 25 26 return 0; 27 } 28 ssize_t led_plat_drv_write(struct file *filp, const char __user *buf, size_t size, loff_t *flags) 29 { 30 int ret; 31 printk("--------^_^ %s------------ ",__FUNCTION__); 32 33 unsigned int value; 34 //应用空间数据转换为内核空间数据 35 ret = copy_from_user(&value, buf, size); 36 if(ret != 0){ 37 printk("copy_from_user error! "); 38 return -EFAULT; 39 } 40 41 42 43 if(value) 44 { 45 // 将led亮起来 46 __raw_writel(__raw_readl(led_reg_base + 4) | (0x3<<3), led_reg_base + 4); 47 }else 48 { 49 __raw_writel(__raw_readl(led_reg_base + 4) &~(0x3<<3), led_reg_base + 4); 50 } 51 52 53 return size; 54 } 55 56 int led_plat_drv_close(struct inode *inode, struct file *filp) 57 { 58 printk("--------^_^ %s------------ ",__FUNCTION__); 59 60 __raw_writel(__raw_readl(led_reg_base + 4) &~(0x3<<3), led_reg_base + 4); 61 62 return 0; 63 } 64 65 66 67 const struct file_operations plat_led_fops = { 68 .open = led_plat_drv_open, 69 .write = led_plat_drv_write, 70 .release = led_plat_drv_close, 71 72 }; 73 74 int led_pdrv_probe(struct platform_device *pdev) 75 { 76 printk("-----------%s----------- ", __FUNCTION__); 77 78 79 //任务1---与应用交互 80 // register_chrdev() , class_create, device_create, fops 81 // 或一种写法---用一个函数搞定上面所有函数 82 led_misc.name = "plat_led"; // /dev/plat_led 83 led_misc.minor = 120; // 主设备号默认为10, 次设备自由定义--MISC_DYNAMIC_MINOR(255)由系统分配 84 led_misc.fops = &plat_led_fops; 85 misc_register(&led_misc); 86 87 88 //任务2---与硬件交互---先要获取资源, ioremap/request_irq() 89 //参数1--从哪个pdev中获取 90 //参数2--资源的类型 91 //参数3--同种资源的第几个 92 struct resource *mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 93 94 //获取地址资源就需要进行地址映射 95 led_reg_base = ioremap(mem_res->start, resource_size(mem_res)); 96 97 98 99 return 0; 100 } 101 int led_pdrv_remove(struct platform_device *pdev) 102 { 103 printk("-----------%s----------- ", __FUNCTION__); 104 105 iounmap(led_reg_base); 106 misc_deregister(&led_misc); 107 108 return 0; 109 } 110 111 112 const struct platform_device_id led_id_table[] = { 113 {"s5pv210_led", 0x123}, //第二个值随便写 114 {"exynos4_led", 0x124}, 115 {"s5p6818_led", 0x444}, 116 }; 117 118 119 struct platform_driver led_pdrv = { 120 .probe = led_pdrv_probe, 121 .remove = led_pdrv_remove, 122 .driver = { //父类一定要初始化 123 .name = "samsung_led_drv", // 一定要初始化--自定义 124 }, 125 .id_table = led_id_table, 126 127 }; 128 129 static int __init plat_led_drv_init(void) 130 { 131 132 //注册一个pdrv 133 return platform_driver_register(&led_pdrv); 134 135 } 136 137 static void __exit plat_led_drv_exit(void) 138 { 139 140 platform_driver_unregister(&led_pdrv); 141 } 142 143 144 module_init(plat_led_drv_init); 145 module_exit(plat_led_drv_exit); 146 MODULE_LICENSE("GPL");
1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/platform_device.h> 4 5 6 #define GPC0_REG_BASE 0xE0200060 7 #define GPC0_SIZE 8 8 9 struct resource led_res[] = { 10 [0] = { 11 .start = GPC0_REG_BASE, 12 .end = GPC0_REG_BASE + GPC0_SIZE - 1, 13 .flags = IORESOURCE_MEM, 14 }, 15 //以下代码为演示如何定义多个资源--led硬件实际没有 16 [1] = { 17 .start = 0x666, 18 .end = 0x666, 19 .name = "fake_irq", 20 .flags = IORESOURCE_IRQ, 21 }, 22 [2] = { 23 .start = 0x12345678, 24 .end = 0x12345678 + 0x8 - 1, 25 .name = "fake_mem", 26 .flags = IORESOURCE_MEM, 27 }, 28 }; 29 30 31 //主要用于解决rmmod的有警告 32 void led_pdev_release(struct device *dev) //pdev从总线移除系统自动调用 33 { 34 35 36 } 37 38 39 struct platform_device led_pdev = { 40 .name = "s5pv210_led", 41 .id = -1, 42 .dev = { 43 .release = led_pdev_release, 44 }, 45 .num_resources = ARRAY_SIZE(led_res), 46 .resource = led_res, 47 }; 48 49 50 static int __init plat_led_dev_init(void) 51 { 52 53 //注册一个pdev 54 return platform_device_register(&led_pdev); 55 56 } 57 58 static void __exit plat_led_dev_exit(void) 59 { 60 61 platform_device_unregister(&led_pdev); 62 } 63 64 65 module_init(plat_led_dev_init); 66 module_exit(plat_led_dev_exit); 67 MODULE_LICENSE("GPL");
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <fcntl.h> 7 8 int main(void) 9 { 10 11 int fd; 12 int on; 13 14 fd = open("/dev/plat_led",O_RDWR); 15 if(fd < 0) 16 { 17 perror("open"); 18 exit(1); 19 } 20 21 22 while(1) 23 { 24 25 on = 1; 26 write(fd,&on,sizeof(on)); 27 sleep(1); 28 29 30 on = 0; 31 write(fd,&on,sizeof(on)); 32 sleep(1); 33 } 34 35 close(fd); 36 return 0; 37 }
1 CROSS_COMPILE = arm-none-linux-gnueabi- 2 CC = $(CROSS_COMPILE)gcc 3 4 #指定内核源码路径 5 KERNEL_DIR = /home/farsight/s5pv210/kernel/driver/linux-3.0.8 6 CUR_DIR = $(shell pwd) 7 8 MYAPP = plat_led_app 9 10 MODULE = plat_led_dev 11 MODULE2 = plat_led_drv 12 13 all: 14 #让make进入内核源码编译,同时将当前目录中的c程序作为内核模块一起编译 15 make -C $(KERNEL_DIR) M=$(CUR_DIR) modules 16 ifneq ($(MYAPP), ) 17 $(CC) -o $(MYAPP) $(MYAPP).c 18 endif 19 20 clean: 21 #删除上面编译生成的文件 22 make -C $(KERNEL_DIR) M=$(CUR_DIR) clean 23 rm -rf $(MYAPP) 24 25 install: 26 cp *.ko $(MYAPP) /opt/rootfs/drv_module 27 28 #指定当前目录下哪个文件作为内核模块编 29 obj-m += $(MODULE).o 30 obj-m += $(MODULE2).o