驱动开发 作业4

作业1

在内核模块中启用定时器,定时 1s,让 led1 一秒亮,一秒灭

  • 全部代码
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

struct device_node *dnode;
struct gpio_desc *gpiono;

struct timer_list mytimer; //定义定时器对象

//定义定时器处理函数
void mytimer_func(struct timer_list *timer)
{
	static int status = 0;
	status = !status;
	gpiod_set_value(gpiono, status);
	//再次启用定时器
	mod_timer(timer, jiffies + HZ);
}

static int __init mycdev_init(void)
{
	//解析 led 灯的设备树节点
	dnode = of_find_node_by_path("/myleds");
	if (dnode == NULL) {
		printk("解析设备树节点失败\n");
		return -ENXIO;
	}
	printk("解析设备树节点成功\n");
	//根据设备树节点获取 led 灯的 gpio 编号并向内核注册
	gpiono = gpiod_get_from_of_node(dnode, "led1", 0, GPIOD_OUT_LOW, NULL);
	if (IS_ERR(gpiono)) {
		printk("申请gpio失败\n");
		return -PTR_ERR(gpiono);
	}
	//初始化定时器对象
	mytimer.expires = jiffies + HZ;
	timer_setup(&mytimer, mytimer_func, 0);
	//将定时器对象注册进内核
	add_timer(&mytimer);

	return 0;
}

static void __exit mycdev_exit(void)
{
	del_timer(&mytimer);
}

module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

作业2

基于 gpio 子系统完成 LED 灯驱动的注册,应用程序测试

  • 全部代码
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "head.h"

struct device_node *dnode;
struct gpio_desc *led[3];
int major;
struct class *cls;
struct device *dev;

void toggle_led(int i)
{
	static int value[3] = { 0, 0, 0 };
	value[i] = !value[i];
	gpiod_set_value(led[i], value[i]);
}

static int mycdev_open(struct inode *inode, struct file *filp)
{
	return 0;
}

static int mycdev_release(struct inode *inode, struct file *filp)
{
	return 0;
}

long mycdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	switch (cmd) {
	case LED_TOGGLE:
		toggle_led(arg);
		break;
	}
	return 0;
}

struct file_operations fops = {
	.open = mycdev_open,
	.unlocked_ioctl = mycdev_ioctl,
	.release = mycdev_release,
};

static int __init mycdev_init(void)
{
	int i;
	char str[5];
	// 字符设备驱动注册
	major = register_chrdev(0, "mychrdev", &fops);
	if (major < 0) {
		printk("字符设备驱动注册失败\n");
		return major;
	}
	printk("字符设备驱动注册成功:major=%d\n", major);
	// 向上提交目录
	cls = class_create(THIS_MODULE, "mychrdev");
	if (IS_ERR(cls)) {
		printk("向上提交目录失败\n");
		return -PTR_ERR(cls);
	}
	// 向上提交设备节点信息
	// 为三盏灯创建三个设备文件
	for (i = 0; i < 3; i++) {
		dev = device_create(cls, NULL, MKDEV(major, i), NULL,
				    "mychrdev%d", i);
		if (IS_ERR(dev)) {
			printk("向上提交设备节点信息失败\n");
			return -PTR_ERR(dev);
		}
	}
	//解析led灯的设备树节点
	dnode = of_find_node_by_path("/myleds");
	if (dnode == NULL) {
		printk("解析设备树节点失败\n");
		return -ENXIO;
	}
	printk("解析设备树节点成功\n");
	//根据设备树节点解析 led123 gpio结构体并向内核注册
	for (i = 0; i < 3; i++) {
		sprintf(str, "led%d", i + 1);
		led[i] = gpiod_get_from_of_node(dnode, str, 0, GPIOD_OUT_LOW,
						NULL);
		if (IS_ERR(led[i])) {
			printk("申请gpio失败\n");
			return -PTR_ERR(led[i]);
		}
	}
	return 0;
}

static void __exit mycdev_exit(void)
{
	int i;
	//灭灯
	for (i = 0; i < 3; i++)
		gpiod_set_value(led[i], 0);
	//注销gpio信息
	for (i = 0; i < 3; i++)
		gpiod_put(led[i]);
	for (i = 0; i < 3; i++)
		device_destroy(cls, MKDEV(major, i));
	class_destroy(cls);
	unregister_chrdev(major, "mychrdev");
}

module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

用户空间测试文件:

#include 
#include 
#include 
#include 
#include 
#include "head.h"

int main(int argc, char const *argv[])
{
	int a, fd[3];
	char str[15];
	for (a = 0; a < 3; a++) {
		sprintf(str, "/dev/mychrdev%d", a);
		fd[a] = open("/dev/mychrdev0", O_RDWR);
		if (fd[a] < 0) {
			printf("打开设备文件失败\n");
			exit(-1);
		}
	}
	while (1) {
		printf("请选择要开关的灯\n");
		printf("0(LED1) 1(LED2) 2(LED3)>");

		scanf("%d", &a);
		ioctl(fd[a], LED_TOGGLE, a);
	}
	for (a = 0; a < 3; a++)
		close(fd[a]);

	return 0;
}

你可能感兴趣的:(华清远见,驱动开发)