?? spitz.c
字號:
/* * PXA270-based Clamshell PDA platforms. * * Copyright (c) 2006 Openedhand Ltd. * Written by Andrzej Zaborowski <balrog@zabor.org> * * This code is licensed under the GNU GPL v2. */#include "hw.h"#include "pxa.h"#include "arm-misc.h"#include "sysemu.h"#include "pcmcia.h"#include "i2c.h"#include "flash.h"#include "qemu-timer.h"#include "devices.h"#include "console.h"#include "block.h"#include "audio/audio.h"#include "boards.h"#define spitz_printf(format, ...) \ fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__)#undef REG_FMT#if TARGET_PHYS_ADDR_BITS == 32#define REG_FMT "0x%02x"#else#define REG_FMT "0x%02lx"#endif/* Spitz Flash */#define FLASH_BASE 0x0c000000#define FLASH_ECCLPLB 0x00 /* Line parity 7 - 0 bit */#define FLASH_ECCLPUB 0x04 /* Line parity 15 - 8 bit */#define FLASH_ECCCP 0x08 /* Column parity 5 - 0 bit */#define FLASH_ECCCNTR 0x0c /* ECC byte counter */#define FLASH_ECCCLRR 0x10 /* Clear ECC */#define FLASH_FLASHIO 0x14 /* Flash I/O */#define FLASH_FLASHCTL 0x18 /* Flash Control */#define FLASHCTL_CE0 (1 << 0)#define FLASHCTL_CLE (1 << 1)#define FLASHCTL_ALE (1 << 2)#define FLASHCTL_WP (1 << 3)#define FLASHCTL_CE1 (1 << 4)#define FLASHCTL_RYBY (1 << 5)#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1)struct sl_nand_s { target_phys_addr_t target_base; struct nand_flash_s *nand; uint8_t ctl; struct ecc_state_s ecc;};static uint32_t sl_readb(void *opaque, target_phys_addr_t addr){ struct sl_nand_s *s = (struct sl_nand_s *) opaque; int ryby; addr -= s->target_base; switch (addr) {#define BSHR(byte, from, to) ((s->ecc.lp[byte] >> (from - to)) & (1 << to)) case FLASH_ECCLPLB: return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) | BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7);#define BSHL(byte, from, to) ((s->ecc.lp[byte] << (to - from)) & (1 << to)) case FLASH_ECCLPUB: return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) | BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7); case FLASH_ECCCP: return s->ecc.cp; case FLASH_ECCCNTR: return s->ecc.count & 0xff; case FLASH_FLASHCTL: nand_getpins(s->nand, &ryby); if (ryby) return s->ctl | FLASHCTL_RYBY; else return s->ctl; case FLASH_FLASHIO: return ecc_digest(&s->ecc, nand_getio(s->nand)); default: spitz_printf("Bad register offset " REG_FMT "\n", addr); } return 0;}static uint32_t sl_readl(void *opaque, target_phys_addr_t addr){ struct sl_nand_s *s = (struct sl_nand_s *) opaque; addr -= s->target_base; if (addr == FLASH_FLASHIO) return ecc_digest(&s->ecc, nand_getio(s->nand)) | (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16); return sl_readb(opaque, addr);}static void sl_writeb(void *opaque, target_phys_addr_t addr, uint32_t value){ struct sl_nand_s *s = (struct sl_nand_s *) opaque; addr -= s->target_base; switch (addr) { case FLASH_ECCCLRR: /* Value is ignored. */ ecc_reset(&s->ecc); break; case FLASH_FLASHCTL: s->ctl = value & 0xff & ~FLASHCTL_RYBY; nand_setpins(s->nand, s->ctl & FLASHCTL_CLE, s->ctl & FLASHCTL_ALE, s->ctl & FLASHCTL_NCE, s->ctl & FLASHCTL_WP, 0); break; case FLASH_FLASHIO: nand_setio(s->nand, ecc_digest(&s->ecc, value & 0xff)); break; default: spitz_printf("Bad register offset " REG_FMT "\n", addr); }}static void sl_save(QEMUFile *f, void *opaque){ struct sl_nand_s *s = (struct sl_nand_s *) opaque; qemu_put_8s(f, &s->ctl); ecc_put(f, &s->ecc);}static int sl_load(QEMUFile *f, void *opaque, int version_id){ struct sl_nand_s *s = (struct sl_nand_s *) opaque; qemu_get_8s(f, &s->ctl); ecc_get(f, &s->ecc); return 0;}enum { FLASH_128M, FLASH_1024M,};static void sl_flash_register(struct pxa2xx_state_s *cpu, int size){ int iomemtype; struct sl_nand_s *s; CPUReadMemoryFunc *sl_readfn[] = { sl_readb, sl_readb, sl_readl, }; CPUWriteMemoryFunc *sl_writefn[] = { sl_writeb, sl_writeb, sl_writeb, }; s = (struct sl_nand_s *) qemu_mallocz(sizeof(struct sl_nand_s)); s->target_base = FLASH_BASE; s->ctl = 0; if (size == FLASH_128M) s->nand = nand_init(NAND_MFR_SAMSUNG, 0x73); else if (size == FLASH_1024M) s->nand = nand_init(NAND_MFR_SAMSUNG, 0xf1); iomemtype = cpu_register_io_memory(0, sl_readfn, sl_writefn, s); cpu_register_physical_memory(s->target_base, 0x40, iomemtype); register_savevm("sl_flash", 0, 0, sl_save, sl_load, s);}/* Spitz Keyboard */#define SPITZ_KEY_STROBE_NUM 11#define SPITZ_KEY_SENSE_NUM 7static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = { 12, 17, 91, 34, 36, 38, 39};static const int spitz_gpio_key_strobe[SPITZ_KEY_STROBE_NUM] = { 88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114};/* Eighth additional row maps the special keys */static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = { { 0x1d, 0x02, 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x3f, 0x40 }, { -1 , 0x03, 0x05, 0x13, 0x15, 0x09, 0x17, 0x18, 0x19, 0x41, 0x42 }, { 0x0f, 0x10, 0x12, 0x14, 0x22, 0x16, 0x24, 0x25, -1 , -1 , -1 }, { 0x3c, 0x11, 0x1f, 0x21, 0x2f, 0x23, 0x32, 0x26, -1 , 0x36, -1 }, { 0x3b, 0x1e, 0x20, 0x2e, 0x30, 0x31, 0x34, -1 , 0x1c, 0x2a, -1 }, { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33, -1 , 0x48, -1 , -1 , 0x38 }, { 0x37, 0x3d, -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d, -1 , -1 }, { 0x52, 0x43, 0x01, 0x47, 0x49, -1 , -1 , -1 , -1 , -1 , -1 },};#define SPITZ_GPIO_AK_INT 13 /* Remote control */#define SPITZ_GPIO_SYNC 16 /* Sync button */#define SPITZ_GPIO_ON_KEY 95 /* Power button */#define SPITZ_GPIO_SWA 97 /* Lid */#define SPITZ_GPIO_SWB 96 /* Tablet mode *//* The special buttons are mapped to unused keys */static const int spitz_gpiomap[5] = { SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY, SPITZ_GPIO_SWA, SPITZ_GPIO_SWB,};static int spitz_gpio_invert[5] = { 0, 0, 0, 0, 0, };struct spitz_keyboard_s { qemu_irq sense[SPITZ_KEY_SENSE_NUM]; qemu_irq *strobe; qemu_irq gpiomap[5]; int keymap[0x80]; uint16_t keyrow[SPITZ_KEY_SENSE_NUM]; uint16_t strobe_state; uint16_t sense_state; uint16_t pre_map[0x100]; uint16_t modifiers; uint16_t imodifiers; uint8_t fifo[16]; int fifopos, fifolen; QEMUTimer *kbdtimer;};static void spitz_keyboard_sense_update(struct spitz_keyboard_s *s){ int i; uint16_t strobe, sense = 0; for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) { strobe = s->keyrow[i] & s->strobe_state; if (strobe) { sense |= 1 << i; if (!(s->sense_state & (1 << i))) qemu_irq_raise(s->sense[i]); } else if (s->sense_state & (1 << i)) qemu_irq_lower(s->sense[i]); } s->sense_state = sense;}static void spitz_keyboard_strobe(void *opaque, int line, int level){ struct spitz_keyboard_s *s = (struct spitz_keyboard_s *) opaque; if (level) s->strobe_state |= 1 << line; else s->strobe_state &= ~(1 << line); spitz_keyboard_sense_update(s);}static void spitz_keyboard_keydown(struct spitz_keyboard_s *s, int keycode){ int spitz_keycode = s->keymap[keycode & 0x7f]; if (spitz_keycode == -1) return; /* Handle the additional keys */ if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) { qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80) ^ spitz_gpio_invert[spitz_keycode & 0xf]); return; } if (keycode & 0x80) s->keyrow[spitz_keycode >> 4] &= ~(1 << (spitz_keycode & 0xf)); else s->keyrow[spitz_keycode >> 4] |= 1 << (spitz_keycode & 0xf); spitz_keyboard_sense_update(s);}#define SHIFT (1 << 7)#define CTRL (1 << 8)#define FN (1 << 9)#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = cstatic void spitz_keyboard_handler(struct spitz_keyboard_s *s, int keycode){ uint16_t code; int mapcode; switch (keycode) { case 0x2a: /* Left Shift */ s->modifiers |= 1; break; case 0xaa: s->modifiers &= ~1; break; case 0x36: /* Right Shift */ s->modifiers |= 2; break; case 0xb6: s->modifiers &= ~2; break; case 0x1d: /* Control */ s->modifiers |= 4; break; case 0x9d: s->modifiers &= ~4; break; case 0x38: /* Alt */ s->modifiers |= 8; break; case 0xb8: s->modifiers &= ~8; break; } code = s->pre_map[mapcode = ((s->modifiers & 3) ? (keycode | SHIFT) : (keycode & ~SHIFT))]; if (code != mapcode) {#if 0 if ((code & SHIFT) && !(s->modifiers & 1)) QUEUE_KEY(0x2a | (keycode & 0x80)); if ((code & CTRL ) && !(s->modifiers & 4)) QUEUE_KEY(0x1d | (keycode & 0x80)); if ((code & FN ) && !(s->modifiers & 8)) QUEUE_KEY(0x38 | (keycode & 0x80)); if ((code & FN ) && (s->modifiers & 1)) QUEUE_KEY(0x2a | (~keycode & 0x80)); if ((code & FN ) && (s->modifiers & 2)) QUEUE_KEY(0x36 | (~keycode & 0x80));#else if (keycode & 0x80) { if ((s->imodifiers & 1 ) && !(s->modifiers & 1)) QUEUE_KEY(0x2a | 0x80); if ((s->imodifiers & 4 ) && !(s->modifiers & 4)) QUEUE_KEY(0x1d | 0x80); if ((s->imodifiers & 8 ) && !(s->modifiers & 8)) QUEUE_KEY(0x38 | 0x80); if ((s->imodifiers & 0x10) && (s->modifiers & 1)) QUEUE_KEY(0x2a); if ((s->imodifiers & 0x20) && (s->modifiers & 2)) QUEUE_KEY(0x36); s->imodifiers = 0; } else { if ((code & SHIFT) && !((s->modifiers | s->imodifiers) & 1)) { QUEUE_KEY(0x2a); s->imodifiers |= 1; } if ((code & CTRL ) && !((s->modifiers | s->imodifiers) & 4)) { QUEUE_KEY(0x1d); s->imodifiers |= 4; } if ((code & FN ) && !((s->modifiers | s->imodifiers) & 8)) { QUEUE_KEY(0x38); s->imodifiers |= 8; } if ((code & FN ) && (s->modifiers & 1) && !(s->imodifiers & 0x10)) { QUEUE_KEY(0x2a | 0x80); s->imodifiers |= 0x10; } if ((code & FN ) && (s->modifiers & 2) && !(s->imodifiers & 0x20)) { QUEUE_KEY(0x36 | 0x80); s->imodifiers |= 0x20; } }#endif } QUEUE_KEY((code & 0x7f) | (keycode & 0x80));}static void spitz_keyboard_tick(void *opaque){ struct spitz_keyboard_s *s = (struct spitz_keyboard_s *) opaque; if (s->fifolen) { spitz_keyboard_keydown(s, s->fifo[s->fifopos ++]); s->fifolen --; if (s->fifopos >= 16) s->fifopos = 0; } qemu_mod_timer(s->kbdtimer, qemu_get_clock(vm_clock) + ticks_per_sec / 32);}static void spitz_keyboard_pre_map(struct spitz_keyboard_s *s){ int i; for (i = 0; i < 0x100; i ++) s->pre_map[i] = i; s->pre_map[0x02 | SHIFT ] = 0x02 | SHIFT; /* exclam */ s->pre_map[0x28 | SHIFT ] = 0x03 | SHIFT; /* quotedbl */ s->pre_map[0x04 | SHIFT ] = 0x04 | SHIFT; /* numbersign */ s->pre_map[0x05 | SHIFT ] = 0x05 | SHIFT; /* dollar */ s->pre_map[0x06 | SHIFT ] = 0x06 | SHIFT; /* percent */ s->pre_map[0x08 | SHIFT ] = 0x07 | SHIFT; /* ampersand */ s->pre_map[0x28 ] = 0x08 | SHIFT; /* apostrophe */ s->pre_map[0x0a | SHIFT ] = 0x09 | SHIFT; /* parenleft */ s->pre_map[0x0b | SHIFT ] = 0x0a | SHIFT; /* parenright */ s->pre_map[0x29 | SHIFT ] = 0x0b | SHIFT; /* asciitilde */ s->pre_map[0x03 | SHIFT ] = 0x0c | SHIFT; /* at */ s->pre_map[0xd3 ] = 0x0e | FN; /* Delete */ s->pre_map[0x3a ] = 0x0f | FN; /* Caps_Lock */ s->pre_map[0x07 | SHIFT ] = 0x11 | FN; /* asciicircum */ s->pre_map[0x0d ] = 0x12 | FN; /* equal */ s->pre_map[0x0d | SHIFT ] = 0x13 | FN; /* plus */ s->pre_map[0x1a ] = 0x14 | FN; /* bracketleft */ s->pre_map[0x1b ] = 0x15 | FN; /* bracketright */ s->pre_map[0x1a | SHIFT ] = 0x16 | FN; /* braceleft */ s->pre_map[0x1b | SHIFT ] = 0x17 | FN; /* braceright */ s->pre_map[0x27 ] = 0x22 | FN; /* semicolon */ s->pre_map[0x27 | SHIFT ] = 0x23 | FN; /* colon */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -