【Linux 驱动篇(二)】LED 驱动开发

2023-11-09

一、Linux 下 LED 灯驱动原理

Linux 下的任何外设驱动,最终都是要配置相应的硬件寄存器。所以本章的 LED 灯驱动最终也是对 I.MX6ULL 的 IO 口进行配置,与裸机实验不同的是,在 Linux 下编写驱动要符合 Linux 的驱动框架。I.MX6U-ALPHA 开发板上的 LED 连接到 I.MX6ULL 的 GPIO1_IO03 这个引脚上,因此本章实验的重点就是编写 Linux 下 I.MX6UL 引脚控制驱动。


1. 地址映射

在编写驱动之前,我们需要先简单了解一下 MMU 这个神器, MMU 全称叫做 Memory Manage Unit,也就是内存管理单元。在老版本的 Linux 中要求处理器必须有 MMU,但是现在 Linux 内核已经支持无 MMU 的处理器了。 MMU 主要完成的功能如下:

  1. 完成虚拟空间到物理空间的映射。
  2. 内存保护,设置存储器的访问权限,设置虚拟存储空间的缓冲特性。

  重点来看一下第①点,也就是虚拟空间到物理空间的映射,也叫做地址映射。首先了解两个地址概念:虚拟地址(VA,Virtual Address)、物理地址(PA, Physcical Address)。对于 32 位的处理器来说,虚拟地址范围是 2^32=4GB,我们的开发板上有 512MB 的 DDR3,这 512MB 的内存就是物理内存,经过 MMU 可以将其映射到整个 4GB 的虚拟空间,如图所示:
在这里插入图片描述
  物理内存只有 512MB,虚拟内存有 4GB,那么肯定存在多个虚拟地址映射到同一个物理地址上去,虚拟地址范围比物理地址范围大的问题处理器自会处理,这里我们不要去深究,因为 MMU 是很复杂的一个东西。
  Linux 内核启动的时候会初始化 MMU,设置好内存映射,设置好以后 CPU 访问的都是虚拟 地 址 。 比 如 I.MX6ULL 的 GPIO1_IO03 引 脚 的 复 用 寄 存 器 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 的地址为 0X020E0068。如果没有开启 MMU 的话直接向 0X020E0068 这个寄存器地址写入数据就可以配置 GPIO1_IO03 的复用功能。现在开启了 MMU,并且设置了内存映射,因此就不能直接向 0X020E0068 这个地址写入数据了。我们必须得到 0X020E0068 这个物理地址在 Linux 系统里面对应的虚拟地址,这里就涉及到了物理内存和虚拟内存之间的转换,需要用到两个函数: ioremap 和 iounmap。


1.1 ioremap 函数

ioremap 函 数 用 于 获 取 指 定 物 理 地 址 空 间 对 应 的 虚 拟 地 址 空 间 , 定 义 在 arch/arm/include/asm/io.h 文件中,定义如下:

1 #define ioremap(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
2 
3 void __iomem * __arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype)
4 {
5 	return arch_ioremap_caller(phys_addr, size, mtype, __builtin_return_address(0));
6 }

ioremap 是个宏,有两个参数: cookie 和 size,真正起作用的是函数__arm_ioremap,此函数有三个参数和一个返回值,这些参数和返回值的含义如下:
  phys_addr:要映射的物理起始地址。
  size:要映射的内存空间大小。
  mtype: ioremap 的类型,可以选择 MT_DEVICE、 MT_DEVICE_NONSHARED、MT_DEVICE_CACHED 和 MT_DEVICE_WC, ioremap 函数选择 MT_DEVICE。
  返回值: __iomem 类型的指针,指向映射后的虚拟空间首地址。


假如我们要获取 I.MX6ULL 的 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 寄存器对应的虚拟地址,使用如下代码即可:

#define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
static void __iomem* SW_MUX_GPIO1_IO03;
SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);

  宏 SW_MUX_GPIO1_IO03_BASE 是寄存器物理地址, SW_MUX_GPIO1_IO03 是映射后的虚拟地址。对于 I.MX6ULL 来说一个寄存器是 4 字节(32 位)的,因此映射的内存长度为 4。映射完成以后直接对 SW_MUX_GPIO1_IO03 进行读写操作即可。


1.2 iounmap 函数

卸载驱动的时候需要使用 iounmap 函数释放掉 ioremap 函数所做的映射, iounmap 函数原型如下:

