0%

按位与 & and

两都为 1 才为 1

1
2
3
0 & 0 = 0;
0 & 1 = 0;
1 & 1 = 1;

寄存器特定位清零使用 & 与 and。

因为要两个 1 才为 1,所以可以使用 0 来清零特定的 bit 位

1
2
// 使用 & 和 0 将 bit8 - bit15 清零而其他位不变
reg &= 0xFFFF00FF;

逻辑与 &&

两个都为真是才为真

按位或 | or

只要有一个为 1,就为 1

1
2
3
0 | 0 = 0;
0 | 1 = 1;
1 | 1 = 1;

寄存器特定位置 1,用 | 或。

因为只要有一个为 1 就是 1,可以使用 1 来将特定为置 1

逻辑或 ||

只要有一个条件为真,结果就为真

概述

DRM 学习笔记,参考 vkms, 写了一份简单的 kms 驱动。

环境:

  • buildroot-2022.11.2
  • qemu_arm_vexpress_defconfig
  • linux-5.15.18

源文件:

  • demo_drv.c
  • demo_drv.h
  • demo_lvds.c
  • demo_crtc.c
  • boadr.dts
  • Makefile

源文件

device tree

在 dts 文件 buildroot-2022.11.2/output/build/linux-5.15.18/arch/arm/boot/dts/vexpress-v2p-ca9.dts 中添加相关节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
drm-demo {
compatible = "drm,display-subsystem";
status = "okay";
ports = <&crtc0>;
};

demo-crtc {
compatible = "demo,drm-crtc";
status = "okay";

crtc0: port@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;

crtc0_lvds: endpoint@0 {
reg = <0>;
remote-endpoint = <&lvds_in_0>;
};
};
};

demo-lvds {
compatible = "demo,drm-lvds";
status = "okay";

port@0 {
reg = <0>;

lvds_in_0: endpoint {
remote-endpoint = <&crtc0>;
};
};
};

Makefile

1
2
3
4
5
6
demo-y := \
demo_drv.o \
demo_crtc.o \
demo_lvds.o

obj-$(CONFIG_DRM_DEMO) += demo.o

demo drv

demo_drv.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/* SPDX-License-Identifier: GPL-2.0+ */

#ifndef _DEMO_DRV_H_
#define _DEMO_DRV_H_

#include <linux/hrtimer.h>

#include <drm/drm.h>
#include <drm/drm_gem.h>
#include <drm/drm_encoder.h>
#include <drm/drm_writeback.h>


#include <drm/drm_gem.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_file.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_vblank.h>

#include <linux/component.h>

#define XRES_MIN 20
#define YRES_MIN 20

#define XRES_DEF 1024
#define YRES_DEF 768

#define XRES_MAX 4096
#define YRES_MAX 4096

struct demo_drv {
struct drm_device drm;
struct drm_crtc crtc;
void *userspace_facing;
};

extern struct platform_driver demo_lvds_driver;
extern struct platform_driver demo_crtc_driver;

#endif /* _DEMO_DRV_H_ */

demo_drv.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>

#include <drm/drm_gem.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_file.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_vblank.h>

#include <drm/drm_of.h>

#include <drm/drm_print.h>
#include <drm/drm_debugfs.h>

#include "demo_drv.h"

#define DRIVER_NAME "DRM DEMO"
#define DRIVER_DESC "Kernel Mode Setting Demo"
#define DRIVER_DATE "20230310"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0

static struct drm_driver driver_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM,
// .dumb_create = drm_gem_shmem_dumb_create,

.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
};

static int compare_of(struct device *dev, void *data)
{
struct device_node *np = data;

if (strcmp(dev->driver->name, "demo-crtc") == 0) {
np = of_get_parent(np);
of_node_put(np);
}

return dev->of_node == np;
}

static const struct drm_mode_config_funcs demo_mode_funcs = {
.fb_create = drm_gem_fb_create,
};

static void demo_drm_mode_config_init(struct drm_device *drm)
{
drm->mode_config.max_width = 4096;
drm->mode_config.max_height = 4096;

drm->mode_config.funcs = &demo_mode_funcs;
}

static int demo_drm_bind(struct device *dev)
{
int ret;
struct demo_drv *drv;
struct drm_device *drm;

drv = devm_drm_dev_alloc(dev, &driver_drm_driver,
struct demo_drv, drm);
if (IS_ERR(drv))
return PTR_ERR(drv);

drm = &drv->drm;

ret = drmm_mode_config_init(drm);
if (ret)
return ret;

drm_mode_config_init(drm);

demo_drm_mode_config_init(drm);

ret = component_bind_all(dev, drm);
if (ret) {
pr_err("component_bind_all failed\n");
}

drm_mode_config_reset(drm);

ret = drm_dev_register(drm, 0);
if (ret) {
pr_err("register drm dev failed\n");
return ret;
}

return 0;
}

static void demo_drm_unbind(struct device *dev)
{
pr_info("%s, %d\n", __func__, __LINE__);
}

static const struct component_master_ops demo_drm_ops = {
.bind = demo_drm_bind,
.unbind = demo_drm_unbind,
};

static int driver_probe(struct platform_device *pdev)
{
int ret;

pr_info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
pr_info("drm demo init\n");
pr_info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

// drm_fbdev_generic_setup(drm, 0);

ret = drm_of_component_probe(&pdev->dev, compare_of, &demo_drm_ops);
if (ret) {
pr_err("drm_of_component_probe failed\n");
} else {
pr_err("drm_of_component_probe\n");
}

return 0;
}

