博客:
这篇和做对照
led.h
#ifndef _HEAD_H#define _HEAD_H#define MAGIC 'h'#define LED_ON _IOW(MAGIC,1,int)#define LED_OFF _IOW(MAGIC,0,int)struct led_device{ dev_t devno; unsigned int led_major; struct cdev *led_cdev; struct class *led_class; struct device *led_device;};#endif
平台设备
dev_led.c
#include平台驱动#include #include #include "led.h"static void led_release(struct device *dev){ }static struct platform_device s5pv210_led_device_lhy = { .name = "s5pv210_led_lhy", .id = 1, .dev = { .release = led_release, //开发模式下,这个真不能少! },};static int __init dev_led_init(void){ platform_device_register(&s5pv210_led_device_lhy); return 0;}static void __exit dev_led_exit(void){ platform_device_unregister(&s5pv210_led_device_lhy);}module_init(dev_led_init);module_exit(dev_led_exit);MODULE_LICENSE("GPL");
led_drv.c
#include#include #include //register_chrled#include //class_create/ledice_create#include //kmalloc#include //copy_to_user/copy_from_user#include //ioremap#include //gpio_request#include //s3c_gpio_cfgpin#include //cdev_alloc#include #include"led.h"static struct led_device *led_drv;static int led_open(struct inode *inode, struct file *file){ printk(KERN_INFO"%s()-%d\n", __func__, __LINE__); s3c_gpio_cfgpin(S5PV210_GPC0(3),S3C_GPIO_OUTPUT); s3c_gpio_cfgpin(S5PV210_GPC0(4),S3C_GPIO_OUTPUT); return 0;}static ssize_t led_read(struct file *file, char __user *buf, size_t count, loff_t *offset){ printk(KERN_INFO"%s()-%d\n", __func__, __LINE__); return count;}ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *offset){ printk(KERN_INFO"%s()-%d\n", __func__, __LINE__); return 0;}static long led_ioctl(struct file *file, unsigned int cmd, unsigned long val){ printk(KERN_INFO"%s()-%d\n", __func__, __LINE__); printk(KERN_INFO"cmd=%d arg=%ld\n", cmd, val); switch(cmd) { case LED_ON: gpio_set_value(S5PV210_GPC0(val),1); break; case LED_OFF: gpio_set_value(S5PV210_GPC0(val),0); break; default: break; } return 0;}//硬件操作方法static struct file_operations led_fops={ .owner = THIS_MODULE, .open = led_open, .write = led_write, .read = led_read, .unlocked_ioctl = led_ioctl,};static int s5pv210_led_probe(struct platform_device *pdrv){ int ret; led_drv = kmalloc(sizeof(struct led_device),GFP_KERNEL); if(led_drv==NULL){ printk(KERN_ERR"no memory malloc for fs210_led\n"); return -ENOMEM; } /*1. 动态注冊/申请主设备*/ ret=alloc_chrdev_region(&led_drv->devno,0,1,"dev_module"); if (ret < 0) { printk(KERN_ERR "unable to get major\n"); return -EFAULT; goto out_err_1; } //从设备号中分离出主设备号 led_drv->led_major = MAJOR(led_drv->devno); /*为cdev分配空间*/ led_drv->led_cdev = cdev_alloc(); /*注冊硬件操作方法/初始化cdev*/ cdev_init(led_drv->led_cdev,&led_fops); /*注冊字符设备*/ cdev_add(led_drv->led_cdev,led_drv->devno,1); /*2. 创建设备类*/ led_drv->led_class=class_create(THIS_MODULE,"led_class"); if (IS_ERR(led_drv->led_class)) { printk(KERN_ERR "class_create() failed for led_class\n"); ret = -ENODATA; goto out_err_2; } /*3. 创建设备文件*/ led_drv->led_device=device_create(led_drv->led_class,NULL,MKDEV(led_drv->led_major,0),NULL,"led"); // /led/xxx if (IS_ERR(led_drv->led_device)) { printk(KERN_ERR "device_create failed for led_device\n"); ret = -ENODEV; goto out_err_3; } /*申请GPC0_3,4引脚资源*/ gpio_request(S5PV210_GPC0(3),"LED1"); gpio_request(S5PV210_GPC0(4),"LED2"); return 0;out_err_3: class_destroy(led_drv->led_class);out_err_2: unregister_chrdev(led_drv->led_major,"led_module");out_err_1: kfree(led_drv); return ret;}static int s5pv210_led_remove(struct platform_device *pdrv){ unregister_chrdev(led_drv->led_major,"led_module"); device_destroy(led_drv->led_class,MKDEV(led_drv->led_major,0)); class_destroy(led_drv->led_class); gpio_free(S5PV210_GPC0(3)); gpio_free(S5PV210_GPC0(4)); kfree(led_drv); return 0;}struct platform_device_id led_ids[]={ [0]={ .name = "s5pv210_led_lhy", .driver_data = 0, },};static struct platform_driver s5pv210_led_driver = { .probe = s5pv210_led_probe, .remove = s5pv210_led_remove, .driver = { .name = "s5pv210_led_lhy", .owner = THIS_MODULE, }, .id_table = led_ids,}; static int __init led_init(void){ platform_driver_register(&s5pv210_led_driver); return 0;}static void __exit led_exit(void){ platform_driver_unregister(&s5pv210_led_driver);}module_init(led_init);module_exit(led_exit);MODULE_LICENSE("GPL");
測试程序:
#includeMakefile#include #include #include #include #include #include #include #include "led.h"/*** ./led_test on num 点亮LED1/2** ./led_test off num 熄灭LED1/2*/int main(int argc, char *argv[]){ if (argc != 3) printf("input:< %s on led_num >or< %s off led_num>\n",argv[0],argv[0]); int fd; unsigned int cmd=0; unsigned long val=0; fd=open("/dev/led", O_RDWR); if(fd<0){ perror("open failed!\n"); exit(1); } if(strcmp(argv[1],"on")==0){ cmd=LED_ON; }else if(strcmp(argv[1],"off")==0){ cmd=LED_OFF; }else{ printf("err input!\n"); } val = atoi(argv[2]); if(ioctl(fd,cmd,val)<0){ perror("ioctl failed!\n"); exit(1); } close(fd); return 0;}
ifeq ($(KERNELRELEASE),) KERNELDIR =/home/farsight/work/kernel/linux-3.0.8 PWD =$(shell pwd)modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules arm-none-linux-gnueabi-gcc led_test.c -o led_test cp led_drv.ko dev_led.ko led_test /opt/filesystem/s5pv210modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_installclean: rm -rf *.so *.o *.ko *test .tmp_versions *.mod.c *.order *.symvers else obj-m :=led_drv.o dev_led.oendif