一.QEMU上创建LCD设备仿真
\qemu\hw\display\100ask_qemu_fb.c
1.在QEMU上创建LCD设备
static const TypeInfo ask100fb_info = {
.name = TYPE_100ASKFB,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(ASK100FbState), /* object_new_with_type 创建设备时会malloc该结构体, 并传给instance_init */
.class_init = ask100fb_class_init,
.instance_init = ask100fb_init, /* object_init_with_type */
};
void create_100ask_qemu_fb(void)
{
DeviceState *dev;
dev = qdev_create(NULL, TYPE_100ASKFB);
qdev_init_nofail(dev);
}
static void ask100fb_register_types(void)
{
type_register_static(&ask100fb_info);
}
type_init(ask100fb_register_types)
2.给LCD控制器提供回调函数
ask100fb_class_init设备类初始化实现图像更新,ask100fb_init设备实例初始化实现读写lcd驱动的值。
// 设备类初始化回调函数
static void ask100fb_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
dc->realize = ask100fb_realize; /* ask100fb_realize 何时被调用 */
/* Note: This device does not any state that we have to reset or migrate */
}
static void ask100fb_realize(DeviceState *dev, Error **errp)
{
ASK100FbState *s = ASK100FB(dev);
if (imx6ul_board_ui_backgroud_prepare())
return;
s->invalidate = 1;
s->fb_xres = imx6ul_board_descs[selected_board].lcd.w;
s->fb_yres = imx6ul_board_descs[selected_board].lcd.h;
s->board_xres = board_mem_pixels.iWidth;
s->board_yres = board_mem_pixels.iHeight;
dev->id = "board";
s->con = graphic_console_init(dev, 0, &ask100fb_ops, s); // 调用ops回调函数实现板子画面更新
qemu_console_resize(s->con, s->board_xres, s->board_yres);
s->input_state = qemu_input_handler_register(dev, &touchscreen_handler);
qemu_input_handler_bind(s->input_state, dev->id, 0, NULL);
qemu_input_handler_activate(s->input_state);
}
static const GraphicHwOps ask100fb_ops = {
.invalidate = ask100fb_invalidate,
.gfx_update = ask100fb_update,
};
static void ask100fb_update(void *opaque)
{
ASK100FbState *s = ASK100FB(opaque);
SysBusDevice *sbd;
DisplaySurface *surface = qemu_console_surface(s->con);
static int inited = 0;
int dest_width;
int src_width;
int first = 0;
int last = 0;
int fb_x, fb