void iounmap (volatile void __iomem *addr)

iounmap 只有一个参数 addr,此参数就是要取消映射的虚拟地址空间首地址。假如我们现在要取消掉 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 寄存器的地址映射,使用如下代码即可:

iounmap(SW_MUX_GPIO1_IO03);

2. I/O 内存访问函数

这里说的 I/O 是输入/输出的意思,并不是我们学习单片机的时候讲的 GPIO 引脚。这里涉及到两个概念: I/O 端口和 I/O 内存。当外部寄存器或内存映射到 IO 空间时,称为 I/O 端口。当外部寄存器或内存映射到内存空间时,称为 I/O 内存。但是对于 ARM 来说没有 I/O 空间这个概念,因此 ARM 体系下只有 I/O 内存(可以直接理解为内存)。使用 ioremap 函数将寄存器的物理地址映射到虚拟地址以后,我们就可以直接通过指针访问这些地址,但是 Linux 内核不建议这么做,而是推荐使用一组操作函数来对映射后的内存进行读写操作。


2.1 读操作函数

readb、 readw 和 readl 这三个函数分别对应 8bit、 16bit 和 32bit 读操作,参数 addr 就是要读取写内存地址,返回值就是读取到的数据。

u8 readb(const volatile void __iomem *addr)
u16 readw(const volatile void __iomem *addr)
u32 readl(const volatile void __iomem *addr)

2.2 写操作函数

writeb、 writew 和 writel 这三个函数分别对应 8bit、 16bit 和 32bit 写操作,参数 value 是要写入的数值, addr 是要写入的地址。

void writeb(u8 value, volatile void __iomem *addr)
void writew(u16 value, volatile void __iomem *addr)
void writel(u32 value, volatile void __iomem *addr)

二、实验程序编写

1. LED 灯驱动程序编写

新建名为“2_led”文件夹,然后在 2_led 文件夹里面创建 VSCode 工程,工作区命名为“led”。工程创建好以后新建 led.c 文件,此文件就是 led 的驱动文件,在 led.c 里面输入如下内容:

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名		: led.c
作者	  	: 左忠凯
版本	   	: V1.0
描述	   	: LED驱动文件。
其他	   	: 无
论坛 	   	: www.openedv.com
日志	   	: 初版V1.0 2019/1/30 左忠凯创建
***************************************************************/
#define LED_MAJOR		200		/* 主设备号 */
#define LED_NAME		"led" 	/* 设备名字 */

#define LEDOFF 	0				/* 关灯 */
#define LEDON 	1				/* 开灯 */
 
/* 寄存器物理地址 */
#define CCM_CCGR1_BASE				(0X020C406C)	
#define SW_MUX_GPIO1_IO03_BASE		(0X020E0068)
#define SW_PAD_GPIO1_IO03_BASE		(0X020E02F4)
#define GPIO1_DR_BASE				(0X0209C000)
#define GPIO1_GDIR_BASE				(0X0209C004)

/* 映射后的寄存器虚拟地址指针 */
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;

/*
 * @description		: LED打开/关闭
 * @param - sta 	: LEDON(0) 打开LED,LEDOFF(1) 关闭LED
 * @return 			: 无
 */
void led_switch(u8 sta)
{
	u32 val = 0;
	if(sta == LEDON) {
		val = readl(GPIO1_DR);
		val &= ~(1 << 3);	
		writel(val, GPIO1_DR);
	}else if(sta == LEDOFF) {
		val = readl(GPIO1_DR);
		val|= (1 << 3);	
		writel(val, GPIO1_DR);
	}	
}

/*
 * @description		: 打开设备
 * @param - inode 	: 传递给驱动的inode
 * @param - filp 	: 设备文件,file结构体有个叫做private_data的成员变量
 * 					  一般在open的时候将private_data指向设备结构体。
 * @return 			: 0 成功;其他 失败
 */
static int led_open(struct inode *inode, struct file *filp)
{
	return 0;
}

/*
 * @description		: 从设备读取数据 
 * @param - filp 	: 要打开的设备文件(文件描述符)
 * @param - buf 	: 返回给用户空间的数据缓冲区
 * @param - cnt 	: 要读取的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 读取的字节数,如果为负值,表示读取失败
 */
static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
	return 0;
}

