在读者学习本章以及后续LCD相关章节之前,最好拥有LCD裸机基础,可以参考:LCD编程

在内核中,表示LCD使用的是framebuffer(帧缓冲,简写为fb),其内容对应于屏幕上的界面显示。修改framebuffer中的内容,即修改屏幕上的内容。操作framebuffer可以直接在LCD上观察到效果。

framebuffer本质上是一段内存,或称作显存。

在内核中,LCD对应的参数使用struct fb_info存储,对应的行为使用struct fb_ops存储。

在以下章节,我会分别讨论fb_info和fb_ops。

一、fb_info

之前说过fb_info定义的是属性,其结构体定义如下:

struct fb_info {
...
struct fb_var_screeninfo var; /* LCD可变参数,如屏幕一行像素点个数xres,一列像素点个数yres,每像素点所占位数等 */
struct fb_fix_screeninfo fix; /* LCD固定参数,记录用户不能修改的显示控制器的参数,如屏幕缓存区物理地址smem_start,id,type等 */ ... struct backlight_device *bl_dev; /* 背光设备 */ ... struct fb_ops *fbops; /* LCD操作函数 */
struct device *device; /* This is the parent */
struct device *dev; /* This is this fb device */ ... char __iomem *screen_base; /* 显存虚拟地址 */
unsigned long screen_size; /* 屏幕大小*每个像素的字节数 */
void *pseudo_palette; /* Fake palette of 16 colors */ ...
};

其中,我们需要关注的有var、fix、screen_base和pseudo_palette

var结构体定义如下:

struct fb_var_screeninfo {
__u32 xres; /* LCD物理分辨率 */
__u32 yres;
__u32 xres_virtual; /* LCD虚拟分辨率 */
__u32 yres_virtual;
__u32 xoffset; /* 虚拟和物理分辨率的偏移值 */
__u32 yoffset; __u32 bits_per_pixel; /* 每一个像素占多少bit */
__u32 grayscale; /* 灰度值,0 = color,1 = grayscale, */
/* >1 = FOURCC */
struct fb_bitfield red; /* bitfield in fb mem if true color, */
struct fb_bitfield green; /* else only length is significant */
struct fb_bitfield blue; ... __u32 activate; /* see FB_ACTIVATE_* */ ... /* Timing指的是LCD上下的黑框的宽度等参数,一般不用设置 */
__u32 pixclock; /* pixel clock in ps (pico seconds) */
__u32 left_margin; /* time from sync to picture */
__u32 right_margin; /* time from picture to sync */
__u32 upper_margin; /* time from sync to picture */
__u32 lower_margin;
__u32 hsync_len; /* length of horizontal sync */
__u32 vsync_len; /* length of vertical sync */
__u32 sync; /* see FB_SYNC_* */
__u32 vmode; /* see FB_VMODE_* */
__u32 rotate; /* angle we rotate counter clockwise */
__u32 colorspace; /* colorspace for FOURCC-based modes */
__u32 reserved[]; /* Reserved for future compatibility */
};

其中需要我们了解的有:

1. bits_per_pixel是LCD逻辑中的BPP,一般有24BPP、16BPP和8BPP。BPP的数值越大,显存所需空间越大,给处理器带来的负担也就越重;BPP的数值在8位以下时,所能表达的颜色又太少,不能够满足用户特定的需求。为解决这个问题,就需要采取调色板,也就是pseudo_palette。

2. fb_bitfield结构体用于设置红色、绿色和蓝色在BPP中的位置和长度。比如16BPP,格式为565,则格式示例代码如下:

    fbinfo->var.red.offset        = ;
fbinfo->var.red.length = ;
// fbinfo->var.red.msb_right = ; /* 1: 右边为高位 */
fbinfo->var.green.offset = ;
fbinfo->var.green.length = ;
// fbinfo->var.green.msb_right = ;
fbinfo->var.blue.offset = ;
fbinfo->var.blue.length = ;
// fbinfo->var.blue.msb_right = ;

3. FB_ACTIVATE宏定义如下:

