ioctl和netlink是用于用户态程序和内核态模块交互的两种方法,这里主要讲解ioctl的使用方法;
-----再牛逼的梦想,也抵不住傻逼般的坚持! ----20240722 08:26
留一个思考问题,ioctl和netlink的优缺点分别是什么?
使用ioctl,ioctl的入参有个cmd,cmd的格式如下, 共两个字节,分别包含了type, number
c
/* -------------------- 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 (需要自己根据自己的业务,做下微调)
用户态:
c
#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;
}
内核态:
c
#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);
}