当前位置: 首页 > news >正文

编写一个简单的Iinput_dev框架

往期内容

本专栏往期内容:

  1. input子系统的框架和重要数据结构详解-CSDN博客
  2. input device和input handler的注册以及匹配过程解析-CSDN博客
  3. input device和input handler的注册以及匹配过程解析-CSDN博客

I2C子系统专栏:

  1. 专栏地址:IIC子系统_憧憬一下的博客-CSDN博客
  2. 具体芯片的IIC控制器驱动程序分析:i2c-imx.c-CSDN博客
    – 末篇,有往期内容观看顺序

总线和设备树专栏:

  1. 专栏地址:总线和设备树_憧憬一下的博客-CSDN博客
  2. 设备树与 Linux 内核设备驱动模型的整合-CSDN博客
    – 末篇,有往期内容观看顺序

前言

img
img

和之前的驱动程序有点差别(IIC专栏中编写的控制器驱动框架编写一个通用的i2c控制器驱动框架-CSDN博客),在driver中变成注册input_dev,file_operations字符驱程序的创建在input_handler层实现(原本是在platform_driver中实现的:file_operation、设备类的注册),实现了内核驱动程序的上层、中转层、下层的分离

下层驱动中,只需要去编写好设备的驱动程序,在程序中分配、设置、注册input_dev,发生中断时只需要上报中断事件即可,其余的中转层和上层的驱动程序内核已经做好了。

这个在之前对内核提供的源码示例进行讲解的时候也很清晰了,详见本专栏前3章内容。

1. 怎么编写input_dev驱动

这里参考内核提供的gpio_keys.c为例子,input_dev上层

\Linux-4.9.88\drivers\input\keyboard\gpio_keys.c:📎gpio_keys.c

1.1 分配、设置、注册input_dev

这一部分主要是probe完成:

img

在gpio_keys.c中,添加了自己理解的一点注释,如下:

static int gpio_keys_probe(struct platform_device *pdev)
{struct device *dev = &pdev->dev;  // 获取设备结构体const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);  // 从平台设备获取平台数据struct gpio_keys_drvdata *ddata;  // 驱动私有数据结构struct input_dev *input;  // 输入设备结构体size_t size;  // 计算需要分配的内存大小int i, error;  // 循环计数器和错误码int wakeup = 0;  // 标志位,指示是否支持唤醒功能// 如果 pdata 为 NULL,则从设备树获取平台数据if (!pdata) {pdata = gpio_keys_get_devtree_pdata(dev);if (IS_ERR(pdata))return PTR_ERR(pdata);  // 返回错误码}// 计算 gpio_keys_drvdata 和按钮数据结构的大小size = sizeof(struct gpio_keys_drvdata) +pdata->nbuttons * sizeof(struct gpio_button_data);// 分配驱动私有数据内存ddata = devm_kzalloc(dev, size, GFP_KERNEL);if (!ddata) {dev_err(dev, "failed to allocate state\n");  // 分配失败,输出错误信息return -ENOMEM;  // 返回内存不足错误码}// 分配输入设备input = devm_input_allocate_device(dev);if (!input) {dev_err(dev, "failed to allocate input device\n");  // 分配失败,输出错误信息return -ENOMEM;  // 返回内存不足错误码}ddata->pdata = pdata;  // 保存平台数据指针ddata->input = input;  // 保存输入设备指针mutex_init(&ddata->disable_lock);  // 初始化互斥锁// 将驱动数据指针与平台设备相关联platform_set_drvdata(pdev, ddata);input_set_drvdata(input, ddata);  // 将驱动数据与输入设备关联// 设置输入设备名称和物理路径input->name = pdata->name ? : pdev->name;  // 如果 pdata 中有名称则使用,否则使用平台设备名称input->phys = "gpio-keys/input0";  // 设置物理路径input->dev.parent = &pdev->dev;  // 设置设备的父设备input->open = gpio_keys_open;  // 设置打开设备的函数input->close = gpio_keys_close;  // 设置关闭设备的函数// 设置输入设备的 IDinput->id.bustype = BUS_HOST;  // 设置总线类型input->id.vendor = 0x0001;  // 设置厂商 IDinput->id.product = 0x0001;  // 设置产品 IDinput->id.version = 0x0100;  // 设置版本号// 启用 Linux 输入子系统的自动重复功能if (pdata->rep)__set_bit(EV_REP, input->evbit);  // 设置 EV_REP 事件位// 遍历每个按钮并设置for (i = 0; i < pdata->nbuttons; i++) {const struct gpio_keys_button *button = &pdata->buttons[i];  // 获取当前按钮信息struct gpio_button_data *bdata = &ddata->data[i];  // 获取按钮数据error = gpio_keys_setup_key(pdev, input, bdata, button);  // 设置按键,里面包括设置了中断函数if (error)return error;  // 返回错误码if (button->wakeup)  // 如果按钮支持唤醒功能wakeup = 1;  // 设置唤醒标志}// 创建 sysfs 组,用于导出按键和开关error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);if (error) {dev_err(dev, "Unable to export keys/switches, error: %d\n", error);  // 输出错误信息return error;  // 返回错误码}// 注册输入设备error = input_register_device(input);if (error) {dev_err(dev, "Unable to register input device, error: %d\n", error);  // 输出错误信息goto err_remove_group;  // 错误处理,移除 sysfs 组}// 初始化唤醒设备功能device_init_wakeup(&pdev->dev, wakeup);return 0;  // 返回成功err_remove_group:// 在错误情况下移除 sysfs 组sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);return error;  // 返回错误码
}

