You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
(1) |
Apr
(104) |
May
(81) |
Jun
(248) |
Jul
(133) |
Aug
(33) |
Sep
(53) |
Oct
(82) |
Nov
(166) |
Dec
(71) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
(121) |
Feb
(42) |
Mar
(39) |
Apr
(84) |
May
(87) |
Jun
(58) |
Jul
(97) |
Aug
(130) |
Sep
(32) |
Oct
(139) |
Nov
(108) |
Dec
(216) |
2003 |
Jan
(299) |
Feb
(136) |
Mar
(392) |
Apr
(141) |
May
(137) |
Jun
(107) |
Jul
(94) |
Aug
(262) |
Sep
(300) |
Oct
(216) |
Nov
(72) |
Dec
(94) |
2004 |
Jan
(174) |
Feb
(192) |
Mar
(215) |
Apr
(314) |
May
(319) |
Jun
(293) |
Jul
(205) |
Aug
(161) |
Sep
(192) |
Oct
(226) |
Nov
(308) |
Dec
(89) |
2005 |
Jan
(127) |
Feb
(269) |
Mar
(588) |
Apr
(106) |
May
(77) |
Jun
(77) |
Jul
(161) |
Aug
(239) |
Sep
(86) |
Oct
(112) |
Nov
(153) |
Dec
(145) |
2006 |
Jan
(87) |
Feb
(57) |
Mar
(129) |
Apr
(109) |
May
(102) |
Jun
(232) |
Jul
(97) |
Aug
(69) |
Sep
(67) |
Oct
(69) |
Nov
(214) |
Dec
(82) |
2007 |
Jan
(133) |
Feb
(307) |
Mar
(121) |
Apr
(171) |
May
(229) |
Jun
(156) |
Jul
(185) |
Aug
(160) |
Sep
(122) |
Oct
(130) |
Nov
(78) |
Dec
(27) |
2008 |
Jan
(105) |
Feb
(137) |
Mar
(146) |
Apr
(148) |
May
(239) |
Jun
(208) |
Jul
(157) |
Aug
(244) |
Sep
(119) |
Oct
(125) |
Nov
(189) |
Dec
(225) |
2009 |
Jan
(157) |
Feb
(139) |
Mar
(106) |
Apr
(130) |
May
(246) |
Jun
(189) |
Jul
(128) |
Aug
(127) |
Sep
(88) |
Oct
(86) |
Nov
(216) |
Dec
(9) |
2010 |
Jan
(5) |
Feb
|
Mar
(11) |
Apr
(31) |
May
(3) |
Jun
|
Jul
(7) |
Aug
|
Sep
(1) |
Oct
|
Nov
(1) |
Dec
|
2012 |
Jan
|
Feb
|
Mar
(3) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2013 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Alexander G. <ag...@su...> - 2009-11-02 23:24:30
|
On 02.11.2009, at 23:42, Alexander Graf wrote: > > Am 02.11.2009 um 23:32 schrieb Ondrej Zajicek > <san...@cr...>: > >> On Mon, Nov 02, 2009 at 11:09:19PM +0100, Alexander Graf wrote: >>> When we want to create a full VirtIO based machine, we're still >>> missing >>> graphics output. Fortunately, Linux provides us with most of the >>> frameworks >>> to render text and everything, we only need to implement a >>> transport. >>> >>> So this is a frame buffer backend written for VirtIO. Using this >>> and my >>> patch to qemu, you can use paravirtualized graphics. >> >> Just a note: it might be useful to allow paravirtualized graphics to >> handle text mode. In that case, it can be done in fbdev layer using >> tileblit operations. > > Is there any real driver implementing this already? I'd prefer to copy > from working code instead of writing my own :-). > > Also, we still need to keep the local frame buffer copy in sync so we > can mmap and read from it, right? So it's not really worth it > probably... But then again we could just try to be closer to a real graphics card. What if we'd set up a memory region on the host that is basically our graphics frame buffer? For S390 we could just append the graphics memory to the guest's memory. We could use that as backing buffer in the qemu graphics frontend and as frame buffer in the Linux fbdev layer, similar to what real graphics cards set up. Then we could send all those fancy commands that we have already over to the host, that renders them and thanks to the mapping have a consistent frame buffer we can mmap. It'd even simplify the deferred IO stuff, making it basically a notify that something changed, but the changes already being written to the frame buffer. On sync we'd just have to make sure the virtio buffer was processed completely. That would get rid of all sys_* calls, a lot of copying and the duplicate frame buffer we have right now. Wow. Alex |
From: Alexander G. <ag...@su...> - 2009-11-02 22:42:34
|
Am 02.11.2009 um 23:32 schrieb Ondrej Zajicek <san...@cr...>: > On Mon, Nov 02, 2009 at 11:09:19PM +0100, Alexander Graf wrote: >> When we want to create a full VirtIO based machine, we're still >> missing >> graphics output. Fortunately, Linux provides us with most of the >> frameworks >> to render text and everything, we only need to implement a transport. >> >> So this is a frame buffer backend written for VirtIO. Using this >> and my >> patch to qemu, you can use paravirtualized graphics. > > Just a note: it might be useful to allow paravirtualized graphics to > handle text mode. In that case, it can be done in fbdev layer using > tileblit operations. Is there any real driver implementing this already? I'd prefer to copy from working code instead of writing my own :-). Also, we still need to keep the local frame buffer copy in sync so we can mmap and read from it, right? So it's not really worth it probably... Alex |
From: Alexander G. <ag...@su...> - 2009-11-02 22:12:12
|
Since Linux now understands how to talk to us graphics over VirtIO, let's add support for it in qemu. The good part about graphics over VirtIO is that you don't need PCI to use it. So if there's any platform out there trying to use graphics, but not capable of MMIO, it can use this one! Signed-off-by: Alexander Graf <ag...@su...> --- Makefile.target | 1 + hw/virtio-fb.c | 434 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/virtio.h | 1 + 3 files changed, 436 insertions(+), 0 deletions(-) create mode 100644 hw/virtio-fb.c diff --git a/Makefile.target b/Makefile.target index fefd7ac..260a6a8 100644 --- a/Makefile.target +++ b/Makefile.target @@ -158,6 +158,7 @@ obj-y = vl.o async.o monitor.o pci.o machine.o gdbstub.o # virtio has to be here due to weird dependency between PCI and virtio-net. # need to fix this properly obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o +obj-y += virtio-fb.o obj-$(CONFIG_KVM) += kvm.o kvm-all.o obj-$(CONFIG_ISA_MMIO) += isa_mmio.o LIBS+=-lz diff --git a/hw/virtio-fb.c b/hw/virtio-fb.c new file mode 100644 index 0000000..c41d3bb --- /dev/null +++ b/hw/virtio-fb.c @@ -0,0 +1,434 @@ +/* + * Virtio Frame Buffer Device + * + * Copyright (c) 2009 Alexander Graf <ag...@su...> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "hw.h" +#include "console.h" +#include "virtio.h" + +#define VIRTIO_ID_FB 6 + +typedef struct VirtIOFB +{ + VirtIODevice vdev; + DisplayState *ds; + VirtQueue *vq_in; + VirtQueue *vq_out; +} VirtIOFB; + +/* guest -> Host commands */ +#define VIRTIO_FB_CMD_RESIZE 0x01 +#define VIRTIO_FB_CMD_FILL 0x02 +#define VIRTIO_FB_CMD_BLIT 0x03 +#define VIRTIO_FB_CMD_COPY 0x04 +#define VIRTIO_FB_CMD_WRITE 0x05 + +/* host -> guest commands */ +#define VIRTIO_FB_CMD_REFRESH 0x81 + +#define ROP_COPY 0 +#define ROP_XOR 1 + +#define BITS_PER_PIXEL 32 +#define BYTES_PER_PIXEL (BITS_PER_PIXEL / 8) + +struct virtio_fb_cmd { + uint8_t cmd; + union { + struct { + uint16_t width; + uint16_t height; + } resize __attribute__ ((packed)); + struct { + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; + } blit __attribute__ ((packed)); + struct { + uint16_t x1; + uint16_t y1; + uint16_t x2; + uint16_t y2; + uint16_t width; + uint16_t height; + } copy_area __attribute__ ((packed)); + struct { + uint8_t rop; + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; + uint32_t color; + } fill __attribute__ ((packed)); + struct { + uint64_t offset; + uint64_t count; + } write __attribute__ ((packed)); + uint8_t pad[31]; + }; + + uint8_t data[]; +} __attribute__ ((packed)); + +static VirtIOFB *to_virtio_fb(VirtIODevice *vdev) +{ + return (VirtIOFB *)vdev; +} + +static uint32_t virtio_fb_get_features(VirtIODevice *vdev) +{ + return 0; +} + +static int virtio_fb_send(struct VirtIOFB *s, struct virtio_fb_cmd *cmd, + uint8_t *data, int len_data) +{ + int len_cmd = sizeof(*cmd); + int len_all = len_cmd + len_data; + VirtQueueElement elem; + int i = 0; + + if (!virtio_queue_ready(s->vq_in)) + return -1; + + if (!virtqueue_pop(s->vq_in, &elem)) { + fprintf(stderr, "virtio-fb: queue lacking elements\n"); + return -1; + } + + if (elem.in_num < 1) { + fprintf(stderr, "virtio-fb: queue lacking sg's\n"); + return -1; + } + + if (elem.in_sg[i].iov_len < len_all) { + fprintf(stderr, "virtio-fb: buffer too small\n"); + return -1; + } + + if (len_data && !data) { + fprintf(stderr, "virtio-fb: passed no data but data length?!\n"); + return -EINVAL; + } + + memcpy(elem.in_sg[i].iov_base, cmd, len_cmd); + if (len_data) + memcpy(elem.in_sg[i].iov_base + len_cmd, data, len_data); + + virtqueue_push(s->vq_in, &elem, len_all); + virtio_notify(&s->vdev, s->vq_in); + + return 0; +} + +/* QEMU display state changed, so refresh the framebuffer copy */ +static void virtio_fb_invalidate(void *opaque) +{ + struct VirtIOFB *s = opaque; + struct virtio_fb_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd = VIRTIO_FB_CMD_REFRESH; + + virtio_fb_send(s, &cmd, NULL, 0); + dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_width(s->ds)); +} + +static void virtio_fb_save(QEMUFile *f, void *opaque) +{ + VirtIOFB *s = opaque; + + virtio_save(&s->vdev, f); +} + +static int virtio_fb_load(QEMUFile *f, void *opaque, int version_id) +{ + VirtIOFB *s = opaque; + + if (version_id != 1) + return -EINVAL; + + virtio_load(&s->vdev, f); + return 0; +} + +static void virtio_fb_handle_input(VirtIODevice *vdev, VirtQueue *vq) +{ +} + +static void virtio_fb_handle_resize(VirtIOFB *s, struct virtio_fb_cmd *cmd) +{ + uint16_t width = tswap16(cmd->resize.width); + uint16_t height = tswap16(cmd->resize.height); + + qemu_free_displaysurface(s->ds); + s->ds->surface = qemu_create_displaysurface_from(width, height, + sizeof(uint32_t) * 8, width * sizeof(uint32_t), + qemu_malloc(width * height * BYTES_PER_PIXEL)); + s->ds->surface->flags |= QEMU_ALLOCATED_FLAG; + + dpy_resize(s->ds); + + if (s->ds->surface->pf.bits_per_pixel != 32) { + fprintf(stderr, "virtio-fb only supports 32 bit ...\n"); + exit(1); + } +} + +static void virtio_fb_handle_fill(VirtIOFB *s, struct virtio_fb_cmd *cmd) +{ + uint16_t x = tswap16(cmd->fill.x); + uint16_t y = tswap16(cmd->fill.y); + uint16_t width = tswap16(cmd->fill.width); + uint16_t height = tswap16(cmd->fill.height); + uint32_t color = tswap32(cmd->fill.color); + uint8_t rop = cmd->fill.rop; + + int ds_depth = ds_get_bytes_per_pixel(s->ds); + int ds_linesize = ds_get_linesize(s->ds); + + uint8_t *ds_data = ds_get_data(s->ds); + uint32_t *src32; + uint8_t *src; + uint8_t *dst; + + int i, len; + + if (ds_depth != sizeof(uint32_t)) { + fprintf(stderr, "ds depth invalid\n"); + exit(1); + } + + if (rop == ROP_XOR) { + fprintf(stderr, "XOR\n"); + exit(1); + } + + if (x > ds_get_width(s->ds)) + return; + + if (y > ds_get_height(s->ds)) + return; + + if ((x + width) > ds_get_width(s->ds)) + return; + + if ((y + height) > ds_get_height(s->ds)) + return; + + len = width * ds_depth; + src = qemu_malloc(width * ds_depth); + src32 = (uint32_t *)src; + + for (i = 0; i < width; i++) { + src32[i] = color; + } + + dst = ds_data + (y * ds_linesize) + (x * ds_depth); + + for (i = 0; i < height; i++) { + memcpy(dst, src, len); + dst += ds_linesize; + } + + qemu_free(src); + + dpy_update(s->ds, x, y, width, height); +} + +static void virtio_fb_handle_blit(VirtIOFB *s, struct virtio_fb_cmd *cmd, + int len) +{ + uint16_t x = tswap16(cmd->blit.x); + uint16_t y = tswap16(cmd->blit.y); + uint16_t width = tswap16(cmd->blit.width); + uint16_t height = tswap16(cmd->blit.height); + + int ds_linesize = ds_get_linesize(s->ds); + int ds_bpp = ds_get_bytes_per_pixel(s->ds); + + int linesize = width * ds_bpp; + uint8_t *ds_data = ds_get_data(s->ds); + uint8_t *dst, *src; + int i; + + if (x > ds_get_width(s->ds)) return; + if (y > ds_get_height(s->ds)) return; + if ((x + width) > ds_get_width(s->ds)) return; + if ((y + height) > ds_get_height(s->ds)) return; + if ((height * linesize) > len) return; + + dst = ds_data + (y * ds_linesize) + (x * ds_bpp); + src = cmd->data; + + for (i = 0; i < height; i++) { + memcpy(dst, src, linesize); + dst += ds_linesize; + src += linesize; + } + + dpy_update(s->ds, x, y, width, height); +} + +static void virtio_fb_handle_copy(VirtIOFB *s, struct virtio_fb_cmd *cmd) +{ + uint16_t x1 = tswap16(cmd->copy_area.x1); + uint16_t y1 = tswap16(cmd->copy_area.y1); + uint16_t x2 = tswap16(cmd->copy_area.x2); + uint16_t y2 = tswap16(cmd->copy_area.y2); + uint16_t width = tswap16(cmd->copy_area.width); + uint16_t height = tswap16(cmd->copy_area.height); + + int ds_width = ds_get_width(s->ds); + int ds_depth = ds_get_bytes_per_pixel(s->ds); + int ds_linesize = ds_get_linesize(s->ds); + uint8_t *ds_data = ds_get_data(s->ds); + uint8_t *bkp; + uint8_t *dst; + uint8_t *src; + int i, len; + + if (ds_depth != sizeof(uint32_t)) { + fprintf(stderr, "ds depth invalid\n"); + exit(1); + } + + if (x1 > ds_get_width(s->ds)) return; + if (y1 > ds_get_height(s->ds)) return; + if (x2 > ds_get_width(s->ds)) return; + if (y2 > ds_get_height(s->ds)) return; + if ((x1 + width) > ds_get_width(s->ds)) return; + if ((y1 + height) > ds_get_height(s->ds)) return; + if ((x2 + width) > ds_get_width(s->ds)) return; + if ((y2 + height) > ds_get_height(s->ds)) return; + + len = (ds_width * ds_depth) + (height * ds_linesize); + bkp = qemu_malloc(len); + memcpy(bkp, ds_data + (x1 * ds_depth) + (y1 * ds_linesize), len); + + src = bkp; + dst = ds_data + (x2 * ds_depth) + (y2 * ds_linesize); + + for (i = 0; i < height; i++) { + memcpy(dst, src, width * ds_depth); + dst += ds_linesize; + src += ds_linesize; + } + + qemu_console_copy(s->ds, x1, y1, x2, y2, width, height); + dpy_update(s->ds, x2, y2, width, height); + + qemu_free(bkp); +} + +static void virtio_fb_handle_write(VirtIOFB *s, struct virtio_fb_cmd *cmd, + int len) +{ + uint64_t offset = tswap64(cmd->write.offset); + uint64_t count = tswap64(cmd->write.count); + uint8_t *ds_data = ds_get_data(s->ds); + int ds_width = ds_get_width(s->ds); + int ds_size = ds_width * ds_get_height(s->ds) * ds_get_bytes_per_pixel(s->ds); + + uint16_t y1 = (offset / sizeof(uint32_t)) / ds_width; + uint16_t y2 = (((offset + count) / sizeof(uint32_t)) / ds_width) + 2; + + if ((offset > ds_size) || (count > len)) + return; + + if ((offset + count) > ds_size) + count = ds_size - offset; + + memcpy(ds_data + offset, cmd->data, count); + + dpy_update(s->ds, 0, y1, ds_get_width(s->ds), y2 - y1); +} + +static void virtio_fb_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOFB *s = to_virtio_fb(vdev); + VirtQueueElement elem; + bool notify = false; + + if (!virtio_queue_ready(vq)) + return; + + while (virtqueue_pop(vq, &elem)) { + int d; + struct virtio_fb_cmd *cmd; + char *data, *p; + int data_len = 0; + + for (d = 0; d < elem.out_num; d++) { + data_len += elem.out_sg[d].iov_len; + } + + data = qemu_malloc(data_len); + p = data; + + for (d = 0; d < elem.out_num; d++) { + memcpy(p, elem.out_sg[d].iov_base, elem.out_sg[d].iov_len); + p += elem.out_sg[d].iov_len; + } + + data_len -= sizeof(*cmd); + cmd = (struct virtio_fb_cmd *)data; + + /* We can have a text console on our display. Don't draw then */ + if (!is_graphic_console()) { + goto next_item; + } + + switch (cmd->cmd) { + case VIRTIO_FB_CMD_RESIZE: + virtio_fb_handle_resize(s, cmd); + break; + case VIRTIO_FB_CMD_FILL: + virtio_fb_handle_fill(s, cmd); + break; + case VIRTIO_FB_CMD_BLIT: + virtio_fb_handle_blit(s, cmd, data_len); + break; + case VIRTIO_FB_CMD_COPY: + virtio_fb_handle_copy(s, cmd); + break; + case VIRTIO_FB_CMD_WRITE: + virtio_fb_handle_write(s, cmd, data_len); + break; + } + +next_item: + + qemu_free(data); + virtqueue_push(vq, &elem, 0); + notify = true; + } + + if (notify) + virtio_notify(vdev, vq); +} + +VirtIODevice *virtio_fb_init(DeviceState *dev) +{ + VirtIOFB *s; + s = (VirtIOFB *)virtio_common_init("virtio-fb", VIRTIO_ID_FB, + 0, sizeof(VirtIOFB)); + s->vdev.get_features = virtio_fb_get_features; + + s->vq_in = virtio_add_queue(&s->vdev, 128, virtio_fb_handle_input); + s->vq_out = virtio_add_queue(&s->vdev, 512, virtio_fb_handle_output); + + s->ds = graphic_console_init(NULL, virtio_fb_invalidate, + NULL, NULL, s); + + register_savevm("virtio-fb", -1, 1, virtio_fb_save, virtio_fb_load, s); + + return &s->vdev; +} diff --git a/hw/virtio.h b/hw/virtio.h index 15ad910..9055f60 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -167,6 +167,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, DriveInfo *dinfo); VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf); VirtIODevice *virtio_console_init(DeviceState *dev); VirtIODevice *virtio_balloon_init(DeviceState *dev); +VirtIODevice *virtio_fb_init(DeviceState *dev); void virtio_net_exit(VirtIODevice *vdev); -- 1.6.0.2 |
From: Alexander G. <ag...@su...> - 2009-11-02 22:12:00
|
We now know how to use a frame buffer on VirtIO, but we still can't use it on x86. In order to leverage the power of VirtIO FB, we need to wrap it through virtio-pci. So let's add all the shiny wrappers and add a -vga option. Signed-off-by: Alexander Graf <ag...@su...> --- hw/pc.c | 5 +++++ hw/pci.h | 1 + hw/virtio-pci.c | 29 +++++++++++++++++++++++++++++ sysemu.h | 3 ++- vl.c | 2 ++ 5 files changed, 39 insertions(+), 1 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index bf4718e..4b0d019 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -1190,6 +1190,11 @@ static void pc_init1(ram_addr_t ram_size, } else { isa_vga_init(); } + } else if (virtio_fb_enabled) { + if (pci_enabled) + pci_create_simple(pci_bus, -1, "virtio-fb-pci"); + else + fprintf(stderr, "%s: virtio_fb: no PCI bus\n", __FUNCTION__); } rtc_state = rtc_init(2000); diff --git a/hw/pci.h b/hw/pci.h index 93f93fb..b65a6df 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -70,6 +70,7 @@ extern target_phys_addr_t pci_mem_base; #define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 #define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 +#define PCI_DEVICE_ID_VIRTIO_FB 0x1004 typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, uint32_t address, uint32_t data, int len); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 1665b59..34937de 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -490,6 +490,25 @@ static int virtio_console_init_pci(PCIDevice *pci_dev) return 0; } +static int virtio_fb_init_pci(PCIDevice *pci_dev) +{ + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); + VirtIODevice *vdev; + + if (proxy->class_code != PCI_CLASS_DISPLAY_OTHER) + proxy->class_code = PCI_CLASS_DISPLAY_OTHER; + + vdev = virtio_fb_init(&pci_dev->qdev); + if (!vdev) { + return -1; + } + virtio_init_pci(proxy, vdev, + PCI_VENDOR_ID_REDHAT_QUMRANET, + PCI_DEVICE_ID_VIRTIO_FB, + proxy->class_code, 0x00); + return 0; +} + static int virtio_net_init_pci(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); @@ -574,6 +593,16 @@ static PCIDeviceInfo virtio_info[] = { }, .qdev.reset = virtio_pci_reset, },{ + .qdev.name = "virtio-fb-pci", + .qdev.size = sizeof(VirtIOPCIProxy), + .init = virtio_fb_init_pci, + .exit = virtio_exit_pci, + .qdev.props = (Property[]) { + DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_PROP_END_OF_LIST(), + }, + .qdev.reset = virtio_pci_reset, + },{ .qdev.name = "virtio-balloon-pci", .qdev.size = sizeof(VirtIOPCIProxy), .init = virtio_balloon_init_pci, diff --git a/sysemu.h b/sysemu.h index 96804b4..c1bc5a3 100644 --- a/sysemu.h +++ b/sysemu.h @@ -104,13 +104,14 @@ extern int autostart; extern int bios_size; typedef enum { - VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB + VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_VIRTIO } VGAInterfaceType; extern int vga_interface_type; #define cirrus_vga_enabled (vga_interface_type == VGA_CIRRUS) #define std_vga_enabled (vga_interface_type == VGA_STD) #define xenfb_enabled (vga_interface_type == VGA_XENFB) +#define virtio_fb_enabled (vga_interface_type == VGA_VIRTIO) #define vmsvga_enabled (vga_interface_type == VGA_VMWARE) extern int graphic_width; diff --git a/vl.c b/vl.c index e57f58f..f999514 100644 --- a/vl.c +++ b/vl.c @@ -4297,6 +4297,8 @@ static void select_vgahw (const char *p) vga_interface_type = VGA_VMWARE; } else if (strstart(p, "xenfb", &opts)) { vga_interface_type = VGA_XENFB; + } else if (strstart(p, "virtio", &opts)) { + vga_interface_type = VGA_VIRTIO; } else if (!strstart(p, "none", &opts)) { invalid_vga: fprintf(stderr, "Unknown vga type: %s\n", p); -- 1.6.0.2 |
From: Alexander G. <ag...@su...> - 2009-11-02 22:09:35
|
When we want to create a full VirtIO based machine, we're still missing graphics output. Fortunately, Linux provides us with most of the frameworks to render text and everything, we only need to implement a transport. So this is a frame buffer backend written for VirtIO. Using this and my patch to qemu, you can use paravirtualized graphics. This is especially important on machines that can't do MMIO, as all current graphics implementations qemu emulates I'm aware of so far fail here. Signed-off-by: Alexander Graf <ag...@su...> --- drivers/video/Kconfig | 15 + drivers/video/Makefile | 1 + drivers/video/virtio-fb.c | 799 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/virtio_ids.h | 1 + 4 files changed, 816 insertions(+), 0 deletions(-) create mode 100644 drivers/video/virtio-fb.c diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 9bbb285..f9be4c2 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2069,6 +2069,21 @@ config XEN_FBDEV_FRONTEND frame buffer driver. It communicates with a back-end in another domain. +config FB_VIRTIO + tristate "Virtio virtual frame buffer support" + depends on FB && VIRTIO + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS + select FB_DEFERRED_IO + help + This driver implements a driver for a Virtio based + frame buffer device. It communicates to something that + can talk Virtio too, most probably a hypervisor. + + If unsure, say N. + config FB_METRONOME tristate "E-Ink Metronome/8track controller support" depends on FB diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 80232e1..40802c8 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -125,6 +125,7 @@ obj-$(CONFIG_FB_XILINX) += xilinxfb.o obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o obj-$(CONFIG_FB_OMAP) += omap/ obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o +obj-$(CONFIG_FB_VIRTIO) += virtio-fb.o obj-$(CONFIG_FB_CARMINE) += carminefb.o obj-$(CONFIG_FB_MB862XX) += mb862xx/ obj-$(CONFIG_FB_MSM) += msm/ diff --git a/drivers/video/virtio-fb.c b/drivers/video/virtio-fb.c new file mode 100644 index 0000000..2a73950 --- /dev/null +++ b/drivers/video/virtio-fb.c @@ -0,0 +1,799 @@ +/* + * VirtIO PV frame buffer device + * + * Copyright (C) 2009 Alexander Graf <ag...@su...> + * + * Based on linux/drivers/video/virtio-fbfront.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/console.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/fb.h> +#include <linux/module.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <linux/virtio.h> +#include <linux/virtio_ids.h> +#include <linux/virtio_config.h> +#include <linux/uaccess.h> +#include <linux/slab.h> +#include <linux/interrupt.h> + +#define MAX_BUF 128 + +struct virtio_fb_info { + struct fb_info *fb_info; + unsigned char *fb; + char *inbuf; + + u16 width; + u16 height; + + int nr_pages; + int size; + + struct kmem_cache *cmd_cache; + struct virtqueue *vq_in; + struct virtqueue *vq_out; + struct virtio_device *vdev; + + void *last_buf[MAX_BUF]; + int last_buf_idx; + spinlock_t vfree_lock; + struct work_struct vfree_work; + struct work_struct refresh_work; +}; + +/* guest -> Host commands */ +#define VIRTIO_FB_CMD_RESIZE 0x01 +#define VIRTIO_FB_CMD_FILL 0x02 +#define VIRTIO_FB_CMD_BLIT 0x03 +#define VIRTIO_FB_CMD_COPY 0x04 +#define VIRTIO_FB_CMD_WRITE 0x05 + +/* host -> guest commands */ +#define VIRTIO_FB_CMD_REFRESH 0x81 + +struct virtio_fb_cmd { + u8 cmd; + union { + struct { + u16 width; + u16 height; + } resize __attribute__ ((packed)); + struct { + u16 x; + u16 y; + u16 width; + u16 height; + } blit __attribute__ ((packed)); + struct { + u16 x1; + u16 y1; + u16 x2; + u16 y2; + u16 width; + u16 height; + } copy_area __attribute__ ((packed)); + struct { + u8 rop; + u16 x; + u16 y; + u16 width; + u16 height; + u32 color; + } fill __attribute__ ((packed)); + struct { + u64 offset; + u64 count; + } write __attribute__ ((packed)); + u8 pad[23]; + }; + + union { + /* We remember the data pointer so we we can easily free + everything later by only knowing this structure */ + char *send_buf; + u64 _pad; + }; +} __attribute__ ((packed)); + +enum copy_type { + COPY_KERNEL, + COPY_USER, + COPY_NOCOPY, +}; + +#define DEFAULT_WIDTH 800 +#define DEFAULT_HEIGHT 600 +#define DEFAULT_DEPTH 32 +#define DEFAULT_MEM 8 + +#define DEFAULT_FB_LEN (DEFAULT_WIDTH * DEFAULT_HEIGHT * DEFAULT_DEPTH / 8) + +enum { KPARAM_MEM, KPARAM_WIDTH, KPARAM_HEIGHT, KPARAM_CNT }; +static int video[KPARAM_CNT] = { DEFAULT_MEM, DEFAULT_WIDTH, DEFAULT_HEIGHT }; +module_param_array(video, int, NULL, 0); +MODULE_PARM_DESC(video, + "Video size in M,width,height in pixels (default \"" + str(DEFAULT_MEM) "," + str(DEFAULT_WIDTH) "," + str(DEFAULT_HEIGHT) "\")"); + +static void virtio_fb_output(struct virtqueue *vq); + +static void *rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr; + + size = PAGE_ALIGN(size); + mem = vmalloc_32(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + while (size > 0) { + SetPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + return mem; +} + +/* This is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c + I modified it to take an extra sg entry for the cmd and work with non + page-aligned pointers though */ +static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int length, + void *cmd, int cmd_len, int *sg_elem) +{ + struct scatterlist *sglist; + struct page *pg; + int nr_pages = (length+PAGE_SIZE-1)/PAGE_SIZE; + int sg_entries; + int i; + + /* unaligned */ + if ((ulong)virt & ~PAGE_MASK) { + int tmp_len = length - (PAGE_SIZE - ((ulong)virt & ~PAGE_MASK)); + /* how long would it be without the first non-aligned chunk? */ + nr_pages = (tmp_len+PAGE_SIZE-1)/PAGE_SIZE; + /* add the first chunk */ + nr_pages++; + } + + sg_entries = nr_pages + 1; + + sglist = kcalloc(sg_entries, sizeof(struct scatterlist), GFP_KERNEL); + if (!sglist) + return NULL; + sg_init_table(sglist, sg_entries); + + /* Put cmd element in */ + sg_set_buf(&sglist[0], cmd, cmd_len); + + /* Fill with elements for the data */ + for (i = 1; i < sg_entries; i++) { + pg = vmalloc_to_page(virt); + if (!pg) + goto err; + + if ((ulong)virt & ~PAGE_MASK) { + int tmp_off = ((ulong)virt & ~PAGE_MASK); + + sg_set_page(&sglist[i], pg, PAGE_SIZE - tmp_off, tmp_off); + virt = (char*)((ulong)virt & PAGE_MASK); + } else { + sg_set_page(&sglist[i], pg, PAGE_SIZE, 0); + } + virt += PAGE_SIZE; + } + + *sg_elem = sg_entries; + return sglist; + + err: + kfree(sglist); + return NULL; +} + + +static void _virtio_fb_send(struct virtio_fb_info *info, + struct virtio_fb_cmd *cmd, + char *buf, int len, enum copy_type copy) +{ + char *send_buf = NULL; + char *sg_buf = NULL; + struct virtio_fb_cmd *send_cmd; + struct scatterlist *sg; + int len_cmd = sizeof(struct virtio_fb_cmd); + int r, sg_elem; + + send_cmd = kmem_cache_alloc(info->cmd_cache, GFP_KERNEL); + if (!send_cmd) { + printk(KERN_ERR "virtio-fb: couldn't allocate cmd\n"); + return; + } + + memcpy(send_cmd, cmd, len_cmd); + + if (len) { + sg_buf = send_buf = vmalloc(len); + if (!send_buf) { + printk(KERN_ERR "virtio-fb: couldn't allocate %d b\n", + len); + return; + } + + switch (copy) { + case COPY_KERNEL: + memcpy(send_buf, buf, len); + break; + case COPY_USER: + r = copy_from_user(send_buf, (const __user char*)buf, + len); + break; + case COPY_NOCOPY: + sg_buf = buf; + break; + } + } + + send_cmd->send_buf = send_buf; + + sg = vmalloc_to_sg(sg_buf, len, send_cmd, len_cmd, &sg_elem); + if (!sg) { + printk(KERN_ERR "virtio-fb: couldn't gather scatter list\n"); + return; + } + +add_again: + r = info->vq_out->vq_ops->add_buf(info->vq_out, sg, sg_elem, 0, send_cmd); + info->vq_out->vq_ops->kick(info->vq_out); + + if ( r == -ENOSPC ) { + /* Queue was full, so try again */ + cpu_relax(); + virtio_fb_output(info->vq_out); + goto add_again; + } + + kfree(sg); +} + +static void virtio_fb_send_user(struct virtio_fb_info *info, + struct virtio_fb_cmd *cmd, + const __user char *buf, int len) +{ + _virtio_fb_send(info, cmd, (char *)buf, len, COPY_USER); +} + +static void virtio_fb_send_nocopy(struct virtio_fb_info *info, + struct virtio_fb_cmd *cmd, + char *buf, int len) +{ + _virtio_fb_send(info, cmd, buf, len, COPY_NOCOPY); +} + +static void virtio_fb_send(struct virtio_fb_info *info, struct virtio_fb_cmd *cmd, + char *buf, int len) +{ + _virtio_fb_send(info, cmd, buf, len, COPY_KERNEL); +} + + +static int virtio_fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u32 v; + if (regno >= 16) + return 1; + +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); +#undef CNVT_TOHW + + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + + ((u32 *) (info->pseudo_palette))[regno] = v; + + return 0; +} + +static void virtio_fb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) +{ + struct virtio_fb_info *info = p->par; + struct virtio_fb_cmd cmd; + + sys_fillrect(p, rect); + + cmd.cmd = VIRTIO_FB_CMD_FILL; + cmd.fill.rop = rect->rop; + cmd.fill.x = rect->dx; + cmd.fill.y = rect->dy; + cmd.fill.width = rect->width; + cmd.fill.height = rect->height; + cmd.fill.color = rect->color; + + virtio_fb_send(info, &cmd, NULL, 0); +} + +static void virtio_fb_imageblit(struct fb_info *p, const struct fb_image *image) +{ + struct virtio_fb_info *info = p->par; + struct virtio_fb_cmd cmd; + char *_buf; + char *buf; + char *vfb; + int i, w; + int bpp = p->var.bits_per_pixel / 8; + int len = image->width * image->height * bpp; + + sys_imageblit(p, image); + + cmd.cmd = VIRTIO_FB_CMD_BLIT; + cmd.blit.x = image->dx; + cmd.blit.y = image->dy; + cmd.blit.height = image->height; + cmd.blit.width = image->width; + + if (image->depth == 32) { + /* Send the image off directly */ + + virtio_fb_send(info, &cmd, (char*)image->data, len); + return; + } + + /* Send the 32-bit translated image */ + + buf = _buf = vmalloc(len); + + vfb = info->fb; + vfb += (image->dy * p->fix.line_length) + image->dx * bpp; + + w = image->width * bpp; + + for (i = 0; i < image->height; i++) { + memcpy(buf, vfb, w); + + buf += w; + vfb += p->fix.line_length; + } + + virtio_fb_send(info, &cmd, _buf, len); + + vfree(_buf); +} + +static void virtio_fb_copyarea(struct fb_info *p, const struct fb_copyarea *area) +{ + struct virtio_fb_info *info = p->par; + struct virtio_fb_cmd cmd; + + sys_copyarea(p, area); + + cmd.cmd = VIRTIO_FB_CMD_COPY; + cmd.copy_area.x1 = area->sx; + cmd.copy_area.y1 = area->sy; + cmd.copy_area.x2 = area->dx; + cmd.copy_area.y2 = area->dy; + cmd.copy_area.width = area->width; + cmd.copy_area.height = area->height; + + virtio_fb_send(info, &cmd, NULL, 0); +} + +static ssize_t virtio_fb_write(struct fb_info *p, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct virtio_fb_info *info = p->par; + struct virtio_fb_cmd cmd; + loff_t pos = *ppos; + ssize_t res; + + res = fb_sys_write(p, buf, count, ppos); + + cmd.cmd = VIRTIO_FB_CMD_WRITE; + cmd.write.offset = pos; + cmd.write.count = count; + + virtio_fb_send_user(info, &cmd, buf, count); + return res; +} + +static int +virtio_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *p) +{ + struct virtio_fb_info *info = p->par; + + if (var->bits_per_pixel != DEFAULT_DEPTH) { + /* We only support 32 bpp */ + return -EINVAL; + } + + if ((var->xres * var->yres * DEFAULT_DEPTH / 8) > info->size) { + /* Doesn't fit in the frame buffer */ + return -EINVAL; + } + + var->xres_virtual = var->xres; + var->yres_virtual = var->yres; + + return 0; +} + +static int virtio_fb_set_par(struct fb_info *p) +{ + struct virtio_fb_info *info = p->par; + struct virtio_fb_cmd cmd; + + /* Do nothing if we're on that resolution already */ + if ((p->var.xres == info->width) && + (p->var.yres == info->height)) + return 0; + + info->width = p->var.xres; + info->height = p->var.yres; + p->fix.line_length = p->var.xres_virtual * 4; + + /* Notify hypervisor */ + + cmd.cmd = VIRTIO_FB_CMD_RESIZE; + cmd.resize.width = p->var.xres; + cmd.resize.height = p->var.yres; + + virtio_fb_send(info, &cmd, NULL, 0); + + return 0; +} + +static struct fb_ops virtio_fb_ops = { + .owner = THIS_MODULE, + .fb_read = fb_sys_read, + .fb_write = virtio_fb_write, + .fb_setcolreg = virtio_fb_setcolreg, + .fb_fillrect = virtio_fb_fillrect, + .fb_copyarea = virtio_fb_copyarea, + .fb_imageblit = virtio_fb_imageblit, + .fb_check_var = virtio_fb_check_var, + .fb_set_par = virtio_fb_set_par, +}; + +static __devinit void +virtio_fb_make_preferred_console(void) +{ + struct console *c; + + if (console_set_on_cmdline) + return; + + acquire_console_sem(); + for (c = console_drivers; c; c = c->next) { + if (!strcmp(c->name, "tty") && c->index == 0) + break; + } + release_console_sem(); + if (c) { + unregister_console(c); + c->flags |= CON_CONSDEV; + c->flags &= ~CON_PRINTBUFFER; /* don't print again */ + register_console(c); + } +} + +static void virtio_fb_deferred_io(struct fb_info *fb_info, + struct list_head *pagelist) +{ + struct virtio_fb_info *info = fb_info->par; + struct page *page; + unsigned long beg, end; + int y1, y2, miny, maxy; + struct virtio_fb_cmd cmd; + + miny = INT_MAX; + maxy = 0; + list_for_each_entry(page, pagelist, lru) { + beg = page->index << PAGE_SHIFT; + end = beg + PAGE_SIZE - 1; + y1 = beg / fb_info->fix.line_length; + y2 = end / fb_info->fix.line_length; + if (y2 >= fb_info->var.yres) + y2 = fb_info->var.yres - 1; + if (miny > y1) + miny = y1; + if (maxy < y2) + maxy = y2; + } + + if (miny != INT_MAX) { + cmd.cmd = VIRTIO_FB_CMD_WRITE; + cmd.write.offset = miny * fb_info->fix.line_length; + cmd.write.count = (maxy - miny + 1) * fb_info->fix.line_length; + + virtio_fb_send_nocopy(info, &cmd, info->fb + cmd.write.offset, + cmd.write.count); + } +} + +static struct fb_deferred_io virtio_fb_defio = { + .delay = HZ / 20, + .deferred_io = virtio_fb_deferred_io, +}; + +/* Callback when the host kicks our input queue. + * + * This is to enable notifications from host to guest. */ +static void virtio_fb_input(struct virtqueue *vq) +{ + struct virtio_fb_info *info = dev_get_drvdata(&vq->vdev->dev); + int len, i; + void *x; + void *reinject[3]; + int reinject_count = 0; + + while ((x = vq->vq_ops->get_buf(vq, &len)) != NULL) { + struct virtio_fb_cmd *cmd = x; + + /* Make sure we're getting an inbuf page! */ + BUG_ON((x != info->inbuf) && + (x != (info->inbuf + PAGE_SIZE)) && + (x != (info->inbuf + (PAGE_SIZE * 2)))); + + switch (cmd->cmd) { + case VIRTIO_FB_CMD_REFRESH: + schedule_work(&info->refresh_work); + break; + } + + reinject[reinject_count++] = x; + } + + + for (i = 0; i < reinject_count; i++) { + struct scatterlist sg; + void *x = reinject[i]; + + sg_init_one(&sg, x, PAGE_SIZE); + vq->vq_ops->add_buf(vq, &sg, 0, 1, x); + vq->vq_ops->kick(vq); + } +} + +/* Asynchronous snippet to send all screen contents to the host */ +static void deferred_refresh(struct work_struct *work) +{ + struct virtio_fb_info *info = container_of(work, struct virtio_fb_info, + refresh_work); + struct virtio_fb_cmd cmd; + + cmd.cmd = VIRTIO_FB_CMD_WRITE; + cmd.write.offset = 0; + cmd.write.count = info->width * info->height * 4; + + virtio_fb_send_nocopy(info, &cmd, info->fb, cmd.write.count); +} + +/* Asynchronous garbage collector :-) */ +static void deferred_vfree(struct work_struct *work) +{ + struct virtio_fb_info *info = container_of(work, struct virtio_fb_info, + vfree_work); + int i; + unsigned long flags; + void *last_buf[MAX_BUF]; + int idx; + + spin_lock_irqsave(&info->vfree_lock, flags); + + idx = info->last_buf_idx; + memcpy(last_buf, info->last_buf, sizeof(void*) * MAX_BUF); + info->last_buf_idx = 0; + + spin_unlock_irqrestore(&info->vfree_lock, flags); + + for (i = 0; i < idx; i++) { + vfree(last_buf[i]); + } +} + +/* Callback when the host kicks our output queue. This can only mean it's done + * processing an item, so let's free up the memory occupied by the entries */ +static void virtio_fb_output(struct virtqueue *vq) +{ + struct virtio_fb_info *info = dev_get_drvdata(&vq->vdev->dev); + int len; + void *x; + + while ((x = vq->vq_ops->get_buf(vq, &len)) != NULL) { + struct virtio_fb_cmd *cmd = x; + + if (cmd->send_buf) { + spin_lock(&info->vfree_lock); + if (info->last_buf_idx != MAX_BUF) { + info->last_buf[info->last_buf_idx++] = + cmd->send_buf; + } + spin_unlock(&info->vfree_lock); + + schedule_work(&info->vfree_work); + } + + kmem_cache_free(info->cmd_cache, x); + } +} + +static int __devinit virtio_fb_probe(struct virtio_device *dev) +{ + vq_callback_t *callbacks[] = { virtio_fb_input, virtio_fb_output }; + const char *names[] = { "input", "output" }; + struct virtio_fb_info *info; + struct virtqueue *vqs[2]; + struct fb_info *fb_info = NULL; + int fb_size, res_size; + int ret, err, i; + char *inbuf; + + err = dev->config->find_vqs(dev, 2, vqs, callbacks, names); + if (err) { + printk(KERN_ERR "VirtIO FB: couldn't find VQs\n"); + return err; + } + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) + return -ENOMEM; + + info->vq_in = vqs[0]; + info->vq_out = vqs[1]; + + res_size = video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * DEFAULT_DEPTH / 8; + fb_size = video[KPARAM_MEM] * 1024 * 1024; + + if (res_size > fb_size) { + video[KPARAM_WIDTH] = DEFAULT_WIDTH; + video[KPARAM_HEIGHT] = DEFAULT_HEIGHT; + } + + dev_set_drvdata(&dev->dev, info); + info->vdev = dev; + + info->fb = rvmalloc(fb_size); + if (info->fb == NULL) + goto error_nomem; + + info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT; + info->size = fb_size; + + fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); + if (fb_info == NULL) + goto error_nomem; + + inbuf = kmalloc(PAGE_SIZE * 3, GFP_KERNEL); + info->inbuf = inbuf; + for (i = 0; i < (3 * PAGE_SIZE); i += PAGE_SIZE) { + struct scatterlist sg; + + sg_init_one(&sg, inbuf + i, PAGE_SIZE); + info->vq_in->vq_ops->add_buf(info->vq_in, &sg, 0, 1, inbuf + i); + } + info->vq_in->vq_ops->kick(info->vq_in); + + fb_info->pseudo_palette = fb_info->par; + fb_info->par = info; + + fb_info->screen_base = info->fb; + + fb_info->fbops = &virtio_fb_ops; + fb_info->var.xres_virtual = fb_info->var.xres = video[KPARAM_WIDTH]; + fb_info->var.yres_virtual = fb_info->var.yres = video[KPARAM_HEIGHT]; + fb_info->var.bits_per_pixel = DEFAULT_DEPTH; + + fb_info->var.transp = (struct fb_bitfield){24, 8, 0}; + fb_info->var.red = (struct fb_bitfield){16, 8, 0}; + fb_info->var.green = (struct fb_bitfield){8, 8, 0}; + fb_info->var.blue = (struct fb_bitfield){0, 8, 0}; + + fb_info->var.activate = FB_ACTIVATE_NOW; + fb_info->var.height = -1; + fb_info->var.width = -1; + fb_info->var.vmode = FB_VMODE_NONINTERLACED; + + fb_info->fix.visual = FB_VISUAL_TRUECOLOR; + fb_info->fix.line_length = fb_info->var.xres * DEFAULT_DEPTH / 8; + fb_info->fix.smem_start = 0; + fb_info->fix.smem_len = fb_size; + strcpy(fb_info->fix.id, "virtio_fb"); + fb_info->fix.type = FB_TYPE_PACKED_PIXELS; + fb_info->fix.accel = FB_ACCEL_NONE; + + fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_COPYAREA | + FBINFO_READS_FAST; + + ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); + if (ret < 0) { + framebuffer_release(fb_info); + goto error; + } + + info->cmd_cache = kmem_cache_create("virtio_fb_cmd", + sizeof(struct virtio_fb_cmd), + 0, 0, NULL); + + if (!info->cmd_cache) { + framebuffer_release(fb_info); + goto error; + } + + fb_info->fbdefio = &virtio_fb_defio; + fb_deferred_io_init(fb_info); + + INIT_WORK(&info->refresh_work, deferred_refresh); + INIT_WORK(&info->vfree_work, deferred_vfree); + spin_lock_init(&info->vfree_lock); + + ret = register_framebuffer(fb_info); + if (ret) { + fb_deferred_io_cleanup(fb_info); + fb_dealloc_cmap(&fb_info->cmap); + framebuffer_release(fb_info); + goto error; + } + info->fb_info = fb_info; + + virtio_fb_make_preferred_console(); + return 0; + + error_nomem: + ret = -ENOMEM; + error: + framebuffer_release(fb_info); + return ret; +} + +static void virtio_fb_apply_config(struct virtio_device *dev) +{ +} + +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_FB, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static unsigned int features[] = { +}; + +static struct virtio_driver virtio_console = { + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virtio_fb_probe, + .config_changed = virtio_fb_apply_config, +}; + +static int __init init(void) +{ + return register_virtio_driver(&virtio_console); +} +module_init(init); + + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("Virtio framebuffer driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/virtio_ids.h b/include/linux/virtio_ids.h index 06660c0..72e39f7 100644 --- a/include/linux/virtio_ids.h +++ b/include/linux/virtio_ids.h @@ -12,6 +12,7 @@ #define VIRTIO_ID_CONSOLE 3 /* virtio console */ #define VIRTIO_ID_RNG 4 /* virtio ring */ #define VIRTIO_ID_BALLOON 5 /* virtio balloon */ +#define VIRTIO_ID_FB 6 /* virtio framebuffer */ #define VIRTIO_ID_9P 9 /* 9p virtio console */ #endif /* _LINUX_VIRTIO_IDS_H */ -- 1.6.0.2 |
From: James S. <jsi...@in...> - 2009-11-02 14:34:19
|
> Without an allocated colormap, FBIOGETCMAP fails. This would make > programs restore an all-black colormap ("links -g") or fail to work > altogether ("mplayer -vo fbdev2"). > > Signed-off-by: Clemens Ladisch <cl...@la...> > --- > Untested. > > --- linux-2.6/drivers/gpu/drm/i915/intel_fb.c > +++ linux-2.6/drivers/gpu/drm/i915/intel_fb.c > @@ -227,6 +227,10 @@ static int intelfb_create(struct drm_dev > > fb->fbdev = info; > > + ret = fb_alloc_cmap(&info->cmap, 256, 0); > + if (ret) > + goto out_unpin; > + > par->intel_fb = intel_fb; > > /* To allow resizeing without swapping buffers */ It would be better to place that code in drm_fb_helper_single_fb_probe. Also instead of 256 I would recommend using crtc->gamma_size. |
From: InKi D. <da...@gm...> - 2009-11-02 08:50:16
|
This patch adds brightness feature to lcd class. (kernel/driver/video/backlight/lcd.c) In the past, most of the lcd panels for embedded system was TFT-LCD Panel needing backlight device. But now AMOLED LCD Panel appeared so we should consider brightness control for AMOLED Panel. For the time being, I used backlight fake driver for brightness control of AMOLED LCD Panel. But this way is not good, so I propose to add brightness feature to lcd class. For this, I attached patch file and if my proposal is approved Then I will send s6e63m0 and tl2796 AMOLED lcd panel driver based on lcd class modified soon. signed-off-by : InKi Dae <ink...@sa...> Best Regards, InKi Dae. |
From: Clemens L. <cl...@la...> - 2009-11-02 07:56:59
|
Without an allocated colormap, FBIOGETCMAP fails. This would make programs restore an all-black colormap ("links -g") or fail to work altogether ("mplayer -vo fbdev2"). Signed-off-by: Clemens Ladisch <cl...@la...> --- Untested. --- linux-2.6/drivers/gpu/drm/i915/intel_fb.c +++ linux-2.6/drivers/gpu/drm/i915/intel_fb.c @@ -227,6 +227,10 @@ static int intelfb_create(struct drm_dev fb->fbdev = info; + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) + goto out_unpin; + par->intel_fb = intel_fb; /* To allow resizeing without swapping buffers */ @@ -270,6 +274,7 @@ int intelfb_remove(struct drm_device *de iounmap(info->screen_base); if (info->par) drm_fb_helper_free(&par->helper); + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); } |
From: Clemens L. <cl...@la...> - 2009-11-02 07:56:26
|
These patches make the KMS framebuffer work with various programs like links, mplayer and X. drivers/gpu/drm/drm_fb_helper.c | 6 +++--- drivers/gpu/drm/i915/intel_fb.c | 5 +++++ drivers/gpu/drm/radeon/radeon_fb.c | 5 +++++ 3 files changed, 13 insertions(+), 3 deletions(-) |
From: Clemens L. <cl...@la...> - 2009-11-02 07:55:47
|
When the framebuffer driver does not publish detailed timing information for the current video mode, the correct value for the pixclock field is zero, not -1. Since pixclock is actually unsigned, the value -1 would be interpreted as 4294967295 picoseconds (i.e., about 4 milliseconds) by register_framebuffer() and userspace programs. This patch allows X.org's fbdev driver to work. Signed-off-by: Clemens Ladisch <cl...@la...> --- linux-2.6/drivers/gpu/drm/drm_fb_helper.c +++ linux-2.6/drivers/gpu/drm/drm_fb_helper.c @@ -583,7 +583,7 @@ int drm_fb_helper_check_var(struct fb_va struct drm_framebuffer *fb = fb_helper->fb; int depth; - if (var->pixclock == -1 || !var->pixclock) + if (var->pixclock != 0) return -EINVAL; /* Need to resize the fb object !!! */ @@ -675,7 +675,7 @@ int drm_fb_helper_set_par(struct fb_info int ret; int i; - if (var->pixclock != -1) { + if (var->pixclock != 0) { DRM_ERROR("PIXEL CLCOK SET\n"); return -EINVAL; } @@ -888,7 +888,7 @@ int drm_fb_helper_single_fb_probe(struct fb_helper->fb = fb; if (new_fb) { - info->var.pixclock = -1; + info->var.pixclock = 0; if (register_framebuffer(info) < 0) return -EINVAL; } else { |
From: Clemens L. <cl...@la...> - 2009-11-02 07:52:42
|
Without an allocated colormap, FBIOGETCMAP fails. This would make programs restore an all-black colormap ("links -g") or fail to work altogether ("mplayer -vo fbdev2"). Signed-off-by: Clemens Ladisch <cl...@la...> --- linux-2.6/drivers/gpu/drm/radeon/radeon_fb.c +++ linux-2.6/drivers/gpu/drm/radeon/radeon_fb.c @@ -242,6 +242,10 @@ int radeonfb_create(struct drm_device *d goto out_unref; } + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) + goto out_unref; + memset_io(fbptr, 0, aligned_size); strcpy(info->fix.id, "radeondrmfb"); @@ -341,6 +345,7 @@ int radeonfb_remove(struct drm_device *d radeon_object_kunmap(robj); radeon_object_unpin(robj); drm_fb_helper_free(&rfbdev->helper); + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); } |
From: Takashi I. <ti...@su...> - 2009-11-01 10:26:53
|
At Fri, 30 Oct 2009 21:43:39 +1030, Rusty Russell wrote: > > On Fri, 30 Oct 2009 08:48:12 pm Takashi Iwai wrote: > > At Fri, 23 Oct 2009 00:51:28 +1030, > > Rusty Russell wrote: > > > > > > This is more kernel-ish, saves some space, and also allows us to > > > expand the ops without breaking all the callers who are happy for the > > > new members to be NULL. > > > > > > The few places which defined their own param types are changed to the > > > new scheme. > > > > > > Since we're touching them anyway, we change get and set to take a > > > const struct kernel_param (which they were, and will be again). > > > > > > To reduce churn, module_param_call creates the ops struct so the callers > > > don't have to change (and casts the functions to reduce warnings). > > > The modern version which takes an ops struct is called module_param_cb. > > > > This is nice, as it also reduces the size of struct kernel_param, so > > each parameter uses less footprint (who cares, though?) :) > > > > But, just wondering whether we still need to export get/set > > functions. They can be called from ops now, so if any, it can be > > defined even as an inlinefunction or a macro. > > My thought too, so I tried that, but many are still used like so: > > module_param_call(foo, set_foo, param_get_uint, NULL, 0644); > > They can all be replaced in time with something like: > static int param_get_foo(char *buffer, const struct kernel_param *kp) > { > return param_ops_uint.get(buffer, kp); > } > > But it'll take a transition period. Fair enough. And, maybe these get/set should be defined as an ops explicitly so that it can be used for multiple parameters. But we can do cleanups later, of course :) Oh, in case you need, Reviewed-by: Takashi Iwai <ti...@su...> for all new patches. Thanks! Takashi |
From: Janusz K. <jkr...@ti...> - 2009-11-01 01:21:24
|
Friday 30 October 2009 18:33:18 Tony Lindgren napisał(a): > * Janusz Krzysztofik <jkr...@ti...> [091030 07:43]: > > Thursday 29 October 2009 23:39:44 Janusz Krzysztofik napisał(a): > > > With CONFIG_PM=y, the omapfb/lcd device on Amstrad Delta, after > > > initially starting correctly, breaks with the following error messages: > > > > > > omapfb omapfb: resetting (status 0xffffff96,reset count 1) > > > ... > > > omapfb omapfb: resetting (status 0xffffff96,reset count 100) > > > omapfb omapfb: too many reset attempts, giving up. > > > > > > Looking closer at this I have found that it had been broken almost 2 > > > years ago with commit 2418996e3b100114edb2ae110d5d4acb928909d2, PM > > > fixes for OMAP1. > > > > > > The definite reason for broken omapfb/lcd_ams_delta in PM mode appeared > > > to be ARM_IDLECT1:IDLIF_ARM (bit 6) put into idle. The patch below > > > fixes it. > > > > > > Since PM area is quite new to me, I am not sure if there may be a > > > better solution. AFAICS, the standard way to prevent an ARM_CLKCT1 bit > > > being switched to idle is to enable a clock that uses it (tipb_ck, > > > dma_ck, or tc_ck or one of its children in this case, right?). > > > > > > I assume there is no bug in omapfb nor lcdc, as that would be already > > > detected. Maybe it would be better to fix > > > drivers/video/omap/lcd_ams_delta.c (or > > > arch/arm/mach-omap1/board-ams-delta), but I don't know what clock > > > should I enable, if any. > > > > More looking at it, I found that might be omap_dma_running() from > > arch/arm/plat-omap/dma.c that needs correction. It already checks for LCD > > dma running for OMAP1610, but does nothing similiar for 1510. I have > > revisited http://focus.ti.com/lit/ug/spru674/spru674.pdf, but found no > > hint how to do that in a 1610 similiar way. > > Hmm to me it looks like the OMAP_DMA_CCR_EN should be set in one of the > channels if enabled. Maybe you need add a similar check somewhere in > the *_lcd_dma_* functions too in dma.c? Tony, It sounds reasonable, but the problem is that in the OMAP5910 documentation I can find no DMA_CCR equivalent in the LCD dedicated DMA channel register set, nor EN equivalent in the DMA_LCD_CTRL register. I have had a look at *_lcd_dma_*, as you suggested, and found this: /* * Set the Enable bit only if an external controller is * connected. Otherwise the OMAP internal controller will * start the transfer when it gets enabled. */ if (enable_1510_mode || !lcd_dma.ext_ctrl) return; That may suggest checking for LCD controller, not DMA channel, enable bit could give an answer if LCD DMA is likely to be running or not. So maybe adding a function to drivers/video/omap/lcdc.c that would check for OMAP_LCDC_CONTROL:OMAP_LCDC_CTRL_LCD_EN, then invoke that function from omap_dma_running() in case of omap1510 could be a proper solution. However, that would affect not only Amstrad Delta, but all 1510 based machines. Since there were no reports about broken LCD DMA on 1510, I'd rather get a confirmation from omap guys, more experienced than me, that the solution proposed is correct and should work not only for my Amstrad Delta before I get that way. Thanks, Janusz |
From: Tony L. <to...@at...> - 2009-10-30 17:34:06
|
* Janusz Krzysztofik <jkr...@ti...> [091030 07:43]: > Thursday 29 October 2009 23:39:44 Janusz Krzysztofik napisał(a): > > With CONFIG_PM=y, the omapfb/lcd device on Amstrad Delta, after initially > > starting correctly, breaks with the following error messages: > > > > omapfb omapfb: resetting (status 0xffffff96,reset count 1) > > ... > > omapfb omapfb: resetting (status 0xffffff96,reset count 100) > > omapfb omapfb: too many reset attempts, giving up. > > > > Looking closer at this I have found that it had been broken almost 2 years > > ago with commit 2418996e3b100114edb2ae110d5d4acb928909d2, PM fixes for > > OMAP1. > > > > The definite reason for broken omapfb/lcd_ams_delta in PM mode appeared to > > be ARM_IDLECT1:IDLIF_ARM (bit 6) put into idle. The patch below fixes it. > > > > Since PM area is quite new to me, I am not sure if there may be a better > > solution. AFAICS, the standard way to prevent an ARM_CLKCT1 bit being > > switched to idle is to enable a clock that uses it (tipb_ck, dma_ck, or > > tc_ck or one of its children in this case, right?). > > > > I assume there is no bug in omapfb nor lcdc, as that would be already > > detected. Maybe it would be better to fix > > drivers/video/omap/lcd_ams_delta.c (or > > arch/arm/mach-omap1/board-ams-delta), but I don't know what clock should I > > enable, if any. > > More looking at it, I found that might be omap_dma_running() from > arch/arm/plat-omap/dma.c that needs correction. It already checks for LCD dma > running for OMAP1610, but does nothing similiar for 1510. I have revisited > http://focus.ti.com/lit/ug/spru674/spru674.pdf, but found no hint how to do > that in a 1610 similiar way. Hmm to me it looks like the OMAP_DMA_CCR_EN should be set in one of the channels if enabled. Maybe you need add a similar check somewhere in the *_lcd_dma_* functions too in dma.c? Regards, Tony |
From: Janusz K. <jkr...@ti...> - 2009-10-30 14:43:49
|
Thursday 29 October 2009 23:39:44 Janusz Krzysztofik napisał(a): > With CONFIG_PM=y, the omapfb/lcd device on Amstrad Delta, after initially > starting correctly, breaks with the following error messages: > > omapfb omapfb: resetting (status 0xffffff96,reset count 1) > ... > omapfb omapfb: resetting (status 0xffffff96,reset count 100) > omapfb omapfb: too many reset attempts, giving up. > > Looking closer at this I have found that it had been broken almost 2 years > ago with commit 2418996e3b100114edb2ae110d5d4acb928909d2, PM fixes for > OMAP1. > > The definite reason for broken omapfb/lcd_ams_delta in PM mode appeared to > be ARM_IDLECT1:IDLIF_ARM (bit 6) put into idle. The patch below fixes it. > > Since PM area is quite new to me, I am not sure if there may be a better > solution. AFAICS, the standard way to prevent an ARM_CLKCT1 bit being > switched to idle is to enable a clock that uses it (tipb_ck, dma_ck, or > tc_ck or one of its children in this case, right?). > > I assume there is no bug in omapfb nor lcdc, as that would be already > detected. Maybe it would be better to fix > drivers/video/omap/lcd_ams_delta.c (or > arch/arm/mach-omap1/board-ams-delta), but I don't know what clock should I > enable, if any. More looking at it, I found that might be omap_dma_running() from arch/arm/plat-omap/dma.c that needs correction. It already checks for LCD dma running for OMAP1610, but does nothing similiar for 1510. I have revisited http://focus.ti.com/lit/ug/spru674/spru674.pdf, but found no hint how to do that in a 1610 similiar way. Thanks, Janusz |
From: Rusty R. <ru...@ru...> - 2009-10-30 11:31:09
|
On Fri, 30 Oct 2009 08:48:12 pm Takashi Iwai wrote: > At Fri, 23 Oct 2009 00:51:28 +1030, > Rusty Russell wrote: > > > > This is more kernel-ish, saves some space, and also allows us to > > expand the ops without breaking all the callers who are happy for the > > new members to be NULL. > > > > The few places which defined their own param types are changed to the > > new scheme. > > > > Since we're touching them anyway, we change get and set to take a > > const struct kernel_param (which they were, and will be again). > > > > To reduce churn, module_param_call creates the ops struct so the callers > > don't have to change (and casts the functions to reduce warnings). > > The modern version which takes an ops struct is called module_param_cb. > > This is nice, as it also reduces the size of struct kernel_param, so > each parameter uses less footprint (who cares, though?) :) > > But, just wondering whether we still need to export get/set > functions. They can be called from ops now, so if any, it can be > defined even as an inlinefunction or a macro. My thought too, so I tried that, but many are still used like so: module_param_call(foo, set_foo, param_get_uint, NULL, 0644); They can all be replaced in time with something like: static int param_get_foo(char *buffer, const struct kernel_param *kp) { return param_ops_uint.get(buffer, kp); } But it'll take a transition period. Thanks! Rusty. > > > thanks, > > Takashi > |
From: Takashi I. <ti...@su...> - 2009-10-30 10:18:29
|
At Fri, 23 Oct 2009 00:51:28 +1030, Rusty Russell wrote: > > This is more kernel-ish, saves some space, and also allows us to > expand the ops without breaking all the callers who are happy for the > new members to be NULL. > > The few places which defined their own param types are changed to the > new scheme. > > Since we're touching them anyway, we change get and set to take a > const struct kernel_param (which they were, and will be again). > > To reduce churn, module_param_call creates the ops struct so the callers > don't have to change (and casts the functions to reduce warnings). > The modern version which takes an ops struct is called module_param_cb. This is nice, as it also reduces the size of struct kernel_param, so each parameter uses less footprint (who cares, though?) :) But, just wondering whether we still need to export get/set functions. They can be called from ops now, so if any, it can be defined even as an inlinefunction or a macro. thanks, Takashi |
From: Janusz K. <jkr...@ti...> - 2009-10-29 23:48:37
|
Thursday 29 October 2009 23:39:44 Janusz Krzysztofik napisał(a): > > Since PM area is quite new to me, I am not sure if there may be a better > solution. AFAICS, the standard way to prevent an ARM_CLKCT1 bit being s/ARM_CLKCT1/ARM_IDLECT1/ > switched to idle is to enable a clock that uses it (tipb_ck, dma_ck, or > tc_ck or one of its children in this case, right?). Janusz |
From: Janusz K. <jkr...@ti...> - 2009-10-29 23:27:25
|
With CONFIG_PM=y, the omapfb/lcd device on Amstrad Delta, after initially starting correctly, breaks with the following error messages: omapfb omapfb: resetting (status 0xffffff96,reset count 1) ... omapfb omapfb: resetting (status 0xffffff96,reset count 100) omapfb omapfb: too many reset attempts, giving up. Looking closer at this I have found that it had been broken almost 2 years ago with commit 2418996e3b100114edb2ae110d5d4acb928909d2, PM fixes for OMAP1. The definite reason for broken omapfb/lcd_ams_delta in PM mode appeared to be ARM_IDLECT1:IDLIF_ARM (bit 6) put into idle. The patch below fixes it. Created and tested against linux-2.6.32-rc5 Signed-off-by: Janusz Krzysztofik <jkr...@ti...> --- Hi, I already reported this issue a few months ago, when drivers/video/omap/lcd_ams_delta.c was proposed to get into mainline - see http://www.spinics.net/lists/linux-omap/msg14546.html. Now I've found some time to look at it again. Since PM area is quite new to me, I am not sure if there may be a better solution. AFAICS, the standard way to prevent an ARM_CLKCT1 bit being switched to idle is to enable a clock that uses it (tipb_ck, dma_ck, or tc_ck or one of its children in this case, right?). I assume there is no bug in omapfb nor lcdc, as that would be already detected. Maybe it would be better to fix drivers/video/omap/lcd_ams_delta.c (or arch/arm/mach-omap1/board-ams-delta), but I don't know what clock should I enable, if any. --- linux-2.6.32-rc5/arch/arm/mach-omap1/pm.c.orig 2009-10-16 02:41:50.000000000 +0200 +++ linux-2.6.32-rc5/arch/arm/mach-omap1/pm.c 2009-10-29 22:07:58.000000000 +0100 @@ -45,6 +45,7 @@ #include <asm/irq.h> #include <asm/atomic.h> +#include <asm/mach-types.h> #include <asm/mach/time.h> #include <asm/mach/irq.h> @@ -139,7 +140,7 @@ void omap1_pm_idle(void) use_idlect1 = omap_dm_timer_modify_idlect_mask(use_idlect1); #endif - if (omap_dma_running()) + if ((omap_dma_running()) || (machine_is_ams_delta())) use_idlect1 &= ~(1 << 6); /* We should be able to remove the do_sleep variable and multiple |
From: Andy S. <and...@gm...> - 2009-10-29 14:55:29
|
From: Andy Shevchenko <ext...@no...> Kernel has simple_strtol() implementation which could be used as atoi(). Signed-off-by: Andy Shevchenko <ext...@no...> --- drivers/video/modedb.c | 24 +++++------------------- 1 files changed, 5 insertions(+), 19 deletions(-) diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 34e4e79..0129f1b 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/fb.h> +#include <linux/kernel.h> #undef DEBUG @@ -402,21 +403,6 @@ const struct fb_videomode vesa_modes[] = { EXPORT_SYMBOL(vesa_modes); #endif /* CONFIG_FB_MODE_HELPERS */ -static int my_atoi(const char *name) -{ - int val = 0; - - for (;; name++) { - switch (*name) { - case '0' ... '9': - val = 10*val+(*name-'0'); - break; - default: - return val; - } - } -} - /** * fb_try_mode - test a video mode * @var: frame buffer user defined part of display @@ -539,7 +525,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, namelen = i; if (!refresh_specified && !bpp_specified && !yres_specified) { - refresh = my_atoi(&name[i+1]); + refresh = simple_strtol(&name[i+1], NULL, 10); refresh_specified = 1; if (cvt || rb) cvt = 0; @@ -549,7 +535,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, case '-': namelen = i; if (!bpp_specified && !yres_specified) { - bpp = my_atoi(&name[i+1]); + bpp = simple_strtol(&name[i+1], NULL, 10); bpp_specified = 1; if (cvt || rb) cvt = 0; @@ -558,7 +544,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, break; case 'x': if (!yres_specified) { - yres = my_atoi(&name[i+1]); + yres = simple_strtol(&name[i+1], NULL, 10); yres_specified = 1; } else goto done; @@ -586,7 +572,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, } } if (i < 0 && yres_specified) { - xres = my_atoi(name); + xres = simple_strtol(name, NULL, 10); res_specified = 1; } done: -- 1.5.6.5 |
From: Claudio S. <cl...@ev...> - 2009-10-29 13:44:01
|
Nicolas Ferre ha scritto: > Hans-Christian Egtvedt : > >> This patch will tell printk the format for irq_base is a decimal and not an >> unsigned long. The irq_base is defined as an int in the struct >> atmel_lcdfb_info. >> > > Hi Hans-Christian, > > I guess this patch is already submitted using the name: > > atmel_lcdfb.c: fix printk() type mismatch > > It goes his way using "trivial" git tree. It is already in linux-next > (baad1b580a7d08a4062a7f50eab0e06f90ad94d6) and I hope it will be > included in 2.6.32-final. > Hi Hans-Christian, I confirm that I sent this patch on October 8th to this list and to LKML too (http://lkml.org/lkml/2009/10/8/67). Then, the patch has been re-sent by Nicolas on October 9th (http://lkml.org/lkml/2009/10/9/86) and finally applied by Jiri Kosina (http://lkml.org/lkml/2009/10/9/218). Many thanks anyway. Best regards, Claudio |
From: Hans-Christian E. <han...@at...> - 2009-10-29 13:25:46
|
On Thu, 29 Oct 2009 14:17:37 +0100 Nicolas Ferre <nic...@at...> wrote: > Hans-Christian Egtvedt : > > This patch will tell printk the format for irq_base is a decimal and not an > > unsigned long. The irq_base is defined as an int in the struct > > atmel_lcdfb_info. > > Hi Hans-Christian, > > I guess this patch is already submitted using the name: > > atmel_lcdfb.c: fix printk() type mismatch > Okay, thanks, sorry for the noise. -- Best regards, Hans-Christian Egtvedt |
From: Paulius Z. <pau...@gm...> - 2009-10-29 13:20:39
|
Hi, After failing to start DirectFB (tries to get and then set current resolution) on my asus eeePC I investigated problem and I found out that it is caused by: static int intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { ... if (FIXED_MODE(dinfo) && (change_var || var->yres_virtual > dinfo->initial_var.yres_virtual || var->yres_virtual < dinfo->initial_var.yres || var->xoffset || var->nonstd)) { if (first) { ERR_MSG("Changing the video mode is not supported.\n"); first = 0; } return -EINVAL; } ... I my situation FIXED_MODE(dinfo) = true, but change_var = false It still fails since dinfo->initial_var.yres_virtual is initialized only once as 0, so var->yres_virtual is always bigger value. Do we need these checks? chnage_var already does size chekings... fbset -accel [true|false] also fails because of this check. Please help me to resolve this issue and we should send patch for stable also. BR, Paulius Zaleckas |
From: Nicolas F. <nic...@at...> - 2009-10-29 13:18:02
|
Hans-Christian Egtvedt : > This patch will tell printk the format for irq_base is a decimal and not an > unsigned long. The irq_base is defined as an int in the struct > atmel_lcdfb_info. Hi Hans-Christian, I guess this patch is already submitted using the name: atmel_lcdfb.c: fix printk() type mismatch It goes his way using "trivial" git tree. It is already in linux-next (baad1b580a7d08a4062a7f50eab0e06f90ad94d6) and I hope it will be included in 2.6.32-final. > Signed-off-by: Hans-Christian Egtvedt <han...@at...> > --- > drivers/video/atmel_lcdfb.c | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c > index 2830ffd..317afab 100644 > --- a/drivers/video/atmel_lcdfb.c > +++ b/drivers/video/atmel_lcdfb.c > @@ -959,7 +959,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) > if (sinfo->atmel_lcdfb_power_control) > sinfo->atmel_lcdfb_power_control(1); > > - dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n", > + dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n", > info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base); > > return 0; Thanks, Bye, -- Nicolas Ferre |
From: Hans-Christian E. <han...@at...> - 2009-10-29 12:36:45
|
This patch will tell printk the format for irq_base is a decimal and not an unsigned long. The irq_base is defined as an int in the struct atmel_lcdfb_info. Signed-off-by: Hans-Christian Egtvedt <han...@at...> --- drivers/video/atmel_lcdfb.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 2830ffd..317afab 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -959,7 +959,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) if (sinfo->atmel_lcdfb_power_control) sinfo->atmel_lcdfb_power_control(1); - dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n", + dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n", info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base); return 0; -- 1.6.0.4 |