热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

linux驱动移植LCD驱动分析

 一、LCD基础知识1.1LCD硬件原理在Mini2440裸机开发之LCD基础我们介绍了LCD的硬件原理,有兴趣的可以去看看,这里我们仅仅简述一下LCD的原理。下图是LCD示意图,

 一、LCD基础知识


1.1 LCD硬件原理

在Mini2440裸机开发之LCD基础我们介绍了LCD的硬件原理,有兴趣的可以去看看,这里我们仅仅简述一下LCD的原理。

下图是LCD示意图,里面的每个点就是一个像素点。它里面有一个电子枪,一边移动,一边发出各种颜色的光。用动态图表示如下:

电子枪是如何移动的?



  • 有一条CLK时钟线与LCD相连,每发出一次CLK(高低电平),电子枪就移动一个像素。

颜色如何确定?



  • 由连接LCD的三组线RGB三原色混合而成:R(Red)、G(Green)、B(Blue)确定。

电子枪如何得知应跳到下一行?



  • 有一条HSYNC信号线与LCD相连,每发出一次脉冲(高低电平),电子枪就跳到下一行,该信号叫做行同步信号。

电子枪如何得知应跳到原点?



  • 有一条VSYNC信号线与LCD相连,每发出一次脉冲(高低电平),电子枪就跳到原点,该信号叫做帧同步信号。

RGB线上的数据从何而来?



  • 内存里面划分一块显存(framebuffer),里面存放了要显示的数据,LCD控制器从里面将数据读出来,通过RGB三组线传给电子枪,电子枪再依次打到显示屏上。

前面的信号由谁发给LCD?



  • 有S3C2440里面的LCD控制器来控制发出信号。

工作原理:



  • LCD屏可以看作是由许多象素构成的,比如320*240就是由320*240个象素构成的,每个象素由RGB三色调和,每种颜色又由多个位组成。比如我们的开发板上的LCD,有320*240个象素,每个象素由RGB三色调和,RGB三色位数分别为:565。

  • S3C2440内集成了LCD控制器,LCD控制器外接LCD,每来一个VLCK,就会从左到右在LCD屏幕上显示一个象素的颜色,而这一个个象素的颜色就存放在显存里,在嵌入式领域,一般不会佩戴专门的显存,而是从内存SDRAM中划分出一部分充当显存;

  • HSYNC引脚每发出一个脉冲,表示一行的数据开始发送;

  • VSYNC引脚每发出一个冒充,表示一帧的数据开始发送。


1.2  frambuffer设备

我们在Mini2440裸机开发之LCD编程(GB2312、ASCII字库制作) 中介绍了如何在LCD显示屏中显示一张图片,其核心步骤就是向framebuffer中写入图片数据。

在linux中,如果我们的系统想使用GUI(图形界面接口),这时LCD设备驱动程序就应该编写成frambuffer接口,而不是像裸机中那样只编写操作底层的LCD控制器接口。

framebuffer是linux系统为显示设备提供的一个用户接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行操作,用户应用程序可以通过framebuffer透明地访问不同类型的显示设备。

linux抽象出framebuffer这个帧缓冲区可以供用户应用程序直接读写,通过更改framebuffer中的内容,就可以立刻显示在LCD显示屏上。

framebuffer是一个标准的字符设备,主设备号是29,次设备号根据缓冲区的数目而定。framebuffer对应/dev/fb%d设备文件。

对用户程序而言,framebuffer设备它和/dev下面的其它设备没有什么区别,用户可以把frameBuffer看成一块内存,既可以写,又可以读。显示器将根据内存数据显示对应的图像界面,这一切都由framebuffer设备驱动来完成。


二、framebuffer设备驱动框架图

framebuffer设备驱动在linux系统框架如下图:


三、基础数据结构


3.1 fb_info结构体

struct fb_info定义在include/linux/fb.h文件中,用于保存我们framebuffer设备信息,其内部提供了对framebuffer设备操作的函数指针:

 