// This function is called before the devm_ resources are released
static int driver_remove(struct platform_device *pdev)
{
struct drm_device *drm = platform_get_drvdata(pdev);

drm_dev_unregister(drm);
drm_atomic_helper_shutdown(drm);

return 0;
}

// This function is called on kernel restart and shutdown
static void driver_shutdown(struct platform_device *pdev)
{
drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
}

static int __maybe_unused driver_pm_suspend(struct device *dev)
{
return drm_mode_config_helper_suspend(dev_get_drvdata(dev));
}

static int __maybe_unused driver_pm_resume(struct device *dev)
{
drm_mode_config_helper_resume(dev_get_drvdata(dev));

return 0;
}

static const struct dev_pm_ops driver_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(driver_pm_suspend, driver_pm_resume)
};

static const struct of_device_id drm_demo_dt_ids[] = {
{ .compatible = "drm,display-subsystem", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, drm_demo_dt_ids);

static struct platform_driver demo_drm_driver = {
.driver = {
.name = "drm-demo",
.of_match_table = drm_demo_dt_ids,
.pm = &driver_pm_ops,
},
.probe = driver_probe,
.remove = driver_remove,
.shutdown = driver_shutdown,
};

static struct platform_driver * const drivers[] = {
&demo_drm_driver,
&demo_lvds_driver,
&demo_crtc_driver,
};

static int __init demo_drm_init(void)
{
return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
module_init(demo_drm_init);

static void __exit demo_drm_exit(void)
{
platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(demo_drm_exit);

lvds

demo_lvds.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/mfd/syscon.h>
#include <linux/of_graph.h>
#include <linux/phy/phy.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>

#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>

#include "demo_drv.h"

struct demo_lvds {
struct device *dev;
struct drm_device *drm_dev;
struct device_node *port;

struct drm_connector connector;
struct drm_encoder encoder;

};


static const struct drm_encoder_helper_funcs demo_lvds_encoder_funcs;

static void demo_connector_destroy(struct drm_connector *connector)
{
drm_connector_cleanup(connector);
}

static const struct drm_connector_funcs demo_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = demo_connector_destroy,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};

static int demo_conn_get_modes(struct drm_connector *connector)
{
int count;

count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX);
drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);

return count;
}

static const struct drm_connector_helper_funcs demo_conn_helper_funcs = {
.get_modes = demo_conn_get_modes,
};

static const struct of_device_id demo_lvds_dt_ids[] = {
{
.compatible = "demo,drm-lvds",
},
{}
};
MODULE_DEVICE_TABLE(of, demo_lvds_dt_ids);

static int demo_lvds_bind(struct device *dev, struct device *master,
void *data)
{
struct demo_lvds *lvds = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
struct drm_encoder *encoder;
struct drm_connector *connector;
struct device_node *np = dev->of_node;
int ret;

lvds->drm_dev = drm_dev;
encoder = &lvds->encoder;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
np);

pr_info("possible_crtcs %d\n", encoder->possible_crtcs);

ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_LVDS);
if (ret < 0) {
DRM_DEV_ERROR(drm_dev->dev,
"failed to initialize encoder: %d\n", ret);
return -1;
}

drm_encoder_helper_add(encoder, &demo_lvds_encoder_funcs);

connector = &lvds->connector;
ret = drm_connector_init(drm_dev, connector,
&demo_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
if (ret) {
DRM_ERROR("Failed to init connector\n");
return -1;
}

drm_connector_helper_add(connector, &demo_conn_helper_funcs);

ret = drm_connector_attach_encoder(connector, encoder);
if (ret) {
DRM_ERROR("Failed to attach connector to encoder\n");
return -1;
}

pr_info("%s, %d\n", __func__, __LINE__);
return 0;
}

static void demo_lvds_unbind(struct device *dev, struct device *master,
void *data)
{
pr_info("%s, %d\n", __func__, __LINE__);
}

static const struct component_ops demo_lvds_component_ops = {
.bind = demo_lvds_bind,
.unbind = demo_lvds_unbind,
};

static int demo_lvds_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct demo_lvds *lvds;
int ret = 0;

pr_info("%s, %d\n", __func__, __LINE__);

lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
if (!lvds)
return -ENOMEM;

dev_set_drvdata(dev, lvds);

ret = component_add(&pdev->dev, &demo_lvds_component_ops);
if (ret < 0) {
pr_err("failed to add component\n");
}

return ret;
}

static int demo_lvds_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &demo_lvds_component_ops);
return 0;
}

struct platform_driver demo_lvds_driver = {
.probe = demo_lvds_probe,
.remove = demo_lvds_remove,
.driver = {
.name = "demo-lvds",
.of_match_table = of_match_ptr(demo_lvds_dt_ids),
},
};

crtc

demo_crtc.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/mfd/syscon.h>
#include <linux/of_graph.h>
#include <linux/phy/phy.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>

#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>

#include "demo_drv.h"

struct demo_lvds {
struct device *dev;
struct drm_device *drm_dev;
struct device_node *port;

struct drm_connector connector;
struct drm_encoder encoder;

};


static const struct drm_encoder_helper_funcs demo_lvds_encoder_funcs;

static void demo_connector_destroy(struct drm_connector *connector)
{
drm_connector_cleanup(connector);
}

static const struct drm_connector_funcs demo_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = demo_connector_destroy,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};