可以看出来,分配、设置、注册input_dev,然后去注册中断函数,用于调用中断的input_event函数上报中断事件,尝试写一个:

static struct input_dev *g_input_dev;
static int g_irq;
static irqreturn_t input_dev_demo_isr(int irq, void *dev_id)
{/* read data *//* report data */input_event(g_input_dev, EV_KEY, XX, 0);//通过 input_event() 上报事件,input_sync() 用于同步报告的输入事件。input_sync(g_input_dev);return IRQ_HANDLED;
}static int input_dev_demo_probe(struct platform_device *pdev)
{struct device *dev = &pdev->dev;int error;struct resource *irq;/* 从设备树中获取硬件信息 *//* 分配、设置并注册 input_dev */g_input_dev = devm_input_allocate_device(dev);// 设置输入设备的基本信息g_input_dev->name = "input_dev_demo";g_input_dev->phys = "input_dev_demo";g_input_dev->dev.parent = dev;g_input_dev->id.bustype = BUS_HOST;g_input_dev->id.vendor = 0x0001;g_input_dev->id.product = 0x0001;g_input_dev->id.version = 0x0100;/* 设置 1: 支持的事件类型 */__set_bit(EV_KEY, g_input_dev->evbit); // 键盘或按钮事件__set_bit(EV_ABS, g_input_dev->evbit); // 绝对坐标事件/* 设置 2: 支持的具体事件 */__set_bit(BTN_TOUCH, g_input_dev->keybit); // 触摸按钮事件__set_bit(ABS_MT_SLOT, g_input_dev->absbit); // 多点触摸槽位__set_bit(ABS_MT_POSITION_X, g_input_dev->absbit); // 触摸屏 X 轴坐标__set_bit(ABS_MT_POSITION_Y, g_input_dev->absbit); // 触摸屏 Y 轴坐标/* 设置 3: 事件参数 */input_set_abs_params(g_input_dev, ABS_MT_POSITION_X, 0, 0xffff, 0, 0); // X 坐标范围input_set_abs_params(g_input_dev, ABS_MT_POSITION_Y, 0, 0xffff, 0, 0); // Y 坐标范围// 注册输入设备error = input_register_device(g_input_dev);/* 硬件操作: 获取中断资源并注册中断 */irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);g_irq = irq->start;request_irq(irq->start, input_dev_demo_isr, IRQF_TRIGGER_RISING, "input_dev_demo_irq", NULL);return 0;
}

1.2 硬件相关操作

  • 申请中断
  • 在中断服务程序里
    • 读取硬件获得数据
    • 上报数据
void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value);static inline void input_sync(struct input_dev *dev); // 实质也是 input_event

input子系统中读取流程解析-CSDN博客
具体内容在该章节的 event 处已经讲解过。

2. 代码

