【Linux Device Driver】—(3.1)—ioctl——代码

本文介绍了通过阅读《Linux Device Driver》一书,学习并实践使用ioctl控制LED灯的亮灭。实验包括编写驱动程序(tiny6410_led_ioctl.c, tiny6410_led_ioctl.h)和测试程序(tiny6410_led_ioctl_app.c),以加深对ioctl的理解。" 108973095,9628446,APP专项测试详解,"['移动开发', 'APP测试', '敏捷开发', '兼容性测试', '性能测试']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

《Linux Device Driver》这本书的却做的很好,对于一个初学者来说虽然有点难度,但是只要认真看,绝对是大有裨益的!

好了,昨天把ioctl的原理以及涉及到的代码贴了一下,今天就做了做实验,感觉还凑合,所以就贴出来!对自己也算是做个笔记吧!

今天这个实验主要就是通过ioctl来控制LED灯的亮灭,虽然有点简单,但是毕竟也是需要花费点时间的。

1、驱动程序

①、tiny6410_led_ioctl.c

 

#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/miscdevice.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>

#include "tiny6410_led_ioctl.h"

MODULE_LICENSE("GPL");

static struct cdev cdev;
static dev_t devno;
struct class *tiny6410_class;
static int major;
volatile unsigned long *gpkcon0 = NULL;
volatile unsigned long *gpkcon1 = NULL;
volatile unsigned long *gpkdat = NULL;



int led_open(struct inode *inode, struct file *filp)
{
	/* LED1 - 4 分别对应GPK4 -7 */
	/* 设置LED 引脚为输出引脚 */
	*gpkcon0 &= (((0x1) << (4*4)) | ((0x1) << (5*4)) | ((0x1) << (6*4)) | ((0x1) << (7*4)));

	/* 对应管脚置高,使LED 全灭 */
	*gpkdat |= 0xf0;
		
	return 0;
}

static ssize_t led_write(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
	/* LED 全部熄灭或者全部打开 */

	int val;

	copy_from_user(&val, buf, size);

	/* 点灯 */
	if(val == 1) {
		*gpkdat &= ~((1<<4) | (1<<5) | (1<<6) | (1<<7));
	}
	/* 灭灯 */
	else {
		*gpkdat |= ((1<<4) | (1<<5) | (1<<6) | (1<<7));
	}
}

static unsigned long led_getdat(void)
{
	return ((*gpkdat >> 4)&0x0f);
}

static void led_setdat(int dat)
{
	*gpkdat = (*gpkdat & ~(0xf<<4)) |((dat&0xf) << 4);
}

int led_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
	int err = 0;
	int ret = 0;
	int ioarg = 0;

	/* 检测命令的有效性 */
	if(_IOC_TYPE(cmd) != LED_IOCTL_MAGIC)
		return -EINVAL;
	if(_IOC_NR(cmd) >= LED_IOCTL_MAXNR)
		return -EINVAL;

	/* 根据命令类型,检测空间是否可以访问,当然有的函数可以省去此步骤。如copy_to_user,下面的就是应用到了,这里为了以后参照,所以也写上了 */
	if(_IOC_DIR(cmd) & _IOC_READ) 
		err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
	else if(_IOC_DIR(cmd) & _IOC_WRITE)
		err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
	if(err)
		return -EFAULT;
	
	/* 根据命令执行相应的操作 */
	switch(cmd) {
		/* 打印当前信息 */
		case LED_IOCTL_IOPRINT:
			printk("<---CMD LED_IOCTL DONE--->\n");
			break;

		/* 获取当前LED 灯的显值 */
		case LED_IOCTL_IOGETDAT:
			ioarg = led_getdat();
			ret = put_user(ioarg, (int *)arg);

			printk("[Call LED_IOCTL_IOGETDAT!]");
			
			break;

		/* 设置当前LED 灯 */
		case LED_IOCTL_IOSETDAT:
			ret = get_user(ioarg, (int *)arg);
			led_setdat(ioarg);
			break;

		default:
			return -EINVAL;
	}

	return ret;
}