static int demo_conn_get_modes(struct drm_connector *connector)
{
int count;

count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX);
drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);

return count;
}

static const struct drm_connector_helper_funcs demo_conn_helper_funcs = {
.get_modes = demo_conn_get_modes,
};

static const struct of_device_id demo_lvds_dt_ids[] = {
{
.compatible = "demo,drm-lvds",
},
{}
};
MODULE_DEVICE_TABLE(of, demo_lvds_dt_ids);

static int demo_lvds_bind(struct device *dev, struct device *master,
void *data)
{
struct demo_lvds *lvds = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
struct drm_encoder *encoder;
struct drm_connector *connector;
struct device_node *np = dev->of_node;
int ret;

lvds->drm_dev = drm_dev;
encoder = &lvds->encoder;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
np);

pr_info("possible_crtcs %d\n", encoder->possible_crtcs);

ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_LVDS);
if (ret < 0) {
DRM_DEV_ERROR(drm_dev->dev,
"failed to initialize encoder: %d\n", ret);
return -1;
}

drm_encoder_helper_add(encoder, &demo_lvds_encoder_funcs);

connector = &lvds->connector;
ret = drm_connector_init(drm_dev, connector,
&demo_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
if (ret) {
DRM_ERROR("Failed to init connector\n");
return -1;
}

drm_connector_helper_add(connector, &demo_conn_helper_funcs);

ret = drm_connector_attach_encoder(connector, encoder);
if (ret) {
DRM_ERROR("Failed to attach connector to encoder\n");
return -1;
}

pr_info("%s, %d\n", __func__, __LINE__);
return 0;
}

static void demo_lvds_unbind(struct device *dev, struct device *master,
void *data)
{
pr_info("%s, %d\n", __func__, __LINE__);
}

static const struct component_ops demo_lvds_component_ops = {
.bind = demo_lvds_bind,
.unbind = demo_lvds_unbind,
};

static int demo_lvds_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct demo_lvds *lvds;
int ret = 0;

pr_info("%s, %d\n", __func__, __LINE__);

lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
if (!lvds)
return -ENOMEM;

dev_set_drvdata(dev, lvds);

ret = component_add(&pdev->dev, &demo_lvds_component_ops);
if (ret < 0) {
pr_err("failed to add component\n");
}

return ret;
}

static int demo_lvds_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &demo_lvds_component_ops);
return 0;
}

struct platform_driver demo_lvds_driver = {
.probe = demo_lvds_probe,
.remove = demo_lvds_remove,
.driver = {
.name = "demo-lvds",
.of_match_table = of_match_ptr(demo_lvds_dt_ids),
},
};

官方文档路径 Copy Between Memory and a File

导出内存为一个文件

1
2
dump [format] memory filename start_addr end_addr
dump [format] value filename expr

Dump the contents of memory from start_addr to end_addr, or the value of expr, to filename in the given format.

The format parameter may be any one of:

  • binary

    Raw binary form.

  • ihex

    Intel hex format.

  • srec

    Motorola S-record format.

  • tekhex

    Tektronix Hex format.

  • verilog

    Verilog Hex format.

将一个文件加载进内存

1
restore filename [binary] bias start end

Restore the contents of file filename into memory. The restore command can automatically recognize any known BFD file format, except for raw binary. To restore a raw binary file you must specify the optional keyword binary after the filename.

If bias is non-zero, its value will be added to the addresses contained in the file. Binary files always start at address zero, so they will be restored at address bias. Other bfd files have a built-in location; they will be restored at offset bias from that location.

If start and/or end are non-zero, then only data between file offset start and file offset end will be restored. These offsets are relative to the addresses in the file, before the bias argument is applied.

Usage

将 /dev/fb0 的文件 dump 出来

1
2
3
4
dump binary memory fb0.argb start_addr end_addr

需要知道虚拟地址(基于物理地址的测试未进行)

将裸数据加载进 fb0

1
restore fb0.argb binary start_addr

可以忽略 end_addr, 加载完后会显示加载到的地址范围

sysfs

在 sysfs 上添加一个文件节点,用于导出一些 debug 信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

static ssize_t reset_store(struct device *dev, struct device_attribute *devatte, const char *buf, size_t size)
{
int ret;
bool enable;

ret = kstrtobool(buf, &enable);
if (ret)
return ret;

if (enable) {
dev_info(dev, "reset\n");
}

return strlen(buf);
}
static DEVICE_ATTR_WO(reset);

static ssize_t debug_show(struct device *dev, struct device_attribute *devatte, char *buf)
{

sprintf(buf, "This is a debug node\n");

sprintf(buf, "%sAdd debug info\n", buf);

return strlen(buf);
}
static DEVICE_ATTR_RO(debug);

static struct attribute *test_attr[] = {
&dev_attr_debug.attr,
&dev_attr_reset.attr,
NULL
};

static int stsfs_create(struct device *dev)
{
int i;

for (i = 0; i < ARRAY_SIZE(test_attr); i++) {
if (!test_attr[i])
break;

if (sysfs_add_file_to_group(&dev->kobj, test_attr[i], NULL) < 0) {
dev_err(dev, "Failed to craeate test attr.\n");
return -1;
}
}
return 0;
}

debugfs

在 debugfs 系统上创建一个节点,调试时需要先挂载 debugfs。

实现过程可参考 ab8500-debugfs.c

1
mount -t debugfs none mnt/