struct fb_info {
atomic_t count;
int node;
int flags;
/*
* -1 by default, set to a FB_ROTATE_* value by the driver, if it knows
* a lcd is not mounted upright and fbcon should rotate to compensate.
*/
int fbcon_rotate_hint;
struct mutex lock; /* Lock for open/release/ioctl funcs */
struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
struct work_struct queue; /* Framebuffer event queue */
struct fb_pixmap pixmap; /* Image hardware mapper */
struct fb_pixmap sprite; /* Cursor hardware mapper */
struct fb_cmap cmap; /* Current cmap */
struct list_head modelist; /* mode list */
struct fb_videomode *mode; /* current mode */
#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
/* assigned backlight device */
/* set before framebuffer registration,
remove after unregister
*/
struct backlight_device *bl_dev;
/* Backlight level curve */
struct mutex bl_curve_mutex;
u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
#ifdef CONFIG_FB_DEFERRED_IO
struct delayed_work deferred_work;
struct fb_deferred_io *fbdefio;
#endif
struct fb_ops *fbops;
struct device *device; /* This is the parent */
struct device *dev; /* This is this fb device */
int class_flag; /* private sysfs flags */
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops; /* Tile Blitting */
#endif
union {
char __iomem *screen_base; /* Virtual address */
char *screen_buffer;
};
unsigned
long screen_size; /* Amount of ioremapped VRAM or 0 */
void *pseudo_palette; /* Fake palette of 16 colors */
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state;
/* Hardware state i.e suspend */
void *fbcon_par; /* fbcon use-only private area */
/* From here on everything is device dependent */
void *par;
/* we need the PCI or similar aperture base/size not
smem_start/size as smem_start may just be an object
allocated inside the aperture so may not actually overlap
*/
struct apertures_struct {
unsigned
int count;
struct aperture {
resource_size_t
base;
resource_size_t size;
} ranges[
0];
}
*apertures;
bool skip_vt_switch; /* no VT switch on suspend/resume required */
};

部分参数含义如下:



  • count:fb_info的引用计数,fb_open时使其+1,release时使其-1,为0时销毁;

  • node:全局变量registered_fb中的索引值,注册的时候分配,通过node可以索引fb_info;

  • flags:一些标志位,有关于硬件加速的,大小端,fb的内存位置(设备或者内存),具体硬件加速的方法,表明哪个使用了硬件加速;

  • var:描述的是具体屏的一些参数,包括可见的分辨率,Bpp(bits_per_pixel),还有具体的时钟信号,包括bp,fp,vsync,hsync等,可以通过应用层设置也可以驱动层配置,相关设置时序的工具有fbset,还有相关的一些调色板配置;

  • fix:描述的是不可变量,驱动中控制参数,不能在用户层更改。包括显存起始位置(一般是显示控制器DMA起始地址-物理地址,smem_start),framebuffer的长度(smem_len);

  • monspecs:描述的是显示器的一些参数,时序,生产日期等,一般这种信息描述在显示器中的EDID中,通过解析EDID来填充此参数;

  • queue:事件队列,不过分析多个驱动,并没有发现使用该字段的,等遇到再做更新;

  • pixmap,sprite(光标)都是像素图,注册framebuffer的时候会默认申请;

  • cmap:设备独立的 colormap 信息,可以通过 ioctl 的 FBIOGETCMAP 和 FBIOPUTCMAP 命令设置 colormap;

  • modelist:将var参数转化成video mode,然后存入这个链表;

  • mode:一些时序,刷新率扫描方式(vmode)(隔行,逐行),极性(sync);

  • 关于背光CONFIG_FB_BACKLIGHT,有关于背光曲线以及背光设备注册,需要注意的是需要在注册framebuffer之前就对其初始化;

  • CONFIG_FB_DEFERRED_IO,延迟IO,使用缺页中断的原理操作,减少FBIOPAN_DISPLAY带来的系统调用开支。

  • fbops:提供具体的fb操作函数,主要是通过fbmem.c中提供的文件操作函数,间接调用fb_ops,主要的操作有fb_check_var,fb_pan_display,fb_mmap,等,以下三个函数提供了绘图的操作,可以使用系统中的绘图函数,也可以重写硬件加速的绘图函数;

  • device:fb_info的设备父节点,对应即sys/device/xxx/fb_info;

  • dev:设备指针,注册framebuffer时创建;

  • pseudo_palette:伪调色板;

  • state:硬件状态,在fbmem中会设置成suspend以及resume;

  • skip_vt_switch:关于VT switch,是与console切换以及PM相关的;


3.2 fb_info标志位

fb_info标志位定义如下:

