驱动:mknod-misc 杂项&自动

一、杂项设备驱动

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/string.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>

#define DEV_NAME "led"
#define GPBCON 0x56000010
#define GPBDAT 0x56000014

static volatile unsigned long * gpbcon;
static volatile unsigned long * gpbdat;

static void init_led(void)						
{
	// 配置GPB5引脚功能为输出
	*gpbcon &= ~(3 << 10);
	*gpbcon |= (1 << 10);

	// 将GPB5引脚电平置高
	*gpbdat |= (1 << 5);
}

static void led_on(void)
{
	// 将GPB5引脚电平置低
	*gpbdat &= ~(1 << 5);
}

static void led_off(void)
{
	// 将GPB5引脚电平置高
	*gpbdat |= (1 << 5);
}

static int open (struct inode *inode, struct file *file)
{
	init_led();
	printk("open..\n");
	return 0;
}

static ssize_t read (struct file * file, char __user * buf, size_t len, loff_t * offset)
{
	printk("read..\n");
	return 0;
}

static ssize_t write (struct file * file, const char __user * buf, size_t len, loff_t *offset)
{
	unsigned char data[12] = {0};
	size_t len_cp = sizeof(data) < len ? sizeof(data) : len;
	copy_from_user(data, buf, len_cp);
	
	if (!strcmp(data,"ledon"))
	{
		led_on();
	}
	else if (!strcmp(data,"ledoff"))
	{
		led_off();
	}
	else
		return -EINVAL;

	printk("write..\n");
	return len_cp;
}

static int close (struct inode * inode, struct file * file)
{
	printk("close..\n");
	return 0;
}

static struct file_operations fops =
{
	.owner = THIS_MODULE,
	.open = open,
	.read = read,
	.write = write,
	.release = close
};

//struct class *class;
//struct device *device;

static struct miscdevice misc_device_node = 
{
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEV_NAME,
	.fops = &fops
};

static int __init led_init(void)
{
	int ret = 0;
//	class = class_create(THIS_MODULE,"led");
	ret = misc_register(&misc_device_node);
	if (ret < 0)
		goto err_misc_register;

	gpbcon = ioremap(GPBCON,sizeof(*gpbcon));//映射一个地址
	gpbdat = ioremap(GPBDAT,sizeof(*gpbdat));

//	device = device_create(class,NULL,dev,NULL,"led");
	printk("led_init ------------------------\n");

	return ret;

err_misc_register:
	misc_deregister(&misc_device_node);
	printk("led misc_register failed\n");
	return ret;
}

static void __exit led_exit(void)
{
//	device_destroy(class,dev);
	iounmap(gpbcon);//解除一个地址
	iounmap(gpbdat);
//	class_destroy(class);
	misc_deregister(&misc_device_node);
	printk("led_exit ----------------------------\n");
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
  1. 新建一个led_misc.c 代码修改内容如上
  2. 修改Makefile
  3. make menuconfig,新选项LED_MISC选中<M>
  4. make modules
  5. cp drivers/char/led_misc.ko /home/linux/nfs/rootfs
  6. 开发板 insmod led_misc.ko 
  7. 开发板 ls /dev -l 查看led设备是否生成
  8. 开发板 ./led_app 运行程序

二、自动创建设备节点

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/string.h>
#include <asm/uaccess.h>
#include <linux/device.h>

#define MAJOR_NUM 253
#define MINOR_NUM 0
#define DEV_NAME "led"
#define DEV_NUM 1
#define GPBCON 0x56000010
#define GPBDAT 0x56000014

static volatile unsigned long * gpbcon;
static volatile unsigned long * gpbdat;

static void init_led(void)						
{
	// 配置GPB5引脚功能为输出
	*gpbcon &= ~(0xff << 10);
	*gpbcon |= (0x55 << 10);

	// 将GPB5引脚电平置高
	*gpbdat |= (0xf << 5);
}

static void led_on(void)
{
	// 将GPB5引脚电平置低
	*gpbdat &= ~(0xf << 5);
}

static void led_off(void)
{
	// 将GPB5引脚电平置高
	*gpbdat |= (0xf << 5);
}

static int open (struct inode * inode, struct file * file)
{
	init_led();
	printk("led open ...\n");
	return 0;
}

static ssize_t read (struct file * file, char __user * buf, size_t len, loff_t * offset)
{
	//copy_to_user(buf, data, len);
	printk("led read ...\n");
	return 0;
}

static ssize_t write (struct file * file, const char __user * buf, size_t len, loff_t * offset)
{
	unsigned char data[12] = {0};
	size_t len_cp = sizeof(data) < len ? sizeof(data) : len;
	copy_from_user(data, buf, len_cp);

	if(!strcmp(data, "ledon"))
		led_on();
	else if(!strcmp(data, "ledoff"))
		led_off();
	else
		 return -1;

	printk("led write ...\n");
	return len_cp;
}

static int close (struct inode * inode, struct file * file)
{
	printk("led close ...\n");
	return 0;
}

static struct file_operations fops = 
{
	.owner = THIS_MODULE,
	.open = open,
	.read = read,
	.write = write,
	.release = close
};
static struct cdev cdev;
static dev_t dev;
struct class * pclass;
struct device * pdev;

static int __init led_init(void) 
{
	int ret = 0;
	dev = MKDEV(MAJOR_NUM, MINOR_NUM);

	cdev_init(&cdev, &fops);

	ret = cdev_add(&cdev, dev, DEV_NUM);
	if(ret < 0)
		goto err_cdev_add;

	ret = register_chrdev_region(dev, DEV_NUM, DEV_NAME);
	if(ret < 0)
		goto err_register_chrdev_region;

	pclass = class_create(THIS_MODULE, "led_class");
	if(pclass == NULL)
		goto err_class_create;

	pdev = device_create(pclass, NULL, dev, NULL, DEV_NAME);
	if(pdev == NULL)
		goto err_device_create;

	gpbcon = ioremap(GPBCON, sizeof(*gpbcon));
	gpbdat = ioremap(GPBDAT, sizeof(*gpbdat));

	printk("led_init  ...\n");

	return ret;

err_cdev_add:
	cdev_del(&cdev);
	printk("led cdev_add failed\n");
	return ret;

err_register_chrdev_region:
	unregister_chrdev_region(dev, DEV_NUM);
	cdev_del(&cdev);
	printk("led register_chrdev_region failed\n");	
	return ret;

err_class_create:
	class_destroy(pclass);
	unregister_chrdev_region(dev, DEV_NUM);
	cdev_del(&cdev);
	printk("led class_create failed\n");	
	return -1;

err_device_create:
	device_destroy(pclass, dev);
	class_destroy(pclass);
	unregister_chrdev_region(dev, DEV_NUM);
	cdev_del(&cdev);
	printk("led device_create failed\n");	
	return -1;
}

static void __exit led_exit(void)
{
	iounmap(gpbcon);
	iounmap(gpbdat);
	device_destroy(pclass, dev);
	class_destroy(pclass);
	unregister_chrdev_region(dev, DEV_NUM);
	cdev_del(&cdev);
	printk("led_exit  ###############################\n");
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

三、GPIO子系统

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值