img

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h>/* 定义指向输入设备结构体的指针 */
static struct input_dev *input_device_demo;
/* 用于保存输入设备的中断号 */
static int irq_num;/* 中断服务程序,处理输入设备的事件 */
static irqreturn_t input_device_demo_isr(int irq, void *dev_id)
{/* 可在此处添加数据读取和事件处理逻辑 *//* 向输入子系统报告按键事件 */input_event(input_device_demo, EV_KEY, KEY_TOUCH, 0);input_sync(input_device_demo);return IRQ_HANDLED;
}/* 分配、配置和注册平台驱动 */
static int input_device_demo_probe(struct platform_device *pdev)
{struct device *dev = &pdev->dev;int error;struct resource *irq;/* 从设备树获取硬件信息 *//* 分配并初始化输入设备结构体 */input_device_demo = devm_input_allocate_device(dev);if (!input_device_demo)return -ENOMEM;/* 设置设备名称和物理位置 */input_device_demo->name = "input_device_demo";input_device_demo->phys = "input_device_demo";input_device_demo->dev.parent = dev;/* 设置设备的总线类型和ID */input_device_demo->id.bustype = BUS_HOST;input_device_demo->id.vendor = 0x0001;input_device_demo->id.product = 0x0001;input_device_demo->id.version = 0x0100;/* 设置输入设备支持的事件类型 */__set_bit(EV_KEY, input_device_demo->evbit); // 支持按键事件__set_bit(EV_ABS, input_device_demo->evbit); // 支持绝对位置事件/* 设置输入设备支持的具体事件 */__set_bit(BTN_TOUCH, input_device_demo->keybit); // 支持触摸按键事件__set_bit(ABS_MT_SLOT, input_device_demo->absbit); // 多点触控槽位事件__set_bit(ABS_MT_POSITION_X, input_device_demo->absbit); // X轴位置事件__set_bit(ABS_MT_POSITION_Y, input_device_demo->absbit); // Y轴位置事件/* 设置具体事件的参数范围,例如X和Y坐标的最小值、最大值等 */input_set_abs_params(input_device_demo, ABS_MT_POSITION_X, 0, 0xffff, 0, 0);input_set_abs_params(input_device_demo, ABS_MT_POSITION_Y, 0, 0xffff, 0, 0);/* 注册输入设备 */error = input_register_device(input_device_demo);if (error)return error;/* 硬件操作:从设备树获取中断资源并注册中断 */irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);irq_num = irq->start;error = request_irq(irq_num, input_device_demo_isr, IRQF_TRIGGER_RISING, "input_device_demo_irq", NULL);if (error)input_unregister_device(input_device_demo);return error;
}/* 驱动移除函数,释放中断资源并注销输入设备 */
static int input_device_demo_remove(struct platform_device *pdev)
{free_irq(irq_num, NULL);input_unregister_device(input_device_demo);return 0;
}/* 设备树匹配表,用于匹配设备树中描述的设备 */
static const struct of_device_id input_device_demo_of_match[] = {{ .compatible = "input,input_device_demo", },{ },
};/* 定义平台驱动结构体,指定probe和remove函数 */
static struct platform_driver input_device_demo_driver = {.probe = input_device_demo_probe,.remove = input_device_demo_remove,.driver = {.name = "input_device_demo",.of_match_table = input_device_demo_of_match,}
};/* 模块初始化函数,注册平台驱动 */
static int __init input_device_demo_init(void)
{return platform_driver_register(&input_device_demo_driver);
}/* 模块退出函数,注销平台驱动 */
static void __exit input_device_demo_exit(void)
{platform_driver_unregister(&input_device_demo_driver);
}module_init(input_device_demo_init);
module_exit(input_device_demo_exit);MODULE_LICENSE("GPL");

img

在以前的驱动程序模板中,platform_driver中不仅注册了file_operation等,也注册了中断处理函数,并且中断处理函数中是直接对中断事件进行处理

但是在内核驱动分层中,platform_input_dev,中断处理函数只上报中断事件给input.c,交由Input.c去调用input_dev对应的input_handler中的函数来处理中断(filter、events、event函数),同时input_handler层提供了app调用的接口函数,如file_operation中的read

相关文章:

编写一个简单的Iinput_dev框架

往期内容 本专栏往期内容&#xff1a; input子系统的框架和重要数据结构详解-CSDN博客input device和input handler的注册以及匹配过程解析-CSDN博客input device和input handler的注册以及匹配过程解析-CSDN博客 I2C子系统专栏&#xff1a; 专栏地址&#xff1a;IIC子系统_憧憬…...

