musicpal.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,510 行 · 第 1/3 页

C
1,510
字号
};static qemu_irq *mv88w8618_pic_init(uint32_t base, qemu_irq parent_irq){    mv88w8618_pic_state *s;    int iomemtype;    qemu_irq *qi;    s = qemu_mallocz(sizeof(mv88w8618_pic_state));    if (!s)        return NULL;    qi = qemu_allocate_irqs(mv88w8618_pic_set_irq, s, 32);    s->base = base;    s->parent_irq = parent_irq;    iomemtype = cpu_register_io_memory(0, mv88w8618_pic_readfn,                                       mv88w8618_pic_writefn, s);    cpu_register_physical_memory(base, MP_PIC_SIZE, iomemtype);    qemu_register_reset(mv88w8618_pic_reset, s);    return qi;}/* PIT register offsets */#define MP_PIT_TIMER1_LENGTH    0x00/* ... */#define MP_PIT_TIMER4_LENGTH    0x0C#define MP_PIT_CONTROL          0x10#define MP_PIT_TIMER1_VALUE     0x14/* ... */#define MP_PIT_TIMER4_VALUE     0x20#define MP_BOARD_RESET          0x34/* Magic board reset value (probably some watchdog behind it) */#define MP_BOARD_RESET_MAGIC    0x10000typedef struct mv88w8618_timer_state {    ptimer_state *timer;    uint32_t limit;    int freq;    qemu_irq irq;} mv88w8618_timer_state;typedef struct mv88w8618_pit_state {    void *timer[4];    uint32_t control;    uint32_t base;} mv88w8618_pit_state;static void mv88w8618_timer_tick(void *opaque){    mv88w8618_timer_state *s = opaque;    qemu_irq_raise(s->irq);}static void *mv88w8618_timer_init(uint32_t freq, qemu_irq irq){    mv88w8618_timer_state *s;    QEMUBH *bh;    s = qemu_mallocz(sizeof(mv88w8618_timer_state));    s->irq = irq;    s->freq = freq;    bh = qemu_bh_new(mv88w8618_timer_tick, s);    s->timer = ptimer_init(bh);    return s;}static uint32_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset){    mv88w8618_pit_state *s = opaque;    mv88w8618_timer_state *t;    offset -= s->base;    switch (offset) {    case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE:        t = s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2];        return ptimer_get_count(t->timer);    default:        return 0;    }}static void mv88w8618_pit_write(void *opaque, target_phys_addr_t offset,                                uint32_t value){    mv88w8618_pit_state *s = opaque;    mv88w8618_timer_state *t;    int i;    offset -= s->base;    switch (offset) {    case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH:        t = s->timer[offset >> 2];        t->limit = value;        ptimer_set_limit(t->timer, t->limit, 1);        break;    case MP_PIT_CONTROL:        for (i = 0; i < 4; i++) {            if (value & 0xf) {                t = s->timer[i];                ptimer_set_limit(t->timer, t->limit, 0);                ptimer_set_freq(t->timer, t->freq);                ptimer_run(t->timer, 0);            }            value >>= 4;        }        break;    case MP_BOARD_RESET:        if (value == MP_BOARD_RESET_MAGIC)            qemu_system_reset_request();        break;    }}static CPUReadMemoryFunc *mv88w8618_pit_readfn[] = {    mv88w8618_pit_read,    mv88w8618_pit_read,    mv88w8618_pit_read};static CPUWriteMemoryFunc *mv88w8618_pit_writefn[] = {    mv88w8618_pit_write,    mv88w8618_pit_write,    mv88w8618_pit_write};static void mv88w8618_pit_init(uint32_t base, qemu_irq *pic, int irq){    int iomemtype;    mv88w8618_pit_state *s;    s = qemu_mallocz(sizeof(mv88w8618_pit_state));    if (!s)        return;    s->base = base;    /* Letting them all run at 1 MHz is likely just a pragmatic     * simplification. */    s->timer[0] = mv88w8618_timer_init(1000000, pic[irq]);    s->timer[1] = mv88w8618_timer_init(1000000, pic[irq + 1]);    s->timer[2] = mv88w8618_timer_init(1000000, pic[irq + 2]);    s->timer[3] = mv88w8618_timer_init(1000000, pic[irq + 3]);    iomemtype = cpu_register_io_memory(0, mv88w8618_pit_readfn,                                       mv88w8618_pit_writefn, s);    cpu_register_physical_memory(base, MP_PIT_SIZE, iomemtype);}/* Flash config register offsets */#define MP_FLASHCFG_CFGR0    0x04typedef struct mv88w8618_flashcfg_state {    uint32_t base;    uint32_t cfgr0;} mv88w8618_flashcfg_state;static uint32_t mv88w8618_flashcfg_read(void *opaque,                                        target_phys_addr_t offset){    mv88w8618_flashcfg_state *s = opaque;    offset -= s->base;    switch (offset) {    case MP_FLASHCFG_CFGR0:        return s->cfgr0;    default:        return 0;    }}static void mv88w8618_flashcfg_write(void *opaque, target_phys_addr_t offset,                                     uint32_t value){    mv88w8618_flashcfg_state *s = opaque;    offset -= s->base;    switch (offset) {    case MP_FLASHCFG_CFGR0:        s->cfgr0 = value;        break;    }}static CPUReadMemoryFunc *mv88w8618_flashcfg_readfn[] = {    mv88w8618_flashcfg_read,    mv88w8618_flashcfg_read,    mv88w8618_flashcfg_read};static CPUWriteMemoryFunc *mv88w8618_flashcfg_writefn[] = {    mv88w8618_flashcfg_write,    mv88w8618_flashcfg_write,    mv88w8618_flashcfg_write};static void mv88w8618_flashcfg_init(uint32_t base){    int iomemtype;    mv88w8618_flashcfg_state *s;    s = qemu_mallocz(sizeof(mv88w8618_flashcfg_state));    if (!s)        return;    s->base = base;    s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */    iomemtype = cpu_register_io_memory(0, mv88w8618_flashcfg_readfn,                       mv88w8618_flashcfg_writefn, s);    cpu_register_physical_memory(base, MP_FLASHCFG_SIZE, iomemtype);}/* Various registers in the 0x80000000 domain */#define MP_BOARD_REVISION       0x2018#define MP_WLAN_MAGIC1          0xc11c#define MP_WLAN_MAGIC2          0xc124#define MP_GPIO_OE_LO           0xd008#define MP_GPIO_OUT_LO          0xd00c#define MP_GPIO_IN_LO           0xd010#define MP_GPIO_ISR_LO          0xd020#define MP_GPIO_OE_HI           0xd508#define MP_GPIO_OUT_HI          0xd50c#define MP_GPIO_IN_HI           0xd510#define MP_GPIO_ISR_HI          0xd520/* GPIO bits & masks */#define MP_GPIO_WHEEL_VOL       (1 << 8)#define MP_GPIO_WHEEL_VOL_INV   (1 << 9)#define MP_GPIO_WHEEL_NAV       (1 << 10)#define MP_GPIO_WHEEL_NAV_INV   (1 << 11)#define MP_GPIO_LCD_BRIGHTNESS  0x00070000#define MP_GPIO_BTN_FAVORITS    (1 << 19)#define MP_GPIO_BTN_MENU        (1 << 20)#define MP_GPIO_BTN_VOLUME      (1 << 21)#define MP_GPIO_BTN_NAVIGATION  (1 << 22)#define MP_GPIO_I2C_DATA_BIT    29#define MP_GPIO_I2C_DATA        (1 << MP_GPIO_I2C_DATA_BIT)#define MP_GPIO_I2C_CLOCK_BIT   30/* LCD brightness bits in GPIO_OE_HI */#define MP_OE_LCD_BRIGHTNESS    0x0007static uint32_t musicpal_read(void *opaque, target_phys_addr_t offset){    offset -= 0x80000000;    switch (offset) {    case MP_BOARD_REVISION:        return 0x0031;    case MP_GPIO_OE_HI: /* used for LCD brightness control */        return lcd_brightness & MP_OE_LCD_BRIGHTNESS;    case MP_GPIO_OUT_LO:        return gpio_out_state & 0xFFFF;    case MP_GPIO_OUT_HI:        return gpio_out_state >> 16;    case MP_GPIO_IN_LO:        return gpio_in_state & 0xFFFF;    case MP_GPIO_IN_HI:        /* Update received I2C data */        gpio_in_state = (gpio_in_state & ~MP_GPIO_I2C_DATA) |                        (i2c_get_data(mixer_i2c) << MP_GPIO_I2C_DATA_BIT);        return gpio_in_state >> 16;    /* This is a simplification of reality */    case MP_GPIO_ISR_LO:        return ~gpio_in_state & 0xFFFF;    case MP_GPIO_ISR_HI:        return ~gpio_in_state >> 16;    /* Workaround to allow loading the binary-only wlandrv.ko crap     * from the original Freecom firmware. */    case MP_WLAN_MAGIC1:        return ~3;    case MP_WLAN_MAGIC2:        return -1;    default:        return 0;    }}static void musicpal_write(void *opaque, target_phys_addr_t offset,                           uint32_t value){    offset -= 0x80000000;    switch (offset) {    case MP_GPIO_OE_HI: /* used for LCD brightness control */        lcd_brightness = (lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) |                         (value & MP_OE_LCD_BRIGHTNESS);        break;    case MP_GPIO_OUT_LO:        gpio_out_state = (gpio_out_state & 0xFFFF0000) | (value & 0xFFFF);        break;    case MP_GPIO_OUT_HI:        gpio_out_state = (gpio_out_state & 0xFFFF) | (value << 16);        lcd_brightness = (lcd_brightness & 0xFFFF) |                         (gpio_out_state & MP_GPIO_LCD_BRIGHTNESS);        i2c_state_update(mixer_i2c,                         (gpio_out_state >> MP_GPIO_I2C_DATA_BIT) & 1,                         (gpio_out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1);        break;    }}/* Keyboard codes & masks */#define KEY_PRESSED             0x80#define KEY_CODE                0x7f#define KEYCODE_TAB             0x0f#define KEYCODE_ENTER           0x1c#define KEYCODE_F               0x21#define KEYCODE_M               0x32#define KEYCODE_EXTENDED        0xe0#define KEYCODE_UP              0x48#define KEYCODE_DOWN            0x50#define KEYCODE_LEFT            0x4b#define KEYCODE_RIGHT           0x4dstatic void musicpal_key_event(void *opaque, int keycode){    qemu_irq irq = opaque;    uint32_t event = 0;    static int kbd_extended;    if (keycode == KEYCODE_EXTENDED) {        kbd_extended = 1;        return;    }    if (kbd_extended)        switch (keycode & KEY_CODE) {        case KEYCODE_UP:            event = MP_GPIO_WHEEL_NAV | MP_GPIO_WHEEL_NAV_INV;            break;        case KEYCODE_DOWN:            event = MP_GPIO_WHEEL_NAV;            break;        case KEYCODE_LEFT:            event = MP_GPIO_WHEEL_VOL | MP_GPIO_WHEEL_VOL_INV;            break;        case KEYCODE_RIGHT:            event = MP_GPIO_WHEEL_VOL;            break;        }    else        switch (keycode & KEY_CODE) {        case KEYCODE_F:            event = MP_GPIO_BTN_FAVORITS;            break;        case KEYCODE_TAB:            event = MP_GPIO_BTN_VOLUME;            break;        case KEYCODE_ENTER:            event = MP_GPIO_BTN_NAVIGATION;            break;        case KEYCODE_M:            event = MP_GPIO_BTN_MENU;            break;        }    if (keycode & KEY_PRESSED)        gpio_in_state |= event;    else if (gpio_in_state & event) {        gpio_in_state &= ~event;        qemu_irq_raise(irq);    }    kbd_extended = 0;}static CPUReadMemoryFunc *musicpal_readfn[] = {    musicpal_read,    musicpal_read,    musicpal_read,};static CPUWriteMemoryFunc *musicpal_writefn[] = {    musicpal_write,    musicpal_write,    musicpal_write,};static struct arm_boot_info musicpal_binfo = {    .loader_start = 0x0,    .board_id = 0x20e,};static void musicpal_init(ram_addr_t ram_size, int vga_ram_size,               const char *boot_device, DisplayState *ds,               const char *kernel_filename, const char *kernel_cmdline,               const char *initrd_filename, const char *cpu_model){    CPUState *env;    qemu_irq *pic;    int index;    int iomemtype;    unsigned long flash_size;    if (!cpu_model)        cpu_model = "arm926";    env = cpu_init(cpu_model);    if (!env) {        fprintf(stderr, "Unable to find CPU definition\n");        exit(1);    }    pic = arm_pic_init_cpu(env);    /* For now we use a fixed - the original - RAM size */    cpu_register_physical_memory(0, MP_RAM_DEFAULT_SIZE,                                 qemu_ram_alloc(MP_RAM_DEFAULT_SIZE));    sram_off = qemu_ram_alloc(MP_SRAM_SIZE);    cpu_register_physical_memory(MP_SRAM_BASE, MP_SRAM_SIZE, sram_off);    /* Catch various stuff not handled by separate subsystems */    iomemtype = cpu_register_io_memory(0, musicpal_readfn,                                       musicpal_writefn, env);    cpu_register_physical_memory(0x80000000, 0x10000, iomemtype);    pic = mv88w8618_pic_init(MP_PIC_BASE, pic[ARM_PIC_CPU_IRQ]);    mv88w8618_pit_init(MP_PIT_BASE, pic, MP_TIMER1_IRQ);    if (serial_hds[0])        serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000,                   serial_hds[0], 1);    if (serial_hds[1])        serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000,                   serial_hds[1], 1);    /* Register flash */    index = drive_get_index(IF_PFLASH, 0, 0);    if (index != -1) {        flash_size = bdrv_getlength(drives_table[index].bdrv);        if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 &&            flash_size != 32*1024*1024) {            fprintf(stderr, "Invalid flash image size\n");            exit(1);        }        /*         * The original U-Boot accesses the flash at 0xFE000000 instead of         * 0xFF800000 (if there is 8 MB flash). So remap flash access if the         * image is smaller than 32 MB.         */        pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, qemu_ram_alloc(flash_size),                              drives_table[index].bdrv, 0x10000,                              (flash_size + 0xffff) >> 16,                              MP_FLASH_SIZE_MAX / flash_size,                              2, 0x00BF, 0x236D, 0x0000, 0x0000,                              0x5555, 0x2AAA);    }    mv88w8618_flashcfg_init(MP_FLASHCFG_BASE);    musicpal_lcd_init(ds, MP_LCD_BASE);    qemu_add_kbd_event_handler(musicpal_key_event, pic[MP_GPIO_IRQ]);    /*     * Wait a bit to catch menu button during U-Boot start-up     * (to trigger emergency update).     */    sleep(1);    mv88w8618_eth_init(&nd_table[0], MP_ETH_BASE, pic[MP_ETH_IRQ]);    mixer_i2c = musicpal_audio_init(MP_AUDIO_BASE, pic[MP_AUDIO_IRQ]);    musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE;    musicpal_binfo.kernel_filename = kernel_filename;    musicpal_binfo.kernel_cmdline = kernel_cmdline;    musicpal_binfo.initrd_filename = initrd_filename;    arm_load_kernel(env, &musicpal_binfo);}QEMUMachine musicpal_machine = {    "musicpal",    "Marvell 88w8618 / MusicPal (ARM926EJ-S)",    musicpal_init,    MP_RAM_DEFAULT_SIZE + MP_SRAM_SIZE + MP_FLASH_SIZE_MAX + RAMSIZE_FIXED};

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?