过程:

  1. 在 debugfs 上创建一个 dir
  2. 在 dir 下创建文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

static int ge_debug_show(struct seq_file *s, void *p)
{
seq_printf(s, "This is a debug node\n");

seq_printf(s, "%sAdd debug info\n");
return 0;
}
DEFINE_SHOW_ATTRIBUTE(ge_debug)

static int xxx_probe(struct platform_device *pdev)
{
struct dentry *debug_dir;

debug_dir = debugfs_create_dir("test", NULL);

debugfs_create_file("file_name", (S_IRUGO | S_IWUSR | S_IWGRP), debug_dir, &pdev->dev, &ge_debug_fops);

}

DEFINE_SHOW_ATTRIBUTE会展开,简化代码。详情参考 include/linux/seq_file.h

Linux 5.10 未对 reset 节点的实现进行封装。参考 ab8500-debugfs.c实现,代码较繁琐。

VIM寄存器

VIM有两个地方可以保存临时数据

OS级别-剪切板
VIM级别-寄存器

VIM寄存器概述

寄存器是VIM用于保存临时数据的地方,不同于传统的编辑器(于系统共享一个寄存器,也成为剪切板),VIM具有多个寄存器,分别保存不同的临时数据,活用多个寄存器可以显著提高数据的安全和可操作性。
同时,为了与系统剪切板互通,VIM有一个专用的寄存器,与系统剪切板内容一致,既保证了VIM本身的统一性,也实现了与操作系统的对接。
查看寄存器值

查看所有寄存器值::reg
查看指定寄存器值::reg "{register_name}

调取寄存器值