ctfshow的sql注入解题思路171-211

ctfshow-SQL注入 web171&#xff1a;爆库名->爆表名->爆字段名->爆字段值 -1 union select 1,database() ,3 -- //返回数据库名 -1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema库名 -- //获取数据库里的表名 -…...

深入理解C语言中的静态库与动态库 —— 原理与实践

引言 在 C 语言编程中&#xff0c;库是预编译的代码集合&#xff0c;用于实现特定功能&#xff0c;以供其他程序使用。库可以分为静态库和动态库两种主要类型。静态库在编译阶段被链接到目标程序中&#xff0c;而动态库则是在运行时被加载。本文旨在深入探讨这两种库的工作原理…...

本地缓存库分析(一):golang-lru

文章目录 本地缓存概览golang-lru标准lrulru的操作PutGet 2q&#xff1a;冷热分离lruPutGet expirable_lru&#xff1a;支持过期时间的lruPutGet过期 总结 本地缓存概览 在业务中&#xff0c;一般会将极高频访问的数据缓存到本地。以减少网络IO的开销&#xff0c;下游服务的压…...

qt配置https请求

qt应用版本 windows 32位 先说下心理路程&#xff0c;你能遇到的我都遇到了&#xff0c;你能想到的我都想到了&#xff0c;怎么解决看这一篇就够了&#xff0c;从上午12点到晚上12点几乎没离开电脑&#xff08;除了吃饭&#xff09;&#xff0c;对于openssl这种用的时候无感&am…...

C语言进阶——文件操作

一、文件的基本知识 1.1什么是文件 在程序设计中&#xff0c;一般谈的文件有两种&#xff1a;程序文件、数据文件。 程序文件&#xff1a;包括源程序文件&#xff08;后缀为.c&#xff09;&#xff0c;目标文件&#xff08;windows环境后缀为.obj&#xff09;&#xff0c;可执…...

MYSQL-查看用户权限语法(二十一)

13.7.5.21 SHOW GRANTS 语句 SHOW GRANTS [FOR user]此语句以GRANT语句的形式显示分配给MySQL用户帐户的权限&#xff0c;必须执行GRANT语句才能复制权限分配。 注意 要显示MySQL帐户的非特权信息&#xff0c;请使用SHOW CREATE USER语句。 参见第 13.7.5.12 节“ SHOW CREA…...

在MySQL中存储IP地址的最佳实践

文章目录 一、IP地址的格式二、存储IP地址的数据类型选择1. VARCHAR优点缺点 2. INT 或 BIGINT优点缺点示例 3. VARBINARY优点缺点示例 三、最佳实践建议1. 选择合适的数据类型2. 索引优化3. 数据验证4. 安全性考虑 四、Java支持五、结论 在现代网络应用中&#xff0c;IP地址是…...

Vite打包配置

Vite打包配置 1.项目启动自动打开网页 {"scripts": {"dev": "vite --open"} }2.base配置打包公共路径 配置base选项的作用主要是指定项目在开发或生产环境中的公共基础路径。这个配置项对于确保资源能够正确加载尤为关键&#xff0c;尤其是在…...

node集成redis (教学)

文章目录 前言一、安装redis二、可视化界面测试连接1.vscode安装插件 三、node代码编写1.先安装两个库&#xff08;redis和ioredis&#xff09;2.测试连接 &#xff08;前提是你的redis服务器要启动起来&#xff09; 总结 前言 在Node.js中集成ioredis是一个常见的做法&#x…...

江协科技STM32学习- P22 实验-ADC单通道/ADC多通道

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…...

RL学习笔记-马尔可夫过程

参考资料&#xff1a;蘑菇书、周博磊老师课程 在强化学习中&#xff0c;智能体与环境交互是通过马尔可夫决策过程来表示的&#xff0c;因此马尔可夫决策过程是强化学习的基本框架。 马尔可夫性质 指一个随机过程在给定现在状态及所有过去状态情况下&#xff0c;其未来状态的条件…...

LeetCode Hot 100:动态规划