static const struct file_operations led_fops =
{
	.open  = led_open,
	.write  = led_write,
	.owner = THIS_MODULE,
	.unlocked_ioctl = led_ioctl,
};

static void tiny6410_led_pin_setup(void)
{
	gpkcon0 = (volatile unsigned long *)ioremap(0x7F008800, 16);
	gpkcon1 = gpkcon0 + 1;
	gpkdat = gpkcon0 + 2;
	
}
static void tiny6410_led_pin_release(void)
{
	iounmap(gpkcon0);
	iounmap(gpkcon1);
	iounmap(gpkdat);
}

static int __init led_init(void)
{
/*	
	alloc_chrdev_region(&devno, 0, 1, "tiny6410_led");
	major = MAJOR(devno);						*/

	major = 255;
	devno = MKDEV(major, 0);
	register_chrdev_region(devno, 1, "tiny6410_led_ioctl");
	
	/* 初始化cdev 结构 */
	cdev_init(&cdev,&led_fops);
	cdev.owner = THIS_MODULE;

	/* 注册字符设备 */
	cdev_add(&cdev, devno,1);

	
	tiny6410_class = class_create(THIS_MODULE, "led_class");

	device_create(tiny6410_class, NULL, MKDEV(major, 0), NULL, "tiny6410_led_ioctl"); 

	tiny6410_led_pin_setup();

	
	return 0;
}

static void __exit led_exit(void)
{
	tiny6410_led_pin_release();
	
	device_destroy(tiny6410_class, MKDEV(major, 0));
	class_destroy(tiny6410_class);

	cdev_del(&cdev);
	unregister_chrdev_region(devno, 1);
}


module_init(led_init);
module_exit(led_exit);

 

②、tiny6410_led_ioctl.h

 

#ifndef _LED_H_
#define _LED_H_

#include <linux/ioctl.h>

/* 定义幻数 */
#define LED_IOCTL_MAGIC 'k'

/* 定义命令 */
#define LED_IOCTL_IOPRINT	_IO(LED_IOCTL_MAGIC, 1)
#define LED_IOCTL_IOGETDAT	_IOR(LED_IOCTL_MAGIC, 2, int)
#define LED_IOCTL_IOSETDAT	_IOW(LED_IOCTL_MAGIC, 3, int)

/* 命令总数 */
#define LED_IOCTL_MAXNR 3

#endif



 2、测试程序

①、tiny6410_led_ioctl_app.c

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "tiny6410_led_ioctl.h"

#define DEVICE_NAME	"/dev/tiny6410_led_ioctl"	
int binstr_to_int(char *binstr)
{
	int ret = 0;
	int i = 0;
	char bnum[5];
	memset(bnum,'0',4);
	int len = strlen(binstr);
	if(len > 4)	
		strcpy(bnum,binstr + len - 4);
	else	
		strcpy(bnum + 4 - len,binstr);
	for(i = 0;i < 4;i ++)	{	
		ret <<= 1;	
		ret += (bnum[i] == '0' ? 1 : 0);
	}	

	return ret;

}

int main(int argc,char **argv)
{	
	if(argc > 2)	{		
		printf("Usage: %s <binary code>\n"	
			"example: %s 1001 -- Will turn on led 0 and 3, and turn off led 1 and 2.\n",argv[0],argv[0]);
		_exit(EXIT_FAILURE);	
	}

	
	int fd,arg;
	if((fd = open(DEVICE_NAME,O_RDWR)) == -1)	{
		printf("Open dev error!\n");	
		_exit(EXIT_FAILURE);
	}

	if(argc == 1)	{	
		ioctl(fd,LED_IOCTL_IOGETDAT,&arg);	
		printf("led dat: %d.\n",arg);	
	}
	else	{	
		arg = binstr_to_int(argv[1]);	
		printf("arg = %d.\n",arg);	
		ioctl(fd,LED_IOCTL_IOSETDAT,&arg);	
	}

	_exit(EXIT_SUCCESS);

}


 


3、测试结果

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值