#define FB_ACTIVATE_NOW        0    /* 立即设置值,一般选用此选项 */
#define FB_ACTIVATE_NXTOPEN 1 /* 下次打开时激活 */
#define FB_ACTIVATE_TEST 2 /* 不设置 */
#define FB_ACTIVATE_MASK 15
/* values */
#define FB_ACTIVATE_VBL 16 /* 在下一次设置值时激活 */
#define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */
#define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */
#define FB_ACTIVATE_FORCE 128 /* force apply even when no change*/
#define FB_ACTIVATE_INV_MODE 256 /* invalidate videomode */

fix结构体定义如下:

struct fb_fix_screeninfo {
char id[]; /* 屏幕名字,自行设置 */
unsigned long smem_start; /* 屏幕缓存区物理地址 */
__u32 smem_len; /* 屏幕缓存区长度 */
__u32 type; /* see FB_TYPE_* */
__u32 type_aux; /* 辅助类型,一般设置为0 */
__u32 visual; /* see FB_VISUAL_* */
__u16 xpanstep; /* zero if no hardware panning */
__u16 ypanstep; /* zero if no hardware panning */
__u16 ywrapstep; /* zero if no hardware ywrap */
__u32 line_length; /* 一行的字节数 */
unsigned long mmio_start; /* 寄存器的起始物理地址,一般不需要设置 */
__u32 mmio_len; /* 寄存器的长度,一般不需要设置 */
__u32 accel; /* Indicate to driver which */
/* specific chip/card we have */
__u16 reserved[]; /* Reserved for future compatibility */
};

其中,FB_TYPE宏定义如下:

#define FB_TYPE_PACKED_PIXELS        0    /* 像素填充,一般选用此选项    */
#define FB_TYPE_PLANES 1 /* 非交错planes */
#define FB_TYPE_INTERLEAVED_PLANES 2 /* 交错planes */
#define FB_TYPE_TEXT 3 /*文本/属性 */
#define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */

FB_VISUAL宏定义如下:

#define FB_VISUAL_MONO01        0    /* 二值图像,只有黑白 1=Black 0=White */
#define FB_VISUAL_MONO10 1 /* 二值图像,只有黑白 1=White 0=Black */
#define FB_VISUAL_TRUECOLOR 2 /* 真彩色,一般选用此选项 */
#define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */
#define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */
#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */

pseudo_palette,又称调色板,它可以在低位BPP的条件下,在有限的像素值与RGB颜色之间建立拥有对应关系的线性表。比如从所有的16BPP的颜色中抽取一定数量的颜色编制索引。当需要使用某种彩色时,不需要对这种颜色的RGB分量进行描述,只需要引用它的索引号,就可以选取自己需要的颜色。索引号的长度远远小于RGB分量的编码长度,因此在彩色显示的同时,也减轻了系统的负担。

若需要调色板,我们需要在LCD操作函数中添加如下代码:

 /* 代码来源于drivers/video/samsung/s3cfb_ops.c */

 inline unsigned int __chan_to_field(unsigned int chan, struct fb_bitfield bf)
{
chan &= 0xffff;
chan >>= - bf.length; return chan << bf.offset;
} int s3cfb_setcolreg(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
unsigned int transp, struct fb_info *fb)
{
unsigned int *pal = (unsigned int *)fb->pseudo_palette;
unsigned int val = ; if (regno < ) {
/* fake palette of 16 colors */
val |= __chan_to_field(red, fb->var.red);
val |= __chan_to_field(green, fb->var.green);
val |= __chan_to_field(blue, fb->var.blue);
val |= __chan_to_field(transp, fb->var.transp);
pal[regno] = val;
} return ;
}

二、fb_ops

之前说过fb_ops定义的是行为,其结构体定义如下:

struct fb_ops {
/* open/release and usage marking */
struct module *owner;
int (*fb_open)(struct fb_info *info, int user);
int (*fb_release)(struct fb_info *info, int user); /* For framebuffers with strange non linear layouts or that do not
* work with normal memory mapped access
*/
ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
size_t count, loff_t *ppos);
ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
size_t count, loff_t *ppos); /* checks var and eventually tweaks it to something supported,
* DO NOT MODIFY PAR */
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info); /* set the video mode according to info->var */
int (*fb_set_par)(struct fb_info *info); /* set color register */
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info); /* set color registers in batch */
int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info); /* blank display */
int (*fb_blank)(int blank, struct fb_info *info); /* pan display */
int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info); /* Draws a rectangle */
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
/* Copy data from area to another */
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
/* Draws a image to the display */
void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image); /* Draws cursor */
int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor); /* Rotates the display */
void (*fb_rotate)(struct fb_info *info, int angle); /* wait for blit idle, optional */
int (*fb_sync)(struct fb_info *info); /* perform fb specific ioctl (optional) */
int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
unsigned long arg); /* Handle 32bit compat ioctl (optional) */
int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
unsigned long arg); /* perform fb specific mmap */
int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma); /* get capability given var */
void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
struct fb_var_screeninfo *var); /* teardown any resources to do with this framebuffer */
void (*fb_destroy)(struct fb_info *info); /* called at KDB enter and leave time to prepare the console */
int (*fb_debug_enter)(struct fb_info *info);
int (*fb_debug_leave)(struct fb_info *info);
};

此结构体中函数我们只需要根据实际情况编写部分函数即可。比如之前的调色板代码应该设置为fb_setcolreg函数指针:.fb_setcolreg = s3cfb_setcolreg,

三、framebuffer驱动调用流程

在应用程序使用LCD之前,内核主要需要做以下工作:

1. 初始化framebuffer框架,这个在drivers/video/fbmem.c中实现

2. 注册LCD设备,也就是注册fb_info

接下来应用程序需要操作LCD,会调用内核函数:

3. 应用程序open(),调用fb_open()

4. 应用程序write()、mmap()等,调用fb_write()、fb_mmap()等

5. 应用程序close(),调用fb_release()

1. 初始化framebuffer框架

 static int __init
fbmem_init(void)
{
/* 1. 在proc文件系统中创建fb相关操作接口 */
proc_create("fb", , NULL, &fb_proc_fops); /* 2. 注册fb字符驱动 */
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR); /* 3. 创建graphics类 */
fb_class = class_create(THIS_MODULE, "graphics");
if (IS_ERR(fb_class)) {
printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
fb_class = NULL;
}
return ;
}

由代码可知,fb的主设备号是代码中定好的,区分各个LCD设备依靠的是次设备号。

在框架搭建完成之后,我们就需要注册自己写的驱动中的fb_info结构体

2. 注册fb_info结构体

 int
register_framebuffer(struct fb_info *fb_info)
{
int ret; mutex_lock(&registration_lock);
ret = do_register_framebuffer(fb_info);
mutex_unlock(&registration_lock); return ret;
}
 static int do_register_framebuffer(struct fb_info *fb_info)
{
...
/* 1. 判断要注册设备的显存和已有设备的显存是否冲突 */
do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
fb_is_primary_device(fb_info)); /* 2. FB_MAX = 32,最多支持32个LCD设备 */
if (num_registered_fb == FB_MAX)
return -ENXIO; ... /* 3. 创建设备fb0/1/2... */
fb_info->dev = device_create(fb_class, fb_info->device,
MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
... /* 4. 若驱动没有实现fb_info中pixmap,内核使用默认参数 */
if (fb_info->pixmap.addr == NULL) {
fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
if (fb_info->pixmap.addr) {
fb_info->pixmap.size = FBPIXMAPSIZE;
fb_info->pixmap.buf_align = ;
fb_info->pixmap.scan_align = ;
fb_info->pixmap.access_align = ;
fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
}
}
fb_info->pixmap.offset = ; ... /* 5. 使用fbinfo中参数初始化mode */
fb_var_to_videomode(&mode, &fb_info->var);
fb_add_videomode(&mode, &fb_info->modelist);
registered_fb[i] = fb_info; event.info = fb_info;
if (!lock_fb_info(fb_info))
return -ENODEV;
/* 6. 通知fb注册成功 */
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
unlock_fb_info(fb_info);
return ;
}

3. 应用程序open(),调用fb_open()函数

