【迅为iTop4412学习笔记】22.编写一个LED驱动(未完成)

声明

以下都是我刚开始看驱动视频的个人强行解读,如果有误请指出,共同进步。

本节目标

https://blog.csdn.net/ZZRsr/article/details/80599489
https://blog.csdn.net/fxjqzs/article/details/47356039
https://www.cnblogs.com/xiansheng/p/5531462.html

仅上代码,此处以后再写。

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("MrYang");

#define DEV_MAJOR		0				/* 默认主设备号(为0则linux自动分配可用号码) */
#define DEV_MINOR		0				/* 默认次设备号(为0则linux自动分配可用号码) */
#define DEV_MINOR_NUM	2				/* 要注册的次设备的数量 */
#define DEV_NAME		"mryang_ascdev"	/* 设备名 */

// 初始化主次设备号
int device_major = DEV_MAJOR;
int device_minor = DEV_MINOR;

static int led_gpios[] = {
	EXYNOS4_GPL2(0),EXYNOS4_GPK1(1),
};

/*打开操作*/
static int chardevnode_open(struct inode *inode, struct file *file){
	printk(KERN_EMERG "chardevnode_open is success!\n");
	
	return 0;
}
/*关闭操作*/
static int chardevnode_release(struct inode *inode, struct file *file){
	printk(KERN_EMERG "chardevnode_release is success!\n");
	
	return 0;
}
/*IO操作*/
static long chardevnode_ioctl(struct file *file, unsigned int cmd, unsigned long arg){
	printk(KERN_EMERG "chardevnode_ioctl is success! cmd is %u,arg is %lu!\n",cmd,arg);
	
	switch(cmd)
	{
		case 0:
		case 1:
			gpio_set_value(led_gpios[arg], cmd);
			break;
		default:
			break;
	}
	
	return 0;
}

ssize_t chardevnode_read(struct file *file, char __user *buf, size_t count, loff_t *f_ops){
	return 0;
}

ssize_t chardevnode_write(struct file *file, const char __user *buf, size_t count, loff_t *f_ops){
	return 0;
}

loff_t chardevnode_llseek(struct file *file, loff_t offset, int ence){
	return 0;
}

// cdev结构体
struct cdev *my_cdev_ptr;

// 文件操作结构体
struct file_operations my_fops = {
	.owner = THIS_MODULE,
	
	.open = chardevnode_open,
	.release = chardevnode_release,
	.unlocked_ioctl = chardevnode_ioctl,
	.read = chardevnode_read,
	.write = chardevnode_write,
	.llseek = chardevnode_llseek,
};

struct class *myclass;

static int led_init(void)
{
	int i = 0;
	int flag = -1;
	
	printk(KERN_EMERG "led init!\n");
	
	
	for(i=0;i<2;i++)
	{
		gpio_free(led_gpios[i]);
		// 申请GPIO
		flag = gpio_request(led_gpios[i],"LEDS");
		if(flag < 0){
			printk(KERN_EMERG "gpio_request LED%d failed!\n", i);
			return flag;
		}
		printk(KERN_EMERG "gpio_request LED%d success!\n", i);

		// 配置GPIO为输出
		s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);
		// 设置默认输出为0
		gpio_set_value(led_gpios[i],0);
	}
	
	return 0;
}


static int mryang_init(void)
{
	int ret, i;
	dev_t mryang_dev;
	
	printk(KERN_EMERG "HELLO MrYang\n");
	
	// 动态申请设备号
	ret = alloc_chrdev_region(&mryang_dev, device_minor, DEV_MINOR_NUM, DEV_NAME);
	if(ret < 0)
		printk(KERN_EMERG "failed!\n");
	else
		printk(KERN_EMERG "success!\n");
	
	// 提取主、次设备号
	device_major = MAJOR(mryang_dev);
	device_minor = MINOR(mryang_dev);
	printk(KERN_EMERG "major: %d, minor: %d\n", device_major, device_minor);
	
	// 注册设备类
	myclass = class_create(THIS_MODULE, DEV_NAME);
	
	
	// 静态申请内存大小(设备数*结构体就是大小)
	my_cdev_ptr = kmalloc( DEV_MINOR_NUM * sizeof(struct cdev), GFP_KERNEL);
	if(my_cdev_ptr==NULL)
	{
		printk(KERN_EMERG "kmalloc failed!\n");
		return -1;
	}
	
	memset(my_cdev_ptr, 0, DEV_MINOR_NUM * sizeof( struct cdev ) );		// 可省略,init会自动memset,看源码
	
	for(i=0;i<DEV_MINOR_NUM;i++)
	{
		// 初始化cdev,并绑定文件操作函数
		cdev_init(&my_cdev_ptr[i], &my_fops);
		// 赋值
		my_cdev_ptr[i].owner = THIS_MODULE;
		my_cdev_ptr[i].ops = &my_fops;
		// 注册到系统
		ret = cdev_add(&my_cdev_ptr[i], MKDEV(device_major, device_minor+i), 1);
		if( ret < 0 )
			printk(KERN_EMERG "cdev_add %d failed!\n", i);
		else
			printk(KERN_EMERG "cdev_add %d success!\n", i);
		/* 创建设备节点 */
		device_create(myclass,NULL, MKDEV(device_major, device_minor+i), NULL, DEV_NAME"%d",i);
	}
	
	led_init();
	
	return 0;
}

static void mryang_exit(void)
{
	int i;
	dev_t mryang_dev;
	// 设备号
	mryang_dev = MKDEV(device_major, device_minor);

	for(i=0;i<DEV_MINOR_NUM;i++)
	{	// 注销字符设备
		cdev_del(&my_cdev_ptr[i]);
		device_destroy(myclass,MKDEV(device_major, device_minor+i));
	}
	// 注销内存
	kfree(my_cdev_ptr);
	// 注销设备号
	unregister_chrdev_region(mryang_dev, DEV_MINOR_NUM);
	
	printk(KERN_EMERG "Bye MrYang\n");
}

module_init(mryang_init);
module_exit(mryang_exit);
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char* argv[])
{
	int fd;
	char *mryang_node0 = "/dev/mryang_ascdev0";
	char *mryang_node1 = "/dev/mryang_ascdev1";
	
	int cmd = atoi(argv[1]);
	int arg = atoi(argv[2]);
	
	switch( arg )
	{
		case 0:
			// 次设备 0
			fd = open(mryang_node0, O_RDWR|O_NDELAY);
			if(fd < 0)
			{
				printf("open %s failed!\n", mryang_node0);
			}
			else
			{
				printf("open %s success! fd=%d\n", mryang_node0, fd);
				ioctl(fd, cmd, arg);
			}
			close(fd);	
			break;
		case 1:
			// 次设备 1
			fd = open(mryang_node1, O_RDWR|O_NDELAY);
			if(fd < 0)
			{
				printf("open %s failed!\n", mryang_node1);
			}
			else
			{
				printf("open %s success! fd=%d\n", mryang_node1, fd);
				ioctl(fd, cmd, arg);
			}
			close(fd);
			break;
		default:
			break;
	}
	
	return 0;
}

你可能感兴趣的:(iTop4412,Linux驱动篇)