/*
 * @description		: 向设备写数据 
 * @param - filp 	: 设备文件,表示打开的文件描述符
 * @param - buf 	: 要写给设备写入的数据
 * @param - cnt 	: 要写入的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 写入的字节数,如果为负值,表示写入失败
 */
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
	int retvalue;
	unsigned char databuf[1];
	unsigned char ledstat;

	retvalue = copy_from_user(databuf, buf, cnt);
	if(retvalue < 0) {
		printk("kernel write failed!\r\n");
		return -EFAULT;
	}

	ledstat = databuf[0];		/* 获取状态值 */

	if(ledstat == LEDON) {	
		led_switch(LEDON);		/* 打开LED灯 */
	} else if(ledstat == LEDOFF) {
		led_switch(LEDOFF);	/* 关闭LED灯 */
	}
	return 0;
}

/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */
static int led_release(struct inode *inode, struct file *filp)
{
	return 0;
}

/* 设备操作函数 */
static struct file_operations led_fops = {
	.owner = THIS_MODULE,
	.open = led_open,
	.read = led_read,
	.write = led_write,
	.release = 	led_release,
};

/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static int __init led_init(void)
{
	int retvalue = 0;
	u32 val = 0;

	/* 初始化LED */
	/* 1、寄存器地址映射 */
  	IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);
	SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);
  	SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4);
	GPIO1_DR = ioremap(GPIO1_DR_BASE, 4);
	GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE, 4);

	/* 2、使能GPIO1时钟 */
	val = readl(IMX6U_CCM_CCGR1);
	val &= ~(3 << 26);	/* 清楚以前的设置 */
	val |= (3 << 26);	/* 设置新值 */
	writel(val, IMX6U_CCM_CCGR1);

	/* 3、设置GPIO1_IO03的复用功能,将其复用为
	 *    GPIO1_IO03,最后设置IO属性。
	 */
	writel(5, SW_MUX_GPIO1_IO03);
	
	/*寄存器SW_PAD_GPIO1_IO03设置IO属性
	 *bit 16:0 HYS关闭
	 *bit [15:14]: 00 默认下拉
     *bit [13]: 0 kepper功能
     *bit [12]: 1 pull/keeper使能
     *bit [11]: 0 关闭开路输出
     *bit [7:6]: 10 速度100Mhz
     *bit [5:3]: 110 R0/6驱动能力
     *bit [0]: 0 低转换率
	 */
	writel(0x10B0, SW_PAD_GPIO1_IO03);

	/* 4、设置GPIO1_IO03为输出功能 */
	val = readl(GPIO1_GDIR);
	val &= ~(1 << 3);	/* 清除以前的设置 */
	val |= (1 << 3);	/* 设置为输出 */
	writel(val, GPIO1_GDIR);

	/* 5、默认关闭LED */
	val = readl(GPIO1_DR);
	val |= (1 << 3);	
	writel(val, GPIO1_DR);

	/* 6、注册字符设备驱动 */
	retvalue = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
	if(retvalue < 0){
		printk("register chrdev failed!\r\n");
		return -EIO;
	}
	return 0;
}