在初始化framebuffer框架的fbmem_init()函数中register_chrdev(FB_MAJOR,"fb",&fb_fops)的fb_fops定义了fb_open()函数。

 static int fb_open(struct inode *inode, struct file *file)
__acquires(&info->lock)
__releases(&info->lock)
{
/* 1. 根据次设备号获取fb_info */
int fbidx = iminor(inode);
struct fb_info *info;
int res = ; info = get_fb_info(fbidx); ... mutex_lock(&info->lock);
if (!try_module_get(info->fbops->owner)) {
res = -ENODEV;
goto out;
}
file->private_data = info; /* 2. 若驱动程序中定义了fb_open(),则优先调用 */
if (info->fbops->fb_open) {
res = info->fbops->fb_open(info,);
if (res)
module_put(info->fbops->owner);
}
#ifdef CONFIG_FB_DEFERRED_IO
if (info->fbdefio)
fb_deferred_io_open(info, inode, file);
#endif
out:
mutex_unlock(&info->lock);
if (res)
put_fb_info(info);
return res;
}

fb_open()函数所做的有私有化数据和调用驱动程序中fb_ops的fb_open()函数。

4. 应用程序write(),调用fb_write()函数

看过LED和KEY驱动程序的读者可以发现write()和read()函数实现差别不大,在此以fb中常用的write()函数为例分析。

 static ssize_t fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
unsigned long p = *ppos; /* 偏移量 */
struct fb_info *info = file_fb_info(file);
u8 *buffer, *src;
u8 __iomem *dst;
int c, cnt = , err = ;
unsigned long total_size; ... /* 若驱动程序中定义了fb_write(),则优先调用 */
if (info->fbops->fb_write)
return info->fbops->fb_write(info, buf, count, ppos); total_size = info->screen_size; if (total_size == )
total_size = info->fix.smem_len; if (p > total_size)
return -EFBIG; if (count > total_size) {
err = -EFBIG;
count = total_size;
} if (count + p > total_size) {
if (!err)
err = -ENOSPC; count = total_size - p;
} buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
GFP_KERNEL);
if (!buffer)
return -ENOMEM; dst = (u8 __iomem *) (info->screen_base + p); /* 若驱动程序中定义了fb_sync(),则优先调用 */
if (info->fbops->fb_sync)
info->fbops->fb_sync(info); /* 使用copy_from_user()将数据从用户空间拷贝到内核空间 */
while (count) {
c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
src = buffer; if (copy_from_user(src, buf, c)) {
err = -EFAULT;
break;
} fb_memcpy_tofb(dst, src, c);
dst += c;
src += c;
*ppos += c;
buf += c;
cnt += c;
count -= c;
} kfree(buffer); return (cnt) ? cnt : err;
}

我们可以发现fb_write()函数默认提供的写操作同样使用了copy_from_user()拷贝数据。除此之外,它还使用fb_memcpy_tofb()函数把数据写到显存。也就是执行两次拷贝操作。

之前我们使用copy_from_user()拷贝数据是因为我们的数据量较小,一般只有几字节。但是fb显存一般为几百KB,copy_from_user()拷贝数据极有可能导致画面卡顿,导致效率降低。

解决此问题的方式就是使用mmap()函数。

应用程序mmap()函数使用方法可以参考:第七章:进程环境中六、存储空间的分配mmap()函数。

内核使用struct task_struct来表示某个进程,该结构体包含一些进程状态、调度信息等成员,并使用结构体链表来管理所有进程。我们需要关注进程描述符中内存描述符:struct mm_struct。

struct mm_struct中struct vm_area_struct用来表示一个独立的虚拟内存区域,该结构体包含映射地址、大小、结束地址等成员,并使用结构体链表来管理所有虚拟内存区域。

由此我们可以推出:mmap()把设备地址映射到进程虚拟地址(ioremap()把设备地址映射到内核虚拟空间)。指针指向如下图:

mmap()函数首先分配一个struct vm_area_struct放到进程的地址空间,之后实现文件地址和虚拟地址区域的映射关系。