LeetCode Hot 100&#xff1a;动态规划 70. 爬楼梯 class Solution { public:int climbStairs(int n) {if (n 0)return 0;vector<int> dp(n 1);// 初始化dp[0] 1;// 状态转移for (int i 1; i < n; i) {dp[i] dp[i - 1];if (i > 2)dp[i] dp[i - 2];}return …...

使用Python制作雪景图片教程

如果你想用Python写一个程序来输出有关“深夜雪”的诗意文本或描述&#xff0c;可以通过简单的字符串输出来实现。以下是一个示例代码&#xff0c;展示如何用Python来描绘深夜雪的场景。 # 定义深夜雪的描述 description """ 夜幕降临&#xff0c;天空洒下银色…...

S-Function

目录 S-Function介绍 生成S-Function的三种常用手段 使用手写S-函数合并定制代码 使用S-Function Builder块合并定制代码 使用代码继承工具合并定制代码 S-Function介绍 我们可以使用S-Function扩展Simulink对仿真和代码生成的支持。例如&#xff0c;可以使用它们&#xf…...

如何具备阅读JAVA JDK虚拟机源码能力

源码位置https://github.com/openjdk/jdk 核心实现源码[部分截图] /* * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistr…...

Python | Leetcode Python题解之第514题自由之路

题目&#xff1a; 题解&#xff1a; Test "godding" target "d"i 0left i lc 0 right i rc 0while Test[left] ! target:left - 1lc 1if left -1:left len(Test) - 1while Test[right] ! target:right 1rc 1if right len(Test):right 0prin…...

Docker 镜像下载问题及解决办法

Docker 镜像下载问题及解决办法 我在杂乱的、破旧的村庄寂寞地走过漫长的雨季&#xff0c;将我年少的眼光从晦暗的日子里打捞出来的是一棵棵开花的树&#xff0c;它们以一串串卓然不俗的花擦明了我的眼睛&#xff0c;也洗净了我的灵魂。 引言 在使用 Docker 时&#xff0c;用户…...

2分钟搞定 HarmonyOs Next创建模拟器

官方文档参考链接&#xff1a; 创建模拟器-管理模拟器-使用模拟器运行应用/服务-应用/服务运行-DevEco Studio - 华为HarmonyOS开发者https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-emulator-create-V5 1. 首先打开Device Manager 2. 进入这个界面后…...

方形件排样优化与订单组批问题探析

方形件排样优化与订单组批问题是计算复杂度很高的组合优化问题&#xff0c;在工业工程中有很广泛的应用背景。为实现个性化定制生产模式&#xff0c;企业会选择订单组批的方式&#xff0c;继而通过排样优化实现批量切割&#xff0c;加工完成后再按照不同客户需求进行分拣&#…...

vue3组件通信--自定义事件

自定义事件是典型的子传父的方法。 为什么叫自定义事件呢&#xff1f;是因为我们用sendToy"getToy"这种格式写&#xff0c;很显然&#xff0c;在DOM中&#xff0c;没有叫sendToy的事件。 父组件FatherComponent.vue: <script setup> import ChildComponent fr…...

ubuntu 安装k3s

配置hostname的方法为 hostnamectl set-hostname k3sserver hostnamectlsudo apt-get update && sudo apt-get upgrade -y sudo apt-get install -y curl#手动下载v1.31.1k3s1 https://github.com/k3s-io/k3s/releases/tag/v1.31.1%2Bk3s1 #将k3s-airgap-images-amd64…...

SQL CHECK 约束:确保数据完整性的关键

SQL CHECK 约束:确保数据完整性的关键 在数据库管理中,确保数据的完整性和准确性是至关重要的。SQL(Structured Query Language)提供了多种约束条件来帮助实现这一目标,其中之一就是 CHECK 约束。本文将深入探讨 SQL CHECK 约束的概念、用法和优势,并展示如何在不同的数…...

C++ | Leetcode C++题解之第502题IPO

题目&#xff1a; 题解&#xff1a; typedef pair<int,int> pii;class Solution { public:int findMaximizedCapital(int k, int w, vector<int>& profits, vector<int>& capital) {int n profits.size();int curr 0;priority_queue<int, vect…...

《虚拟现实的边界:探索虚拟世界的未来可能》