/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static void __exit led_exit(void)
{
	/* 取消映射 */
	iounmap(IMX6U_CCM_CCGR1);
	iounmap(SW_MUX_GPIO1_IO03);
	iounmap(SW_PAD_GPIO1_IO03);
	iounmap(GPIO1_DR);
	iounmap(GPIO1_GDIR);

	/* 注销字符设备驱动 */
	unregister_chrdev(LED_MAJOR, LED_NAME);
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");

第 22~26 行,定义了一些宏,包括主设备号、设备名字、 LED 开/关宏。
第 29~33 行,本实验要用到的寄存器宏定义。
第 36~40 行,经过内存映射以后的寄存器地址指针。
第 47~59 行, led_switch 函数,用于控制开发板上的 LED 灯亮灭,当参数 sta 为 LEDON(1)的时候打开 LED 灯, sta 为 LEDOFF(0)的时候关闭 LED 灯。
第 68~71 行, led_open 函数,为空函数,可以自行在此函数中添加相关内容,一般在此函数中将设备结构体作为参数 filp 的私有数据(filp->private_data)。
第 81~84 行, led_read 函数,为空函数,如果想在应用程序中读取 LED 的状态,那么就可以在此函数中添加相应的代码,比如读取 GPIO1_DR 寄存器的值,然后返回给应用程序。
第 94~114 行, led_write 函数,实现对 LED 灯的开关操作,当应用程序调用 write 函数向 led 设备写数据的时候此函数就会执行。首先通过函数 copy_from_user 获取应用程序发送过来的操作信息(打开还是关闭 LED),最后根据应用程序的操作信息来打开或关闭 LED 灯。
第 121~124 行, led_release 函数,为空函数,可以自行在此函数中添加相关内容,一般关闭设备的时候会释放掉 led_open 函数中添加的私有数据。
第 127~133 行,设备文件操作结构体 led_fops 的定义和初始化。
第 140~185 行,驱动入口函数 led_init,此函数实现了 LED 的初始化工作, 147~151 行通过 ioremap 函数获取物理寄存器地址映射后的虚拟地址,得到寄存器对应的虚拟地址以后就可以完成相关初始化工作了。比如使能 GPIO1 时钟、设置 GPIO1_IO03 复用功能、配置 GPIO1_IO03 的属性等等。最后,最重要的一步!使用 register_chrdev 函数注册 led 这个字符设备。
第 192~202 行,驱动出口函数 led_exit,首先使用函数 iounmap 取消内存映射,最后使用函数 unregister_chrdev 注销 led 这个字符设备。
第 205~206 行,使用 module_init 和 module_exit 这两个函数指定 led 设备驱动加载和卸载函数。
第 207~208 行,添加 LICENSE 和作者信息。


2. 编写测试 APP

编写测试 APP, led 驱动加载成功以后手动创建/dev/led 节点,应用 APP 通过操作/dev/led 文件来完成对 LED 设备的控制。向/dev/led 文件写 0 表示关闭 LED 灯,写 1 表示打开 LED 灯。新建 ledApp.c 文件,在里面输入如下内容:

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名		: ledApp.c
作者	  	: 左忠凯
版本	   	: V1.0
描述	   	: chrdevbase驱测试APP。
其他	   	: 无
使用方法	 :./ledtest /dev/led  0 关闭LED
		     ./ledtest /dev/led  1 打开LED		
论坛 	   	: www.openedv.com
日志	   	: 初版V1.0 2019/1/30 左忠凯创建
***************************************************************/

#define LEDOFF 	0
#define LEDON 	1

/*
 * @description		: main主程序
 * @param - argc 	: argv数组元素个数
 * @param - argv 	: 具体参数
 * @return 			: 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
	int fd, retvalue;
	char *filename;
	unsigned char databuf[1];
	
	if(argc != 3){
		printf("Error Usage!\r\n");
		return -1;
	}

	filename = argv[1];

	/* 打开led驱动 */
	fd = open(filename, O_RDWR);
	if(fd < 0){
		printf("file %s open failed!\r\n", argv[1]);
		return -1;
	}

	databuf[0] = atoi(argv[2]);	/* 要执行的操作:打开或关闭 */

	/* 向/dev/led文件写入数据 */
	retvalue = write(fd, databuf, sizeof(databuf));
	if(retvalue < 0){
		printf("LED Control Failed!\r\n");
		close(fd);
		return -1;
	}

	retvalue = close(fd); /* 关闭文件 */
	if(retvalue < 0){
		printf("file %s close failed!\r\n", argv[1]);
		return -1;
	}
	return 0;
}

ledApp.c 的内容还是很简单的,就是对 led 的驱动文件进行最基本的打开、关闭、写操作等。


三、运行测试

1. 编译驱动程序和测试 APP

1.1 编译驱动程序

编写 Makefile 文件,本章实验的 Makefile 文件和第四十章实验基本一样,只是将 obj-m 变量的值改为 led.o, Makefile 内容如下所示:

KERNELDIR := /home/zuozhongkai/linux/IMX6ULL/linux/temp/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
CURRENT_PATH := $(shell pwd)

obj-m := led.o

build: kernel_modules

kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules

clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

第 4 行,设置 obj-m 变量的值为 led.o。输入如下命令编译出驱动模块文件:make -j32
编译成功以后就会生成一个名为“led.ko”的驱动模块文件。


1.2 编译测试 APP

输入如下命令编译测试 ledApp.c 这个测试程序:
arm-linux-gnueabihf-gcc ledApp.c -o ledApp
编译成功以后就会生成 ledApp 这个应用程序。


2. 运行测试

