• 喜羊羊系列之【设备-驱动 动态载入进内核】


    博客:http://blog.csdn.net/muyang_ren

    这篇和设备驱动编入内核做对照

    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 <linux/init.h>
    #include <linux/module.h>
    #include <linux/platform_device.h>
    #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<linux/init.h>
    #include<linux/module.h>
    #include<linux/fs.h>		//register_chrled
    #include<linux/device.h>	//class_create/ledice_create
    #include<linux/slab.h>		//kmalloc
    #include<asm/uaccess.h>		//copy_to_user/copy_from_user
    #include<asm/io.h>			//ioremap
    #include<linux/gpio.h>		//gpio_request
    #include <plat/gpio-cfg.h>	//s3c_gpio_cfgpin
    #include <linux/cdev.h>     //cdev_alloc
    
    #include <linux/platform_device.h>
    
    
    #include"led.h"
    
    static struct led_device *led_drv;
    
    static int led_open(struct inode *inode, struct file *file)
    {	
    	printk(KERN_INFO"%s()-%d
    ", __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
    ", __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
    ", __func__, __LINE__);
    	return 0;
    }
    
    static long led_ioctl(struct file *file, unsigned int cmd, unsigned long val)
    {
    	printk(KERN_INFO"%s()-%d
    ", __func__, __LINE__);
    	printk(KERN_INFO"cmd=%d arg=%ld
    ", 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
    ");
    		return -ENOMEM;
    	}
    
    	/*1. 动态注冊/申请主设备*/
    	ret=alloc_chrdev_region(&led_drv->devno,0,1,"dev_module");
    	if (ret < 0) {
    		printk(KERN_ERR "unable to get major
    ");
    		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
    ");
    		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
    ");
    		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");
    

    測试程序:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <sys/ioctl.h>
    #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>
    ",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!
    ");
    		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!
    ");
    	}
    
    	val = atoi(argv[2]);
    
    	if(ioctl(fd,cmd,val)<0){
    		perror("ioctl failed!
    ");
    		exit(1);
    	}
    
    	close(fd);
    	return 0;
    }

    Makefile

    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/s5pv210
    modules_install:
    	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
    clean:
    	rm -rf *.so *.o *.ko *test  .tmp_versions *.mod.c *.order *.symvers 
    else
    	obj-m :=led_drv.o dev_led.o
    endif




  • 相关阅读:
    面向对象(接口 ,多态)
    面向对象(继承,重写,this,super,抽象类)
    IO(字符流 字符缓冲流)
    ArrayList集合
    字符串常用API
    面向对象(类,封装,this,构造方法)
    不同类型问题代码训练
    java中的方法
    04慕课网《进击Node.js基础(一)》HTTP讲解
    《JavaScript设计模式与开发实践》——第3章 闭包和高阶函数
  • 原文地址:https://www.cnblogs.com/llguanli/p/8436663.html
Copyright © 2020-2023  润新知