内容概要 在虚拟现实&#xff08;VR&#xff09;技术的浪潮中&#xff0c;我们见证了其从实验室的奇想逐渐走向日常生活的非凡旅程。技术发展的背后是不断突破的创新&#xff0c;早期的设备虽然笨重&#xff0c;但如今却趋向精致、轻巧&#xff0c;用户体验显著提升。想象一下…...

Rust教程

2024 Rust现代实用教程&#xff1a;1.1Rust简介与安装更新––2024 Rust现代实用教程&#xff1a;1.2编译器与包管理工具以及开发环境–––––––––––...

测试代理IP的有效性和可用性

使用代理IP的有效性和可用性直接关系到用户的工作效率&#xff0c;尤其是在进行数据抓取、网络爬虫和保护个人隐私等场景中。 一、测试代理IP的必要性 代理IP的可用性测试是确保代理服务正常运行的重要步骤。测试代理IP的必要性主要体现在以下几个方面&#xff1a; 提升工作…...

散列表:为什么经常把散列表和链表放在一起使用?

散列表:为什么经常把散列表和链表放在一起使用? 在计算机科学中,散列表(哈希表)和链表是两种常见的数据结构。你可能会好奇,为什么它们经常被放在一起使用呢?让我们一起来深入探讨这个问题。 一、散列表的特点 散列表是一种根据关键码值(Key value)而直接进行访问的…...

计算机网络:网络层 —— IPv4 地址与 MAC 地址 | ARP 协议

文章目录 IPv4地址与MAC地址的封装位置IPv4地址与MAC地址的关系地址解析协议ARP工作原理ARP高速缓存表 IPv4地址与MAC地址的封装位置 在数据传输过程中&#xff0c;每一层都会添加自己的头部信息&#xff0c;最终形成完整的数据包。具体来说&#xff1a; 应用层生成的应用程序…...

PMP--一、二、三模、冲刺、必刷--分类--10.沟通管理--技巧--文化意识

文章目录 技巧一模10.沟通管理--1.规划沟通管理--文化意识--军事背景和非军事背景人员有文化差异文化意识&#xff1a;题干关键词 “两拨人的背景不同、文化差异、风格差异”。5、 [单选] 项目团队由前军事和非军事小组成员组成。没有军事背景的团队成员认为前军事团队成员在他…...

vs2015 手机网站开发/seo工程师招聘

原题链接&#xff1a;https://uva.onlinejudge.org/index.php?optioncom_onlinejudge&Itemid8&pageshow_problem&problem2031 题意 给你一个有向图&#xff0c;问你定义一个环的平均值为这个环上所有边的平均值&#xff0c;问你最小的环的平均值是多少。 题解 一种…...

重庆公司建设网站/营销管理培训课程

1、查看Linux系统版本&#xff1a;uname -a 2、根据系统版本找到对应的Go语言安装包&#xff0c;Go语言中文网地址&#xff1a;https://studygolang.com/dl 3. 切换到 /usr/local 目录下&#xff0c;下载Go语言安装包&#xff0c;并解压缩&#xff1a; cd /usr/local/#下载安装…...

机关公文写作网站/高佣金app软件推广平台

本文转自&#xff1a;https://blog.csdn.net/jeff06143132/article/details/25696371 连接Oracle&#xff0c;以Oracle用户登陆: $su - oracle$sqlplus 数据库用户/数据库密码 as sysdba输入查询&#xff1a; select * from dba_profiles where profileDEFAULT and resource_na…...

网站平台建设包括哪些/seo搜索引擎优化营销案例

1. 在实际工作中&#xff0c;您可以给工作簿设置编辑权限密码&#xff0c;让工作簿只允许观看而避免被误编辑。首先点击左上角的文件选项卡。 2. 然后在左侧的快捷命令区&#xff0c;选择另存为命令。 3. 接着点击浏览按钮&#xff0c;打开另存为设置窗口。 4. 在弹出的另存为窗…...

wordpress 上传任意附件/搜狐视频

如何判断R为第几范式&#xff1f; 已知一个关系模式的属性之间的语义&#xff0c;也就是相互依赖的关系&#xff0c;如何判断该模式满足第几范式&#xff1f; 1、首先要通过语义把属性之间的函数依赖关系列出来&#xff0c; 2、然后确定哪些属性组合可以候选码&#xff0c;从…...

百度站长工具网站验证/自己怎样推广呢

软考体型分值分配...