此时映射关系有了,但内存中没有数据,进程访问内存会引发引发缺页异常,最终内核会发起请求调页过程,它先在交换缓存空间中寻找需要访问的内存页,如果没有则调用nopage()函数把所缺的页从磁盘装入到主存中。在这之后进程便可以正常访问数据。

这样做的好处是映射过程并没有拷贝数据,只需要从磁盘到用户主存的一次拷贝数据过程。而write()函数需要从磁盘到页缓存再到用户主存的两次拷贝数据过程。

分析完mmap()后,我们来查看fb_mmap()函数

 static int fb_mmap(struct file *file, struct vm_area_struct * vma)
{
struct fb_info *info = file_fb_info(file);
struct fb_ops *fb;
unsigned long off;
unsigned long start;
u32 len; if (!info)
return -ENODEV;
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
return -EINVAL;
off = vma->vm_pgoff << PAGE_SHIFT;
fb = info->fbops;
if (!fb)
return -ENODEV;
mutex_lock(&info->mm_lock);
if (fb->fb_mmap) {
int res;
res = fb->fb_mmap(info, vma); /* 若驱动程序中定义了fb_mmap(),则优先调用 */
mutex_unlock(&info->mm_lock);
return res;
} /* frame buffer memory */
start = info->fix.smem_start; /* 显存起始地址 */
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); /* 显存大小*/
if (off >= len) {
/* memory mapped io */
off -= len;
if (info->var.accel_flags) {
mutex_unlock(&info->mm_lock);
return -EINVAL;
}
start = info->fix.mmio_start;
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
}
mutex_unlock(&info->mm_lock);
start &= PAGE_MASK;
if ((vma->vm_end - vma->vm_start + off) > len)
return -EINVAL;
off += start;
vma->vm_pgoff = off >> PAGE_SHIFT;
/* This is an IO map - tell maydump to skip this VMA */
vma->vm_flags |= VM_IO | VM_RESERVED;
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
fb_pgprotect(file, vma, off); /* 映射页I/O,vma为用户分配的空间 */
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
return ;
}

接下来简单举例在应用程序中使用mmap()函数并把LCD显示器的背景刷成蓝色。此代码读者暂时不需要会修改,熟悉即可。我将在接下来的LCD章节中对平台驱动框架对代码中参数进行分析。

 #include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h> /* Usage:
* ./a.out <fb0|fb1|fb2|...>
*/
int main(int argc, char **argv)
{
if (argc != ) {
printf("Usage:\n");
printf("%s <fb0|fb1|fb2|...>\n", argv[]);
return -;
} char path[] = "/dev/";
strcat(path, argv[]); int fd = open(path, O_RDWR);
if (fd < )
perror("open"), exit(-); /* 1280*800*4
* 1280: xres,x方向分辨率
* 800:yres,y方向分辨率
* 4:我的内核中默认LCD为24BPP,查手册可以确定24BPP占32位,也就是4字节
*/
unsigned int *memory = (unsigned int *)mmap(NULL, **, PROT_READ | PROT_WRITE, MAP_SHARED, fd, );
if (memory == (unsigned int *)-) {
close(fd);
perror("mmap");
exit(-);
} close(fd); /* 把屏幕刷成蓝色 */
int i;
for (i = ; i < (*); ++i) {
memory[i] = 0x000000ff;
} /* 写回磁盘文件中 */
msync(memory, **, MS_SYNC); return ;
}

5. 应用程序close(),调用fb_release()

在此仅给出调用过程:

fb_release(struct inode *inode, struct file *file)
if (info->fbops->fb_release)
info->fbops->fb_release(info,);
-> put_fb_info(info);
if (fb_info->fbops->fb_destroy)
fb_info->fbops->fb_destroy(fb_info);

下一章  十一、三星平台framebuffer驱动

