Recent Posts

2011年9月17日星期六

ClockworkMod Recovery for Acer Stream

Download here (Warning! Very experimental. Use at your own risk.)

Install:
Use fastboot (or Rom Manager?) to flash the recovery image. See ClockworkMod Recovery for more information.


Acer Stream 這隻手機,就像 Kindle DX 一樣,出來時也都算風風光光,也一度是名義上的旗艦機種,但因為銷售不理想,很快都被原廠打入冷宮,停止更新。現在完全找不到 Acer Stream 的 Custom Rom,所以,只好自力救濟一下了。由於我對 Android custom rom 幾乎毫無經驗,所以先從 Recovery image 開始。
Acer Stream 的特點:
  • image header 是 4K
  • Framebuffer 的 bits per pixel 似乎固定為 32。VSCREENINFO 傳回的 xres 和 yres 不可靠,預設是 1280x800, 但其實 lcd 的解析度是 480x800。OS_RESOLUTION 的傳回值才是對的。framebuffer 的 第二頁的起始值固定在 1280x800x4 bytes 的位置。大部分 recovery image 畫面會壞掉的原因在此。我猜大概要支援 HDMI 的緣故。
  • /data 不是 mtd@userdata 而是 mmcblk1p1 。
原本打算用 malez recovery 來改,但發現好像沒有提供 source。所以抓了野火機的 ClockworkMod Recovery Image,並且抓下 source 重新編譯 recovery。(主要的困難是 kernel.org 被駭,花了一點時間才抓到完整的 source。)
我只修改了 graphics.c ,修改的部份如下:
    if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
        perror("failed to get fb0 info");
        close(fd);
        return -1;
    }
    // should use OS_RESOLUTION ioctl to get xres
    vi.xres=480;

    bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (bits == MAP_FAILED) {
        perror("failed to mmap framebuffer");
        close(fd);
        return -1;
    }

    fb->version = sizeof(*fb);
    fb->width = vi.xres;
    fb->height = vi.yres;
    fb->stride = vi.xres;
    fb->data = bits;
    fb->format = GGL_PIXEL_FORMAT_RGBX_8888;
    memset(fb->data, 0, vi.yres * vi.xres * 4);

    fb++;

    fb->version = sizeof(*fb);
    fb->width = vi.xres;
    fb->height = vi.yres;
    fb->stride = vi.xres;
    fb->data = (void*) (((unsigned) bits) + (fi.smem_len>>1));
    fb->format = GGL_PIXEL_FORMAT_RGBX_8888;
    memset(fb->data, 0, vi.yres * vi.xres * 4);

    return fd;
}

static void get_memory_surface(GGLSurface* ms) {
  ms->version = sizeof(*ms);
  ms->width = vi.xres;
  ms->height = vi.yres;
  ms->stride = vi.xres;
  ms->data = malloc(vi.xres * vi.yres * 4);
  ms->format = GGL_PIXEL_FORMAT_RGBX_8888;
}

static void set_active_framebuffer(unsigned n)
{
    if (n > 1) return;
    vi.yoffset = n * vi.yres;
    if (ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
        printf("active fb swap failed %d\n", n);
    }
}

void gr_flip(void)
{
    GGLContext *gl = gr_context;

    /* swap front and back buffers */
    gr_active_fb = (gr_active_fb + 1) & 1;

    /* copy data from the in-memory surface to the buffer we're about
     * to make active. */
    memcpy(gr_framebuffer[gr_active_fb].data, gr_mem_surface.data,
           vi.xres * vi.yres * 4);

    /* inform the display driver */
    set_active_framebuffer(gr_active_fb);
}
張貼留言