/* FBINFO_* = fb_info.flags bit flags */
#define FBINFO_DEFAULT 0
#define FBINFO_HWACCEL_DISABLED 0x0002
/* When FBINFO_HWACCEL_DISABLED is set:
* Hardware acceleration is turned off. Software implementations
* of required functions (copyarea(), fillrect(), and imageblit())
* takes over; acceleration engine should be in a quiescent state
*/
/* hints */
#define FBINFO_VIRTFB 0x0004 /* FB is System RAM, not device. */
#define FBINFO_PARTIAL_PAN_OK 0x0040 /* otw use pan only for double-buffering */
#define FBINFO_READS_FAST 0x0080 /* soft-copy faster than rendering */
/* hardware supported ops */
/* semantics: when a bit is set, it indicates that the operation is
* accelerated by hardware.
* required functions will still work even if the bit is not set.
* optional functions may not even exist if the flag bit is not set.
*/
#define FBINFO_HWACCEL_NONE 0x0000
#define FBINFO_HWACCEL_COPYAREA 0x0100 /* required */
#define FBINFO_HWACCEL_FILLRECT 0x0200 /* required */
#define FBINFO_HWACCEL_IMAGEBLIT 0x0400 /* required */
#define FBINFO_HWACCEL_ROTATE 0x0800 /* optional */
#define FBINFO_HWACCEL_XPAN 0x1000 /* optional */
#define FBINFO_HWACCEL_YPAN 0x2000 /* optional */
#define FBINFO_HWACCEL_YWRAP 0x4000 /* optional */
#define FBINFO_MISC_USEREVENT 0x10000 /* event request
from userspace */
#define FBINFO_MISC_TILEBLITTING 0x20000 /* use tile blitting */
/* A driver may set this flag to indicate that it does want a set_par to be
* called every time when fbcon_switch is executed. The advantage is that with
* this flag set you can really be sure that set_par is always called before
* any of the functions dependent on the correct hardware state or altering
* that state, even if you are using some broken X releases. The disadvantage
* is that it introduces unwanted delays to every console switch if set_par
* is slow. It is a good idea to try this flag in the drivers initialization
* code whenever there is a bug report related to switching between X and the
* framebuffer console.
*/
#define FBINFO_MISC_ALWAYS_SETPAR 0x40000
/* where the fb is a firmware driver, and can be replaced with a proper one */
#define FBINFO_MISC_FIRMWARE 0x80000
/*
* Host and GPU endianness differ.
*/
#define FBINFO_FOREIGN_ENDIAN 0x100000
/*
* Big endian math. This is the same flags as above, but with different
* meaning, it is set by the fb subsystem depending FOREIGN_ENDIAN flag
* and host endianness. Drivers should not use this flag.
*/
#define FBINFO_BE_MATH 0x100000
/*
* Hide smem_start in the FBIOGET_FSCREENINFO IOCTL. This is used by modern DRM
* drivers to stop userspace from trying to share buffers behind the kernel's
* back. Instead dma-buf based buffer sharing should be used.
*/
#define FBINFO_HIDE_SMEM_START 0x200000

3.3 fb_ops 

fb_ops里存放时的framebuffer设备操作函数:

/*
* Frame buffer operations
*
* LOCKING NOTE: those functions must _ALL_ be called with the console
* semaphore held, this is the only suitable locking mechanism we have
* in 2.6. Some may be called at interrupt time at this point though.
*
* The exception to this is the debug related hooks. Putting the fb
* into a debug state (e.g. flipping to the kernel console) and restoring
* it must be done in a lock-free manner, so low level drivers should
* keep track of the initial console (if applicable) and may need to
* perform direct, unlocked hardware writes in these hooks.
*/
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);
/* 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);
};

三、fbmem.c源码分析

fbmem.c是framebuffer设备驱动的核心,它向上给应用程序提供了系统调用的接口,向下对特定的硬件提供了底层的驱动接口,底层驱动可以通过接口向内核注册自己。

fbmem.c位于drivers/video/fbdev/core路径下。我们可以在该文件定位到驱动模块的入口和出口:

module_init(fbmem_init);
module_exit(fbmem_exit);

3.1 入口函数

我们定位到fbmem.c的入口函数,也就是fbmem_init:

/**
* fbmem_init - init frame buffer subsystem
*
* Initialize the frame buffer subsystem.
*
* NOTE: This function is _only_ to be called by drivers/char/mem.c.
*
*/
static int __init
fbmem_init(
void)
{
int ret;
if (!proc_create_seq("fb", 0, NULL, &proc_fb_seq_ops))
return -ENOMEM;
ret
= register_chrdev(FB_MAJOR, "fb", &fb_fops);
if (ret) {
printk(
"unable to get major %d for fb devs\n", FB_MAJOR);
goto err_chrdev;
}
fb_class
= class_create(THIS_MODULE, "graphics");
if (IS_ERR(fb_class)) {
ret
= PTR_ERR(fb_class);
pr_warn(
"Unable to create fb class; errno = %d\n", ret);
fb_class
= NULL;
goto err_class;
}
fb_console_init();
return 0;
err_class:
unregister_chrdev(FB_MAJOR,
"fb");
err_chrdev:
remove_proc_entry(
"fb", NULL);
return ret;
}