NORMAL Mode:"{register_name}
COMMAND MODE:<C-r>+"寄存器名称 (输入<C-r>后VIM会自动打出"寄存器引用符号。
INSERT MODE:<C-r>+寄存器名称(无需输入寄存器引用符号")

VIM寄存器分类

  1. 无名寄存器(默认寄存器)

引用方式: ""
该寄存器是默认的寄存器,所有的复制和修改操作(x、s、d、c、y)都会将该数据复制到无名寄存器。

  1. 字母寄存器

引用方式:"a - "z 或"A - "Z
{register_name}只能是一位的26个英文字母,从a-z。
大写字母A-Z寄存器内容将会合并到对应小写字母内容后边。

  1. 数字寄存器

引用方式:"0 (数字0)- "9

3.1 复制专用寄存器 0

引用方式:"0 (数字0)
仅当使用复制操作(y)时,该数据将会同时被复制到无名寄存器和复制专用寄存器。

3.2 逐级临时缓存寄存器1-9**

引用方式:”1 - “9 (数字1-9)
所有不带范围(‘(’,‘)’,‘{’,‘}’)、操作涉及1行以上的删除修改操作(x、s、d、c)的数据都会复制到逐级临时缓存寄存器,并在新的数据加入时,逐级先后推移。1的数据复制到2,2的复制到3,最后的9寄存器内容将会被删除。

1行以内的数据删除修改操作的数据不会复制到逐级临时缓存寄存器1-9,而是复制到另一个Small Delete Register: "-
  1. 黑洞寄存器

引用方式:"_
几乎所有的操作涉及的数据都会被复制到寄存器,如果想让操作的数据不经过寄存器,可以指定黑洞寄存器,数据到该寄存器就会消失掉,不能显示,也不存在。

  1. 系统剪切板

引用方式:"+ 或"*
于VIM外部的GUI交互数据时,需要使用专用的系统剪切板。
在Unix环境下,”+寄存器需要+xterm-clipboard feature的VIM软件才能使用,具有这个feature的VIM可以安装vim-gtk(包含gvim和vim),使用gvim可以正常调用”+寄存器。

“+和”*的區別:

    Under Windows, the * and + registers are equivalent.
    For X11 systems, though, they differ. For X11 systems, * is the selection, and + is the cut buffer (like clipboard).
        Text selected, or otherwise highlighted in one X11 app is available in the selection buffer.
        Text explicitly copied or cut is available in the cut buffer.

Ref:

  1. Accessing the system clipboard
  2. Getting Vim with +clipboard support

5.1 剪切板与自动缩进indent

如果开启了set autoindent,在粘贴具有格式缩进的文本时(如python程序),粘贴的结果将会是缩进混乱的,因为set autoindent的影响。
解决这个问题有两个方法:

  1. 使用 set paste 模式
    开启paste模式后,autoindent等缩进功能将会被屏蔽,粘贴格式就会不受影响。
    每次手工开启关闭paste模式将会比较麻烦,可以在_vimrc中为其设置一个快捷键,每次需要时按一下即可切换:set pastetoggle=

  2. 使用普通模式的 "+p 命令

  3. 插入模式输入 <C-r><C-p>"+

  4. 表达式寄存器

引用方式:”=
所有寄存器里最特殊的一个,用于计算表达式。
输入完该寄存器应用后,会在命令行里提示“=”,按需输入表达式,结果将会显示到光标处。
7. 其他寄存器

“% 当前文件名,包含文件路径。
“/ 上次查找的内容。
“. 上次插入的内容。

HEXO

创建新博客

new指令

1
hexo new post -p 后端/test.md 

执行后,会在 _posts文件夹下创建子文件夹 “后端”,并创建一篇test.md博文。

创建关联文件夹

_config.yml 配置文件

1
post_asset_folder: true

网页生成

1
2
3
hexo generate --> hexo g

hexo g -d #生成并部署

网页预览

1
hexo server --> hexo s  #启动服务预览

网页部署

1
hexo deploy --> hexo d #部署

YUV简介

YUV是一种颜色编码方法,它和我们熟知的RGB红绿蓝颜色体系相对应,它们之间能通过公式相互转换。YUV将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的。

YUV将亮度Y和色差UV三个信号分别进行编码,用同一信道发送出去。YUV不像RGB那样要求三个独立的视频信号同时传输,所以用YUV方式传送占用极少的频宽。

YUV 三个字母的意义分别为:

  • Y:亮度,就是灰度值。除了表示亮度信号外,还含有较多的绿色通道量。单纯的 Y 分量可以显示出完整的黑白图像。
  • U:蓝色通道与亮度的差值。
  • V:红色通道与亮度的差值。

其中,U、V 分量分别表示蓝 (blue)、红 (red) 分量信号,只含有色度信息,所以 YUV 也称为 YCbCr,其中,Cb、Cr的含义等同于U、V,C 可以理解为 component 或者 color。

第一幅是Y分量描述黑白图像,第二幅是U(V)分量描述,第三幅是V(U)分量描述,第四幅是YUV三幅合成后得到的正常图像

人眼对亮度的敏感超过色度,即使把色度信息减少一点,人眼也无法查觉这一点。如果一张图片使用YUV格式保存将更少地占用存储空间。

以采集视频为例,RGB24格式一帧的大小size=width×heigth×3 Bit,RGB32的size=width×heigth×4,如果是I420(即YUV标准格式4:2:0)的数据量是 size=width×heigth×1.5 Bit

YUV详解

YUV的存储格式

YUV的存储格式有两大类:planar和packed。

  • 对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。

  • 对于packed的YUV格式,每个像素点的Y,U,V是连续交替存储的。

YUV的采样方式

YUV采样方式,主要描述像素Y、U、V分量采样比例,即表达每个像素时,Y、U、V分量的数目,通常有三种方式:YUV4:4:4,YUV4:2:2,YUV4:2:0。

  • YUV4:4:4采样,每一个Y对应一组UV分量。

  • YUV4:2:2采样,每两个Y共用一组UV分量。

  • YUV4:2:0采样,每四个Y共用一组UV分量。

用图直观地表示采集的方式,以黑点表示采样该像点的Y分量,以空心圆圈表示采用该像素点的UV分量

  • 使用YUV4:4:4采样,一共要进行12次采样分别4个Y,4个U,4个V,对每一个Y,U,V每个需要8个比特位,就需要12*8=96位,平均下每个像素点需要96/4=24位比特位表示。

  • 使用YUV4:2:2采样,就需要8*8 =64位,平均每个像素64/4=16位。

  • 使用YUV4:2:0采样,就需要6*8 =48位,平均每个像素48/4=12位。

常见的YUV码流的存储方式

Cb、Cr的含义等同于U、V

YUVY 采用422采样格式,packed存储格式

YUVY 采用422采样格式,Planar存储格式

YUV420

YUV420P 和 YUV420SP

  • YUV420p:又叫planer平面模式,Y ,U,V分别再不同平面,也就是有三个平面。
  • YUV420sp:又叫bi-planer或two-planer双平面,Y一个平面,UV在同一个平面交叉存储。

YUV420P –> YUV420SP

NV12 和 NV21

  • NV12:IOS只有这一种模式。存储顺序是先存Y,再UV交替存储。YYYYUVUVUV
  • NV21:安卓的模式。存储顺序是先存Y,再存U,再VU交替存储。YYYYVUVUVU

NV12: UV交替

NV21: VU交替

YUV420的内存计算

1
2
3
4
5
Y = width * hight 

U = Y / 4 V = Y / 4

U + V = Y/2

YUV420中

  • V的步长(也就是宽)是Y的步长的一半,V的行高也是Y的一半。
  • U的步长和行高与V相同,也就是都是Y的一半。
  • U 和 V 的内存占用为都Y的 1/4, U + V 的内存占用为 Y 的 1/2

所以YUV420 数据在内存中的长度是 width * hight * 3 / 2 = width * hight * 1.5

以720×488大小图象YUV420 planar为例,

其存储格式是: 共大小为720 × 480× 3 × 1.5字节,

分为三个部分:Y,U和V

  • Y分量: (720×480)个字节

  • U(Cb)分量:(720×480 × 1/4)个字节

  • V(Cr)分量:(720×480 × 1/4)个字节

三个部分内部均是行优先存储,三个部分之间是Y,U,V 顺序存储。

即YUV数据

  • 0--720×480字节是Y分量值,

  • 720×480--720×480×5/4字节是U分量

  • 720×480×5/4 --720×480×3/2字节是V分量。

YUV422

每两个Y共用一组UV分量。U/V的步长(也就是宽)是Y的步长的一半,但高与 Y 相同

1
2
3
4
5
Y = width * hight 

U = Y / 2 V = Y / 2

Y = U + V

NV16 和 NV61

  • NV16: UV 交替

  • NV61: VU 交替

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
NV16:
w
+--------------------+
|Y0Y1Y2Y3... |
|... | h
|... |
| |
+--------------------+ UV 交替为NV16,VU 交替为NV61
|U0V0U1V1 |
|... | h
|... |
| |
+--------------------+


YUV420与YUV422

UV分量的长都是 Y的一般,仅有宽不同, 420 UV的宽是Y的 1/2, 422 UV的宽与 Y 相同

YUV400

灰度数据,没有色度数据, 即仅有 Y 分量

YUV常用格式附录

格式 Mode 通道 比特 示例
GRAY Planar 1 8 400. Y0Y1…Y15
I420 Planar 3 12 420. Y0Y1..Y15 U0U1U2U3 V0V1V2V3 * 常用 理解为YU12
IYUV Planar 3 12 同I420
YUV420P Planar 3 12 同I420 * 感觉 YUV420P 名字更常用
YUVJ420P Planar 3 12 同I420,不同的是色彩转换公式,YUVJ使用 JPEG 公式, 输出数据范围[0..255], I420的范围是 [16-240]
YV12 Planar 3 12 420. Y0Y1..Y15 V0V1V2V3 U0U1U2U3 * 常用 很多编解码器都用这个格式输入输出
YVU420P Planar 3 12 同YV12
NV12 Planar 2 12 420. Y0Y1..Y15 U0V0U1V1…..U3V3 *常用
NV21 Planar 2 12 420. Y0Y1..Y15 V0U0V1U1…..V3U3
YV16 Planar 3 16 422. Y0Y1..Y15 V0V1..V7 U0U1..U7
YUV422P Planar 3 16 同YV16 * 感觉 YUV422P 名字更常用
I422 Planar 3 16 同YV16
UYVY Packed 1 16 422. U0Y0V0Y1
Y422 Packed 1 16 同UYVY
YUY2 Packed 1 16 422. Y0U0Y1V0
YUV422 Packed 1 16 同YUY2
YUYV Packed 1 16 同YUY2
YVYU Packed 1 16 422. Y0V0Y1U0
YU16 Planar 3 16 422. Y0Y1..Y15 U0U1..U7 V0V1..V7
NV16 Planar 2 16 422. Y0Y1..Y15 U0V0U1V1..U7V7
YV24 Planar 3 24 444. Y0Y1..Y15 V0V1..V15 U0U1..U15
I444 Planar 3 24 同YV24
IYU2 Packed 1 24 444. U0Y0V0

使用Gtags辅助查看kernel源码

使用make gtags在kernel根目录下生成索引文件。

1
gtags       - Generate GNU GLOBAL index

kernel已对该命令进行封装,不必手动生成索引文件。在生成索引文件时还可以指定架构,这可以有效减少干扰项。

1
2
make gtags ARCH=arm
make gtags ARCH=riscv

kernel根目录下会生成三个新文件

1
2
$ ls G*
GPATH GRTAGS GTAGS

gtags.vim

General form of Gtags command is as follows:

1
:Gtags [option] pattern

To go to ‘func’, you can say

1
:Gtags func

Input completion is available. If you forgot the name of a function but recall only some characters of the head, please input them and press key.

1
2
:Gtags fu<TAB>
:Gtags func <- Vim will append 'nc'.

To go to the referenced point of ‘func’, add -r option.

1
:Gtags -r func

To go to any symbols which are not defined in GTAGS, try this.

1
:Gtags -s func

To go to any string other than symbol, try this.

1
:Gtags -g ^[sg]et_

This command accomplishes the same function as grep(1) but is more convenient because it retrieves an entire directory structure.

To get list of objects in a file ‘main.c’, use -f command.

1
:Gtags -f main.c

If you are editing main.c itself, you can use ‘%’ instead.

1
:Gtags -f %

You can get a list of files whose path include specified pattern.
For example:

1
2
3
   :Gtags -P /vm/			<- all files under 'vm' directory.
:Gtags -P \.h$ <- all include files.
:Gtags -P init <- all paths includes 'init'

If you omitted an argument and input only key to the prompt, vim shows list of all files in the project.

Since all short options are sent to global(1) as is, you can use the -i, -o, -O, and so on.

For example, if you want to ignore case distinctions in pattern.

1
:Gtags -gi paTtern

It will match to both of ‘PATTERN’ and ‘pattern’.

If you want to search a pattern which starts with a hyphen like ‘-C’
then you can use the -e option like grep(1).

1
:Gtags -ge -C

By default, Gtags command search only in source files. If you want to
search in both source files and text files, or only in text files then

1
2
:Gtags -go pattern		# both source and text
:Gtags -gO pattern # only text file

gtags-cscope

1
2
3
4
5
6
7
8
9
Find symbol		:cs find 0 or s
Find definition :cs find 1 or g
Find functions called by this function :cs find 2 or d
Find reference :cs find 3 or c
Find text string :cs find 4 or t
Find egrep pattern :cs find 6 or e
Find path :cs find 7 or f
Find include file :cs find 8 or i
Find assignments :cs find 9 or a

总结

一般情况下,Gtags已能满足需求。

NAME

1
tig - text-mode interface for Git

SYNOPSIS

1
2
3
4
5
6
7
8
9
10
tig        [options] [revisions] [--] [paths]
tig log [options] [revisions] [--] [paths]
tig show [options] [revisions] [--] [paths]
tig reflog [options] [revisions]
tig blame [options] [rev] [--] path
tig grep [options] [pattern]
tig refs [options]
tig stash
tig status
tig < [Git command output]

DESCRIPTION

1
2
3
Tig is an ncurses-based text-mode interface for git(1). It functions mainly as a Git
repository browser, but can also assist in staging changes for commit at chunk level and
act as a pager for output from various Git commands.

OPTIONS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Command line options recognized by Tig include all valid git-log(1) and git-diff(1)
options, as well as the following subcommands and Tig-specific options. The first command
line parameter not starting with "-" is interpreted as being either a revision
specification or a path and will end the option parsing. All additional options will be
passed to the underlying Git command.

show
Open diff view using the given git-show(1) options.

blame
Show given file annotated by commits. Takes zero or more git-blame(1) options.
Optionally limited from given revision.

status
Start up in status view.

log
Start up in log view, displaying git-log(1) output.

reflog
Start up in reflog view.

refs
Start up in refs view.

stash
Start up in stash view.

grep
Open the grep view. Supports the same options as git-grep(1).

+<number>
Show the first view with line <number> visible and selected.

-v, --version
Show version and exit.

-h, --help
Show help message and exit.

-C<path>
Run as if Tig was started in <path> instead of the current working directory.

PAGER MODE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Tig enters pager mode when input is provided via stdin and supports the following
subcommands and options:

· When the show subcommand is specified and the --stdin option is given, stdin is
assumed to be a list of commit IDs and will be forwarded to the diff view’s underlying
git-show(1) command. For example:

$ git rev-list --author=vivien HEAD | tig show --stdin

· When --stdin is given, stdin is assumed to be a list of commit IDs and will be
forwarded to the main view’s underlying git-log(1) command. For example:

$ tig --no-walk --stdin < cherry-picks.txt

· When --pretty=raw is given, stdin is assumed to be a "pretty=raw" formatted output
similar to that of git-log(1). For example:

$ git reflog --pretty=raw | tig --pretty=raw

When no subcommands nor options are given, the pager view will be used for displaying the
Git command input given on stdin. The pager view assumes the input is either from
git-log(1) or git-diff(1) and will highlight it similar to the log and diff views. For
example:

$ git log -Schange -p --raw | tig

EXAMPLES

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
Display the list of commits for the current branch:

$ tig

Display commits from one or more branches:

$ tig test master

Pretend as if all the refs in refs/ are listed on the command line:

$ tig --all

Display differences between two branches:

$ tig test..master

Display changes for sub-module versions:

$ tig --submodule

Display changes for a single file:

$ tig -- README

Display contents of the README file in a specific revision:

$ tig show tig-0.8:README

Display revisions between two dates for a specific file:

$ tig --after="2004-01-01" --before="2006-05-16" -- README

Blame file with copy detection enabled:

$ tig blame -C README

Display the list of stashes:

$ tig stash

Grep all files for lines containing DEFINE_ENUM:

$ tig grep -p DEFINE_ENUM

Show references (branches, remotes and tags):

$ tig refs

Use word diff in the diff view:

$ tig --word-diff=plain

ENVIRONMENT VARIABLES

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
In addition to environment variables used by Git (e.g. GIT_DIR), Tig defines the ones
below. The command related environment variables have access to the internal state of Tig
via replacement variables, such as %(commit) and %(blob). See tigrc(5) for a full list.

TIGRC_USER
Path of the user configuration file (defaults to ~/.tigrc or
$XDG_CONFIG_HOME/tig/config).

TIGRC_SYSTEM
Path of the system wide configuration file (defaults to {sysconfdir}/tigrc). Define to
empty string to use built-in configuration.

TIG_LS_REMOTE
Command for retrieving all repository references. The command should output data in
the same format as git-ls-remote(1).

TIG_DIFF_OPTS
The diff options to use in the diff view. The diff view uses git-show(1) for
formatting and always passes --patch-with-stat. You may also set the diff-options
setting in the configuration file.

TIG_TRACE
Path for trace file where information about Git commands are logged.

TIG_SCRIPT
Path to script that should be executed automatically on startup. If this environment
variable is defined to the empty string, the script is read from stdin. The script is
interpreted line-by-line and can contain prompt commands and key mappings.

TIG_NO_DISPLAY
Open Tig without rendering anything to the terminal. This force Ncurses to write to
/dev/null. The main use is for automated testing of Tig.

FILES

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$XDG_CONFIG_HOME/tig/config, ~/.config/tig/config, ~/.tigrc
The Tig user configuration file is loaded in the following way. If $XDG_CONFIG_HOME is
set, read user configuration from $XDG_CONFIG_HOME/tig/config. If $XDG_CONFIG_HOME is
empty or undefined, read user configuration from ~/.config/tig/config if it exists and
fall back to ~/.tigrc if it does not exist. See tigrc(5) for examples.

/etc/tigrc
System wide configuration file.

$GIT_DIR/config, ~/.gitconfig, /etc/gitconfig
Git configuration files. Read on start-up with the help of git-config(1).

$XDG_DATA_HOME/tig/history, ~/.local/share/tig/history, ~/.tig_history
When compiled with readline support, Tig writes a persistent command and search
history. The location of the history file is determined in the following way. If
$XDG_DATA_HOME is set and $XDG_DATA_HOME/tig/ exists, store history to
$XDG_DATA_HOME/tig/history. If $XDG_DATA_HOME is empty or undefined, store history to
~/.local/share/tig/history if the directory ~/.local/share/tig/ exists, and fall back
to ~/.tig_history if it does not exist.

BUGS

1
2
Please visit Tig’s home page[1] or main Git repository[2] for information about new
releases and how to report bugs or feature request.

COPYRIGHT

1
2
3
4
5
Copyright (c) 2006-2014 Jonas Fonseca <jonas.fonseca@gmail.com[3]>

This program is free software; you can redistribute it and/or modify it under the terms of
the GNU General Public License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

How to use Tig to browse Git logs

Tig is more than just a text-mode interface for Git. Here’s how it can enhance your daily workflow.

If you work with Git as your version control system, you’ve likely already resigned yourself to the fact that Git is a complicated beast. It is a fantastic tool, but it can be cumbersome to navigate Git repositories. That’s where a tool like Tig comes in.

From the Tig man page:

Tig is an ncurses-based text-mode interface for git. It functions mainly as a Git repository browser, but can also assist in staging changes for commit at chunk level and act as a pager for output from various Git commands.

This basically means that Tig provides a text-based user interface you can run in your terminal. Tig makes it easy to browse your Git logs, but it can do much more than just bounce you around from your last commit to a previous one.

Many of the examples in this quick introduction to Tig have been poached directly from its excellent man page. I highly recommend reading it to learn more.

Install Tig

  • Fedora and RHEL: sudo dnf install tig
  • Ubuntu and Debian: sudo apt install tig
  • MacOS: brew install tig

See the official installation instructions for even more options.

Browse commits in your current branch

If you want to browse the latest commits in your branch, enter:

1
tig

That’s it. This three-character command will launch a browser where you can navigate the commits in your current branch. You can think of it as a wrapper around git log.

To navigate the output, you can use the Up and Down arrow keys to move from one commit to another. Pressing the Return/Enter key will open a vertical split with the contents of the chosen commit on the right-hand side. You can continue to browse up and down in your commit history on the left-hand side, and your changes will appear on the right. Use k and j to navigate up and down by line and - and the Space Bar to page up and down on the right-hand side. Use q to exit the right-hand pane.

Searching on tig output is simple as well. Use / to search forward and ? to search backward on both the left and right panes.

That’s enough to get you started navigating your commits. There are too many key bindings to cover here, but clicking h will display a Help menu where you can discover its navigation and command options. You can also use / and ? to search the Help menu. Use q to exit Help.

Browse revisions for a single file

Since Tig is a wrapper around git log, it conveniently accepts the same arguments that can be passed to git log. For instance, to browse the commit history for a single file, enter:

1
tig README.md

Compare this with the output of the Git command being wrapped to get a clearer view of how Tig enhances the output.

1
git log README.md

To include the patches in the raw Git output, you can add a -p option:

1
git log -p README.md

If you want to narrow the commits down to a specific date range, try something like this:

1
tig --after="2017-01-01" --before="2018-05-16" -- README.md

Again, you can compare this with the raw Git version:

1
git log --after="2017-01-01" --before="2018-05-16" -- README.md

Browse who changed a file

Sometimes you want to find out who made a change to a file and why. The command:

1
tig blame README.md

is essentially a wrapper around git blame. As you would expect, it allows you to see who the last person was to edit a given line, and it also allows you to navigate to the commit that introduced the line. This is somewhat like the :Gblame command Vim’s vim-fugitive plugin provides.

Browse your stash

If you’re like me, you may have a pile of edits in your stash. It’s easy to lose track of them. You can view the latest item in your stash via:

1
git stash show -p stash@{0}

You can find the second most recent item via:

1
git stash show -p stash@{1}

and so on. If you can recall these commands whenever you need them, you have a much sharper memory than I do.

As with the Git commands above, Tig makes it easy to enhance your Git output with a simple invocation:

1
tig stash

Try issuing this command in a repository with a populated stash. You’ll be able to browse and search your stash items, giving you a quick overview of everything you saved for a rainy day.

Browse your refs

A Git ref is the hash of something you have committed. This includes files as well as branches. Using the tig refs command allows you to browse all of your refs and drill down to specific commits.

1
tig refs

When you’re finished, use q to return to a previous menu.

Browse git status

If you want to view which files have been staged and which are untracked, use tig status, a wrapper around git status.

Browse git grep

You can use the grep command to search for expressions in text files. The command tig grep allows you to navigate the output of git grep. For example:

1
tig grep -i foo lib/Bar

will navigate the output of a case-insensitive search for foo in the lib/Bar directory.

Pipe output to Tig via STDIN

If you are piping a list of commit IDs to Tig, you must use the --stdin flag so that tig show reads from stdin. Otherwise, tig show launches without input (rendering an empty screen).

1
git rev-list --author=olaf HEAD | tig show --stdin

Add custom bindings

You can customize Tig with an rc file. Here’s how you can configure Tig to your liking, using the example of adding some helpful custom key bindings.

Create a file in your home directory called .tigrc. Open ~/.tigrc in your favorite editor and add:

1
2
3
4
5
# Apply the selected stash
bind stash a !?git stash apply %(stash)

# Drop the selected stash item
bind stash x !?git stash drop %(stash)

Run tig stash to browse your stash, as above. However, with these bindings in place, you can press a to apply an item from the stash to your repository and x to drop an item from the stash. Keep in mind that you’ll need to perform these commands when browsing the stash list. If you’re browsing a stash item, enter q to exit that view and press a or x to get the effect you want.

For more information, you can read more about Tig key bindings.

Wrapping up
I hope this has been a helpful demonstration of how Tig can enhance your daily workflow. Tig can do even more powerful things (such as staging lines of code), but that’s outside the scope of this introductory article. There’s enough information here to make you dangerous, but there’s still more to explore.

via: https://opensource.com/article/19/6/what-tig