十、LCD的framebuffer设备驱动的更多相关文章

  1. 2016/1/9:深度剖析安卓Framebuffer设备驱动

    忙了几天,今天在公司居然没什么活干 ,所以早上就用公司的电脑写写之前在公司编写framebuffer的使用心得体会总结,这也算是一点开发经验,不过我还没写全,精华部分还是自己藏着吧.直到下午才开始有点 ...

  2. framebuffer设备驱动分析

    一.设备驱动相关文件 1.1. 驱动框架相关文件 1.1.1. drivers/video/fbmem.c a. 创建graphics类.注册FB的字符设备驱动 fbmem_init(void) { ...

  3. Linux设备驱动中的软件架构思想

    目录 更新记录 一.Linux驱动的软件架构 1.1 出发点 1.2 分离思想 1.3 分层思想 二.platform设备驱动 2.1 platform设备 2.2 platform驱动 2.3 pl ...

  4. Linux中LCD设备驱动-framebuffer(帧缓冲)【】

    转自:https://blog.csdn.net/linux_devices_driver/article/details/7079442 1.framebuffer 帧缓冲     帧缓冲(fram ...

  5. linux设备驱动归纳总结(十二):简单的数码相框【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-116926.html linux设备驱动归纳总结(十二):简单的数码相框 xxxxxxxxxxxxxx ...

  6. linux lcd设备驱动剖析四

    在"linux lcd设备驱动剖析二"文章中,我们详细分析了s3c24xxfb_probe函数. 文章链接:http://blog.csdn.net/lwj103862095/ar ...

  7. LCD驱动分析(一)字符设备驱动框架分析

    参考:S3C2440 LCD驱动(FrameBuffer)实例开发<一>   S3C2440 LCD驱动(FrameBuffer)实例开发<二> LCD驱动也是字符设备驱动,也 ...

  8. 【Linux开发】linux设备驱动归纳总结(十二):简单的数码相框

    linux设备驱动归纳总结(十二):简单的数码相框 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  9. linux设备驱动归纳总结(十):1.udev&misc【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-111839.html linux设备驱动归纳总结(十):1.udev&misc xxxxxxx ...

随机推荐

  1. ansible 主机正则

    ansible <pattern> -m <module_name> -a <arguments> 该功能主要针对Inventory的主机列表,案例如下: 1.AL ...

  2. [提权]Windows COM组件提权漏洞 (CVE-2017-0213)

    0x01 简介 COM组件是微软开发的一种新软件开发技术,在这个COM框架的下,可以开发出多功能的组件,可以根据自己的需求进行定制开发,替换旧的组件,多个功能组件组合到一起,从而形成了一个复杂的定制化 ...

  3. 【2018.08.01】(表/栈/队列/大小顶堆)学习Stark和Queue算法小记

    Train Problem I As the new term comes, the Ignatius Train Station is very busy nowadays. A lot of st ...

  4. LeetCode31 Next Permutation and LeetCode60 Permutation Sequence

    Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...

  5. Java 面向对象(十四)

    反射 反射是框架设计的灵魂 一.类的加载时机 当程序要使用某个类时,如果该类还未被加载到内存中,系统会通过加载,连接,初始化三步来实现对这个类进行初始化. 加载 :就是指将class文件读入内存,并为 ...

  6. macbook配置homebrew

    打开homebrew官网,https://brew.sh/将安装脚本复制到命令行中,执行即可 命令正在运行,下载应用,如果在安装应用时,下载速度很慢,可以参考https://blog.csdn.net ...

  7. sklearn中的弹性网函数 ElasticNet

    语法:  ElasticNet(self, alpha=1.0, l1_ratio=0.5, fit_intercept=True, normalize=False, precompute=False ...

  8. Shell中的$0、$1、$2的含义

    在 shell 中我们会见到 $0.$1.$2这样的符号,这是什么意思呢? 简单来说 $0 就是你写的shell脚本本身的名字,$1 是你给你写的shell脚本传的第一个参数,$2 是你给你写的she ...

  9. centos上安装Python并修复yum

    date: 2019-07-01  18:09:53 author: headsen chen notice: 个人原创 1,安装python3.7: yum install zlib-devel b ...

  10. linux下程序启动后后台运行实现

    关于linux下的程序运行很简单,将源码编译成二进制(假设为proram)文件后直接在命令行运行即可,root#./program如果需要后台运行,即不占用当前终端,这在嵌入式linux显得十分有必要 ...