简要分析一下该函数执行流程:



  • 创建/proc/fb文件;



  • 创建字符设备fb,主设备编号为FB_MAJOR(29),注册file_operations结构体fb_fops;



  • 调用class_create在/sys/class目录下创建graphics这个类,但是此时并没有调用device_create在/dev下创建设备节点 ;

可以通过如下命令查看字符设备:

root@zhengyang:/work/sambashare/linux-5.2.8# cat /proc/devices
Character devices:
1 mem
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
5 ttyprintk
6 lp
7 vcs
10 misc
13 input
14 sound/midi
14 sound/dmmidi
21 sg
29 fb // 这个名字来自register_chrdev函数第二个参数
89 i2c

可以看到,确实是创建了主设备号为29的"fb"设备,而这里还没有创建设备节点,后面会提到,内核将该工作放到注册lcd驱动的接口函数里了。


3.2 fb_fops

我们再来看看file_operations结构体fb_fops:

static const struct file_operations fb_fops = {
.owner
= THIS_MODULE,
.read
= fb_read,
.write
= fb_write,
.unlocked_ioctl
= fb_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl
= fb_compat_ioctl,
#endif
.mmap
= fb_mmap,
.open
= fb_open,
.release
= fb_release,
#if defined(HAVE_ARCH_FB_UNMAPPED_AREA) || \
(defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA)
&& \
!defined(CONFIG_MMU))
.get_unmapped_area
= get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
.fsync
= fb_deferred_io_fsync,
#endif
.llseek
= default_llseek,
};

下面我们来一一分析这些成员函数。

3.3 fb_open

static int
fb_open(
struct inode *inode, struct file *file)
__acquires(
&info->lock)
__releases(
&info->lock)
{
int fbidx = iminor(inode); // 获取设备节点的次设备号
struct fb_info *info; // 定义fb_info指针
int res = 0;
info
= get_fb_info(fbidx); // 根据次设备编号获取lcd驱动信息
if (!info) {
request_module(
"fb%d", fbidx);
info
= get_fb_info(fbidx);
if (!info)
return -ENODEV;
}
if (IS_ERR(info))
return PTR_ERR(info);
mutex_lock(
&info->lock); // 获取互斥锁
if (!try_module_get(info->fbops->owner)) {
res
= -ENODEV;
goto out;
}
file
->private_data = info;
if (info->fbops->fb_open) {
res
= info->fbops->fb_open(info,1);
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;
}

这里我们来看一下get_fb_info函数的实现:

static struct fb_info *get_fb_info(unsigned int idx)
{
struct fb_info *fb_info;
if (idx >= FB_MAX)
return ERR_PTR(-ENODEV);
mutex_lock(
&registration_lock);
fb_info
= registered_fb[idx];
if (fb_info)
atomic_inc(
&fb_info->count);
mutex_unlock(
&registration_lock);
return fb_info;
}

可以看到get_fb_info函数将registered_fb数组的第idx个元素赋值给了fb_info,registered_fb是一个struct fb_info结构类型的全局数组:

struct fb_info *registered_fb[FB_MAX] __read_mostly;

这和数组会在register_framebuffer函数中赋值。

经过分析,我们最终会发现fb_open执行的是fb的操作函数中的fbopen函数。

3.4 fb_read

static ssize_t
fb_read(
struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
unsigned
long p = *ppos;
struct fb_info *info = file_fb_info(file);
u8
*buffer, *dst;
u8 __iomem
*src;
int c, cnt = 0, err = 0;
unsigned
long total_size;
if (!info || ! info->screen_base)
return -ENODEV;
if (info->state != FBINFO_STATE_RUNNING)
return -EPERM;
if (info->fbops->fb_read)
return info->fbops->fb_read(info, buf, count, ppos);
total_size
= info->screen_size;
if (total_size == 0)
total_size
= info->fix.smem_len;
if (p >= total_size)
return 0;
if (count >= total_size)
count
= total_size;
if (count + p > total_size)
count
= total_size - p;
buffer
= kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
GFP_KERNEL);
if (!buffer)
return -ENOMEM;
src
= (u8 __iomem *) (info->screen_base + p);
if (info->fbops->fb_sync)
info
->fbops->fb_sync(info);
while (count) {
c
= (count > PAGE_SIZE) ? PAGE_SIZE : count;
dst
= buffer;
fb_memcpy_fromfb(dst, src, c);
dst
+= c;
src
+= c;
if (copy_to_user(buf, buffer, c)) {
err
= -EFAULT;
break;
}
*ppos += c;
buf
+= c;
cnt
+= c;
count
-= c;
}
kfree(buffer);
return (err) ? err : cnt;
}