将编译出来的led.ko和ledApp这两个文件拷贝到rootfs/lib/modules/4.1.15目录中,重启开发板,进入到目录 lib/modules/4.1.15 中,输入如下命令加载 led.ko 驱动模块:

depmod 				//第一次加载驱动的时候需要运行此命令
modprobe led.ko 	//加载驱动

驱动加载成功以后创建“/dev/led”设备节点,命令如下:

mknod /dev/led c 200 0

驱动节点创建成功以后就可以使用 ledApp 软件来测试驱动是否工作正常,输入如下命令打开 LED 灯:

./ledApp /dev/led 1 //打开 LED 灯

输入上述命令以后观察 I.MX6U-ALPHA 开发板上的红色 LED 灯是否点亮,如果点亮的话说明驱动工作正常。在输入如下命令关闭 LED 灯:

./ledApp /dev/led 0 //关闭 LED 灯

输入上述命令以后观察 I.MX6U-ALPHA 开发板上的红色 LED 灯是否熄灭,如果熄灭的话说明我们编写的 LED 驱动工作完全正常!至此,我们成功编写了第一个真正的 Linux 驱动设备程序。

如果要卸载驱动的话输入如下命令即可:

rmmod led.ko
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Linux 驱动篇(二)】LED 驱动开发 的相关文章

  • 我们如何在使用循环时调用 ansible playbook 中的变量

    我有两个文件 其中这些文件包含server names and server IP s 我想更改 替换一些特定的server names and IP addressees根据要求在两个文件中 这与这篇文章 因为它被要求开设一个新职位 ht
  • Pthreads - 高内存使用率

    我正在用 C 编写一些东西 在 256Mb 系统上的 Linux 中创建大量 Pthread 我通常有 200Mb 的免费空间 当我使用少量线程运行该程序时 它可以工作 但是一旦我让它创建大约 100 个线程 它就会出现错误 因为系统内存不
  • 应用程序中两个不同版本的库

    考虑一个场景 其中有两个不同版本的共享库 考虑 A 1 so 链接到 B so A 2 so 链接到 C so 现在 B so 和 C so 都链接到 d exe 当 B so 想要调用 A 1 so 中的函数时 它最终会调用 A 2 so
  • 如何在Linux上用C/C++编写Web服务器[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在考虑在 Linux 平台上开发一个小型 阅读 初级 Web 服务器 但我不知道从哪里开始 我希望它能够做的是 监听特定端口 接受
  • Linux中如何避免sleep调用因信号而中断?

    我在 Linux 中使用实时信号来通知串行端口中新数据的到达 不幸的是 这会导致睡眠呼叫在有信号时被中断 有人知道避免这种行为的方法吗 我尝试使用常规信号 SIGUSR1 但我不断得到相同的行为 来自 nanosleep 联机帮助页 nan
  • Vagrant 遇到问题 - “404 - 未找到”

    我正在尝试使用 Vagrant 制作一个 LAMP 盒子 有人告诉我它使用起来非常简单 我对网络和虚拟机完全陌生 对 Linux Ubuntu 的经验也很少 我目前已尝试按照官方文档页面上的教程进行操作 http docs vagrantu
  • 使用 ioctl 在 C++ 中以编程方式添加路由

    我编写了简单的 C 函数 添加了新路线 void addRoute int fd socket PF INET SOCK DGRAM IPPROTO IP struct rtentry route memset route 0 sizeof
  • 更新Linux中的包含路径

    我的 my path to file 文件夹中有几个头文件 我知道如何将这些文件包含在新的 C 程序中 但每次我都需要在包含它之前输入头文件的完整路径 我可以在linux中设置一些路径变量 以便它自动查找头文件吗 您可以创建一个 makef
  • Bash:将字符串添加到文件末尾而不换行

    如何将字符串添加到文件末尾而不换行 例如 如果我使用 gt gt 它将添加到文件末尾并换行 cat list txt yourText1 root host 37 echo yourText2 gt gt list txt root hos
  • Linux shell 从用户输入中获取设备 ID

    我正在为一个程序编写安装脚本 该程序需要在其配置中使用 lsusb 的设备 ID 因此我正在考虑执行以下操作 usblist lsusb put the list into a array for each line use the arr
  • “git add”返回“致命:外部存储库”错误

    我刚刚进入 git 的奇妙世界 我必须提交我对程序所做的一系列更改 位于名为的目录中 var www myapp 我创建了一个新目录 home mylogin gitclone 从这个目录中 我做了一个git clone针对公共回购 我能够
  • 使用 libusb 输出不正确

    我用libusb编写了一个程序 我怀疑输出是否正确 因为所有条目都显示相同的供应商和产品 ID 以下是代码 include
  • 为 Linux 编译 Objective-C 应用程序(API 覆盖范围)

    我可能在这里问一些奇怪的问题 但我不确定从哪里开始 问题是我正在考虑使用 Obj C 和 Foundation 类在 Mac 上编写一个命令行工具 但存在一个非常大的风险 那就是我希望能够为不同的 Linux 发行版编译它 以便将来作为服务
  • 来自守护程序的错误响应:加入会话密钥环:创建会话密钥:超出磁盘配额

    我尝试在我的服务器上安装 docker 使用本教程 https docs docker com install linux docker ce ubuntu 我想远程运行 docker 镜像并使用 portainer Web 界面来管理一切
  • ioctl 命令的用户权限检查

    我正在实现 char 驱动程序 Linux 并且我的驱动程序中有某些 IOCTL 命令仅需要由 ADMIN 执行 我的问题是如何在 ioctl 命令实现下检查用户权限并限制非特权用户访问 IOCTL 您可以使用bool capable in
  • 在内核代码中查找函数的最佳方法[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我开始浏览内核代码 遇到的一件事是如何跟踪函数调用 结构定义等 有没有一种好的方法可以快速跳转到函数定义并退出 我尝试过 Source N
  • 找不到包“gdk-pixbuf-2.0”

    我正在尝试在 Amazon Linux 发行版实例上构建 librsvg 我已经通过 yum 安装了大部分依赖项 其中一些在实例上启用的默认 yum 存储库中不可用 因此必须从头开始构建它们 我已经走了很远 但还停留在最后一点 跑步时sud
  • SSH,运行进程然后忽略输出

    我有一个命令可以使用 SSH 并在 SSH 后运行脚本 该脚本运行一个二进制文件 脚本完成后 我可以输入任意键 本地终端将恢复到正常状态 但是 由于该进程仍在我通过 SSH 连接的计算机中运行 因此任何时候它都会登录到stdout我在本地终
  • 有没有一种快速方法可以从 Jar/war 中删除文件,而无需提取 jar 并重新创建它?

    所以我需要从 jar war 文件中删除一个文件 我希望有类似 jar d myjar jar file I donot need txt 的内容 但现在我能看到从 Linux 命令行执行此操作的唯一方法 不使用 WinRAR Winzip
  • 在 .gitconfig 中隐藏 GitHub 令牌

    我想将所有点文件存储在 GitHub 上 包括 gitconfig 这需要我将 GitHub 令牌隐藏在 gitconfig 中 为此 我有一个 gitconfig hidden token 文件 这是我打算编辑并放在隐藏令牌的 git 下

随机推荐

  • ctf.show web6 sql注入过滤了空格

    ctf show web6 sql注入过滤了空格 开始的页面 是一个登录的页面 随便输入用户名和密码 没有报错之类的 就把账户名和密码都清空了 那就来burpsuit抓包 先用个万能密码 or 1 1
  • 加密 scrapy

    js常见的加密方式 加密在前端开发和爬虫中是经常遇见的 掌握了加密算法且可以将加密的密文进行解密破解的 也是你从一个编程小白到大神级别质的一个飞跃 且加密算法的熟练和剖析也是很有助于帮助我们实现高效的js逆向 下述只把我们常用的加密方法进行
  • Windows服务器怎么才能长时间保持远程桌面不自动断开

    服务器在通过mstsc远程连接后 如果长时间不操作 会自动断开 这种是Windows系统的远程保护机制 但是对于操作服务器来说 这种断开可能会影响到工作效率 那么如何设置才能一直保持连接状态呢 用过Windows自带的远程桌面连接服务可能都
  • Please make sure you have the correct access rights

    使用git克隆 拉取 提交的时候 发现不能操作 提示如下 Please make sure you have the correct access rights fatal Could not read from remote reposi
  • QTP工具简单操作使用说明

    简介 QTP是QuickTest Professional 的简称 是一种自动化测试工具 使用QTP的目的是用它来执行重复的手动测试 主要用于回归测试和测试同一软件的新版本 版本迭代 启动QuickTest 第一次启动QuickTest时
  • go的channel实现归并排序

    func main ch1 create int 1 3 6 待排序的管道1 ch2 create int 2 5 9 待排序的管道2 ch merge ch1 ch2 for c range ch fmt Println c for ru
  • java概述,发展历程

    1 java概述 首先对于刚刚接触java的小白来说 可能连java是什么 为什么叫这么名字都不知道 其实 Java语言是有个曾用名的 叫Oak 而且起这个名字的时候也是很随心的 只是因为看到了窗口外的一颗橡树 歌词 只是因为面向窗外多看了
  • python 合并不同文件夹下名称相同的文件

    转载 https blog csdn net qq 42769683 article details 104565285 utm source app app version 4 10 0 code app 1562916241 uLink
  • 3D 人体姿态估计简述[转]

    转自 3D 人体姿态估计简述 知乎 0 前言 3D Human Pose Estimation 以下简称 3D HPE 的目标是在三维空间中估计人体关键点的位置 3D HPE 的应用非常广泛 包括人机交互 运动分析 康复训练等 它也可以为其
  • 使用Python的Cufflinks库创建三维散点图

    使用Python的Cufflinks库创建三维散点图 在数据可视化中 三维散点图是一种常用的图形展示方式 如果您正在寻找一种方便易用的数据可视化工具来创建三维散点图 那么Cufflinks就是一个不错的选择 Cufflinks是一个基于pl
  • 恕我直言,自从用完Gradle后,有点嫌弃Maven了!速度贼快!

    点击上方蓝色字体 选择 标星公众号 优质文章 第一时间送达 99套Java企业级实战项目 4000G架构师资料 作者 乐百川 点击阅读原文前往 授权转载自 toutiao com i6824937779193971207 相信使用Java的
  • Spring 基于ApplicationEvent、ApplicationEventPublisher、ApplicationListener的事件监听、发布记录

    1 概述 事件发布和订阅具体流程 1 具体要发布的事件 事件中携带发送的数据 2 发送事件 3 监听器 监听发布的事件 获取事件的携带数据 执行业务逻辑 发布 事件作为参数 事件 监听 事件作为参数 例如 使用切面记录系统日志 发送相同类型
  • oracle 9i在线重定义,Oracle 9i中表的在线重定义(转)

    今天遇到要把数据库中的某张表改成分区表 而且该表在别的地方还有其他的注册信息 如果自己手工建一个分区表的替代该表的话 那就得要手工地去执行该表在其他地方的注册 所以不想删除该表再手工创建同名的分区表 想到了Oracle 9i中可以使用在线重
  • gitee上传代码方法(命令)

    第一次上传 创建一个gitee仓库 在 我的电脑 里找到你要上传的文件的位置 在地址栏输入cmd 回车 输入git init 输入git add 输入git commit m 备注信息可更改 输入 git remote add origin
  • C语言中的清屏函数(自己编写)

    在csdn论坛里看到这样一个问题 如何在c语言命令提示下清除屏幕 感兴趣 随查之 有解 include
  • 蓝帽杯半决赛2022

    手机取证 1 iPhone手机的iBoot固件版本号 答案参考格式 iBoot 1 1 1 直接通过盘古石取证 打开 取证大师和火眼不知道为什么都无法提取这个 手机取证 2 该手机制作完备份UTC 8的时间 非提取时间 答案参考格式 200
  • 修炼离线:(五)hbase映射表插入hive

    一 创建hive表 sql drop table if exists ods odsyyy create table if not exists ods odsfff row id string comment 行记录唯一ID 对应ROW
  • Makefile入门二、理解$@、$^和$<

    文章目录 一 理解 lt 的含义 二 举例 三 简提Makefile中打印日志信息 前面简单记录了一下Makefile中helloworld的用法 这次来理解一些 lt 的含义 一 理解 lt 的含义 Makefile中 格式为这样的 ta
  • Spring Roo 实站( 一 )部署安装 & 第一个示例程序

    一 安装 注 可以参与官网spring roo static springsource org spring roo reference html intro html intro exploring sampleROO OPTS http
  • 【Linux 驱动篇(二)】LED 驱动开发

    文章目录 一 Linux 下 LED 灯驱动原理 1 地址映射 1 1 ioremap 函数 1 2 iounmap 函数 2 I O 内存访问函数 2 1 读操作函数 2 2 写操作函数 二 实验程序编写 1 LED 灯驱动程序编写 2