字符设备应用之私有ioctl的使用

ioctl和netlink是用于用户态程序和内核态模块交互的两种方法,这里主要讲解ioctl的使用方法;
-----再牛逼的梦想,也抵不住傻逼般的坚持! ----20240722 08:26

留一个思考问题,ioctl和netlink的优缺点分别是什么?

使用ioctl,ioctl的入参有个cmd,cmd的格式如下, 共两个字节,分别包含了type, number

/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
/* --------|-type-|-number-|-direction-|-size--|--------------------*/
/* --------|-8bit-|--8bit--|----2bit---|-14bit-|--------------------*/

#define SIOCGCHIPID 0x9160 /*get wifi chip id*/
#define SIOCGCHIPTEMP 0x9161 

cmd[31:30]—数据(args)的传输方向(读写) cmd[29:16]—数据(args)的大小
cmd[15:8]—>命令的类型,可以理解成命令的密钥,一般为ASCII码(0-255的一个字符,有部分字符已经被占用,每个字符的序号段可能部分被占用)
cmd[7:0] —>命令的序号,是一个8bits的数字(序号,0-255之间)

其实cmd本质是一个命令码,不按照上述的规则定义可以嘛?当然可以,只要上下都是你自己做的,发什么cmd做什么事情你自己清楚就好

接下来是干货,直接上Demo (需要自己根据自己的业务,做下微调)
用户态:

#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>

#define DEVICE_PATH "/dev/test_s_cdev"

/*get wifi module chip id or other info*/
int get_dev_info(int cmd, char *buf) 
{
    int fd = -1;
    char info[32] = "";
	
	printf("open [%s]\n", DEVICE_PATH);
	fd = open(DEVICE_PATH, O_RDWR);
    if (fd < 0) 
	{
        perror("Failed to open device--");
        return 1;
    }

    int ret = ioctl(fd, cmd, info);

    if (ret < 0) 
	{
		printf("IOCTL failed\n");
    }
	else
	{
        printf("Got string: %s\n", info);
		memcpy(buf, info, strlen(info));
    }

    close(fd);
    return 0;
}

内核态:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#include "ipc_msg.h"

#define DEVICE_NAME "test_s_cdev"
static char wifi_chip_id[32] = "";

static struct cdev test_s_cdev;
static struct class *test_s_class;
static struct device *test_s_dev;

extern struct ssv_hw *g_ssv_hw;
extern struct ssv_rftool_cfg rftool_cfg;

extern int ssv_send_priv_msg_rf_cmd_wait_resp(struct ssv_rftool_softc *srfc, struct ssv_rf_tool_param *param);

static int device_open(struct inode *inode, struct file *file)
{
    return 0;
}
static int device_write(struct inode *inode, struct file *file)
{
    return 0;
}
static int device_read(struct inode *inode, struct file *file)
{
    return 0;
}
static int device_release(struct inode *inode, struct file *file)
{
    return 0;
}
long test_s_set_chip_id(char *chip_id)
{
	if (copy_to_user(wifi_chip_id, chip_id, strlen(chip_id)))
	{
		printk("[test_s] set chip id fail[%s]\n", chip_id);
		return -EFAULT;
	}
	printk("[test_s]set chip id success[%s]\n", wifi_chip_id);
	return strlen(wifi_chip_id);
}

static void test_s_get_temp()
{
    struct ssv_rf_tool_param rf_tool_param = {0};
    rf_tool_param.rf_cmd = (u32)SSV6XXX_RFPHY_CMD_RF_TOOL_TEMPERATURE;
    rf_tool_param.wait_resp = 1;

    ssv_send_priv_msg_rf_cmd_wait_resp(g_ssv_hw->srfc, &rf_tool_param);
    printk("temperature = %d\n", rftool_cfg.temperature);
}

static long test_s_private_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
   // char *buffer = NULL;
	printk("[test_s]ssv recv ioctl[%04x]\n", cmd);

    if (cmd == SIOCGCHIPID) 
	{
	#if 0
        buffer = kmalloc(strlen(wifi_chip_id) + 1, GFP_KERNEL);
        if (!buffer)
        {
			return -ENOMEM;
		}

        strcpy(buffer, wifi_chip_id);
	#endif
        if (copy_to_user((void __user *)arg, wifi_chip_id, strlen(wifi_chip_id))) 
		{
           // kfree(buffer);
            return -EFAULT;
        }

       // kfree(buffer);
        return 0;
    }
    else if (SIOCGCHIPTEMP == cmd)
    {
        test_s_get_temp();
        if (copy_to_user((void __user *)arg, &rftool_cfg.temperature, sizeof(s8))) 
        {
            return -EFAULT;
        }
        return 0;
    }

    return -EINVAL;
}

static struct file_operations test_s_fops = {
 .owner = THIS_MODULE,
 .open = device_open,
 .read = device_read,
 .write = device_write,
 .release = device_release,
 .unlocked_ioctl = test_s_private_ioctl,
};

int test_s_char_module_init(void)
{
    int ret = -1;
	
	/*设备节点初始化*/
	cdev_init(&test_s_cdev, &test_s_fops);
	
	/*动态申请主设备号*/
    ret = alloc_chrdev_region(&test_s_cdev.dev, 0, 1, DEVICE_NAME);
    if (0 != ret) 
	{
		printk("[test_s]alloc_chrdev_region fail\n");
        return ret;
    }
	
    test_s_cdev.owner = THIS_MODULE;
	ret = cdev_add(&test_s_cdev, test_s_cdev.dev, 1);
    if (0 != ret) 
	{
		printk("[test_s]cdev_add fail\n");
        return ret;
    }

	test_s_class = class_create(THIS_MODULE, DEVICE_NAME);
    if (IS_ERR(test_s_class)) 
	{
		printk("[test_s]class_create fail\n");
        return PTR_ERR(test_s_class);
    }

    test_s_dev = device_create(test_s_class, NULL, test_s_cdev.dev, NULL, DEVICE_NAME);
	if (IS_ERR(test_s_dev)) 
	{
		printk("[test_s]device_create fail\n");
        return PTR_ERR(test_s_dev);
    }
	printk("[test_s]device_create success\n");

    return 0;
}

void test_s_char_module_exit(void)
{
    device_destroy(test_s_class, test_s_cdev.dev);
    class_destroy(test_s_class);
    unregister_chrdev_region(test_s_cdev.dev, 1);
}
  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鸡蛋炒肉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值