3.5 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 = 0, err = 0;
unsigned
long total_size;
if (!info || !info->screen_base)
return -ENODEV;
if (info->state != FBINFO_STATE_RUNNING)
return -EPERM;
if (info->fbops->fb_write)
return info->fbops->fb_write(info, buf, count, ppos);
total_size
= info->screen_size;
if (total_size == 0)
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);
if (info->fbops->fb_sync)
info
->fbops->fb_sync(info);
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;
}

3.6 fb_ioctl

参考文章

[1]十二、Linux驱动之LCD驱动

[2]15.linux-LCD层次分析(详解)

[3]Linux LCD Frambuffer 基础介绍和使用(1)

[4]Linux驱动开发 (framebuffer驱动)

[5]Linux-FrameBuffer fb_info结构体解析申请以及注册



推荐阅读
  • 本文详细介绍了如何在 Linux 平台上安装和配置 PostgreSQL 数据库。通过访问官方资源并遵循特定的操作步骤,用户可以在不同发行版(如 Ubuntu 和 Red Hat)上顺利完成 PostgreSQL 的安装。 ... [详细]
  • 掌握远程执行Linux脚本和命令的技巧
    本文将详细介绍如何利用Python的Paramiko库实现远程执行Linux脚本和命令,帮助读者快速掌握这一实用技能。通过具体的示例和详尽的解释,让初学者也能轻松上手。 ... [详细]
  • MySQL 数据库迁移指南:从本地到远程及磁盘间迁移
    本文详细介绍了如何在不同场景下进行 MySQL 数据库的迁移,包括从一个硬盘迁移到另一个硬盘、从一台计算机迁移到另一台计算机,以及解决迁移过程中可能遇到的问题。 ... [详细]
  • Hadoop入门与核心组件详解
    本文详细介绍了Hadoop的基础知识及其核心组件,包括HDFS、MapReduce和YARN。通过本文,读者可以全面了解Hadoop的生态系统及应用场景。 ... [详细]
  • 本文详细介绍了VMware的多种认证选项,帮助你根据职业需求和个人技能选择最合适的认证路径,涵盖从基础到高级的不同层次认证。 ... [详细]
  • 本文由瀚高PG实验室撰写,详细介绍了如何在PostgreSQL中创建、管理和删除模式。文章涵盖了创建模式的基本命令、public模式的特性、权限设置以及通过角色对象简化操作的方法。 ... [详细]
  • 本文详细介绍了如何在Ubuntu系统中下载适用于Intel处理器的64位版本,涵盖了不同Linux发行版对64位架构的不同命名方式,并提供了具体的下载链接和步骤。 ... [详细]
  • 本文介绍如何通过更改软件源来提前体验Ubuntu 8.10,包括详细的配置步骤和相关注意事项。 ... [详细]
  • 本文详细记录了在银河麒麟操作系统和龙芯架构上使用 Qt 5.15.2 进行项目打包时遇到的问题及解决方案,特别关注于 linuxdeployqt 工具的应用。 ... [详细]
  • Linux设备驱动程序:异步时间操作与调度机制
    本文介绍了Linux内核中的几种异步延迟操作方法,包括内核定时器、tasklet机制和工作队列。这些机制允许在未来的某个时间点执行任务,而无需阻塞当前线程,从而提高系统的响应性和效率。 ... [详细]
  • 本文介绍如何在Linux服务器之间使用SCP命令进行文件传输。SCP(Secure Copy Protocol)是一种基于SSH的安全文件传输协议,支持从远程机器复制文件到本地服务器或反之。示例包括从192.168.45.147复制tomcat目录到本地/home路径。 ... [详细]
  • Composer Registry Manager:PHP的源切换管理工具
    本文介绍了一个用于Composer的源切换管理工具——Composer Registry Manager。该项目旨在简化Composer包源的管理和切换,避免与常见的CRM系统混淆,并提供了详细的安装和使用指南。 ... [详细]
  • PHP中去除换行符的多种方法及应用场景
    本文将详细介绍在PHP中去除换行符的各种方法,并结合实际应用场景进行说明。通过本文,您将了解如何根据不同操作系统的特点,选择最合适的换行符处理方式。 ... [详细]
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
  • 深入探讨CPU虚拟化与KVM内存管理
    本文详细介绍了现代服务器架构中的CPU虚拟化技术,包括SMP、NUMA和MPP三种多处理器结构,并深入探讨了KVM的内存虚拟化机制。通过对比不同架构的特点和应用场景,帮助读者理解如何选择最适合的架构以优化性能。 ... [详细]
author-avatar
e我爱你很多
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有