Annotation of qemu/hw/ssd0303.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * SSD0303 OLED controller with OSRAM Pictiva 96x16 display.
                      3:  *
                      4:  * Copyright (c) 2006-2007 CodeSourcery.
                      5:  * Written by Paul Brook
                      6:  *
                      7:  * This code is licenced under the GPL.
                      8:  */
                      9: 
                     10: /* The controller can support a variety of different displays, but we only
                     11:    implement one.  Most of the commends relating to brightness and geometry
                     12:    setup are ignored. */
                     13: #include "hw.h"
                     14: #include "i2c.h"
                     15: #include "console.h"
                     16: 
                     17: //#define DEBUG_SSD0303 1
                     18: 
                     19: #ifdef DEBUG_SSD0303
                     20: #define DPRINTF(fmt, args...) \
                     21: do { printf("ssd0303: " fmt , ##args); } while (0)
                     22: #define BADF(fmt, args...) \
                     23: do { fprintf(stderr, "ssd0303: error: " fmt , ##args); exit(1);} while (0)
                     24: #else
                     25: #define DPRINTF(fmt, args...) do {} while(0)
                     26: #define BADF(fmt, args...) \
                     27: do { fprintf(stderr, "ssd0303: error: " fmt , ##args);} while (0)
                     28: #endif
                     29: 
                     30: /* Scaling factor for pixels.  */
                     31: #define MAGNIFY 4
                     32: 
                     33: enum ssd0303_mode
                     34: {
                     35:     SSD0303_IDLE,
                     36:     SSD0303_DATA,
                     37:     SSD0303_CMD
                     38: };
                     39: 
                     40: enum ssd0303_cmd {
                     41:     SSD0303_CMD_NONE,
                     42:     SSD0303_CMD_SKIP1
                     43: };
                     44: 
                     45: typedef struct {
                     46:     i2c_slave i2c;
                     47:     DisplayState *ds;
                     48:     int row;
                     49:     int col;
                     50:     int start_line;
                     51:     int mirror;
                     52:     int flash;
                     53:     int enabled;
                     54:     int inverse;
                     55:     int redraw;
                     56:     enum ssd0303_mode mode;
                     57:     enum ssd0303_cmd cmd_state;
                     58:     uint8_t framebuffer[132*8];
                     59: } ssd0303_state;
                     60: 
                     61: static int ssd0303_recv(i2c_slave *i2c)
                     62: {
                     63:     BADF("Reads not implemented\n");
                     64:     return -1;
                     65: }
                     66: 
                     67: static int ssd0303_send(i2c_slave *i2c, uint8_t data)
                     68: {
                     69:     ssd0303_state *s = (ssd0303_state *)i2c;
                     70:     enum ssd0303_cmd old_cmd_state;
                     71:     switch (s->mode) {
                     72:     case SSD0303_IDLE:
                     73:         DPRINTF("byte 0x%02x\n", data);
                     74:         if (data == 0x80)
                     75:             s->mode = SSD0303_CMD;
                     76:         else if (data == 0x40)
                     77:             s->mode = SSD0303_DATA;
                     78:         else
                     79:             BADF("Unexpected byte 0x%x\n", data);
                     80:         break;
                     81:     case SSD0303_DATA:
                     82:         DPRINTF("data 0x%02x\n", data);
                     83:         if (s->col < 132) {
                     84:             s->framebuffer[s->col + s->row * 132] = data;
                     85:             s->col++;
                     86:             s->redraw = 1;
                     87:         }
                     88:         break;
                     89:     case SSD0303_CMD:
                     90:         old_cmd_state = s->cmd_state;
                     91:         s->cmd_state = SSD0303_CMD_NONE;
                     92:         switch (old_cmd_state) {
                     93:         case SSD0303_CMD_NONE:
                     94:             DPRINTF("cmd 0x%02x\n", data);
                     95:             s->mode = SSD0303_IDLE;
                     96:             switch (data) {
                     97:             case 0x00 ... 0x0f: /* Set lower colum address.  */
                     98:                 s->col = (s->col & 0xf0) | (data & 0xf);
                     99:                 break;
                    100:             case 0x10 ... 0x20: /* Set higher column address.  */
                    101:                 s->col = (s->col & 0x0f) | ((data & 0xf) << 4);
                    102:                 break;
                    103:             case 0x40 ... 0x7f: /* Set start line.  */
                    104:                 s->start_line = 0;
                    105:                 break;
                    106:             case 0x81: /* Set contrast (Ignored).  */
                    107:                 s->cmd_state = SSD0303_CMD_SKIP1;
                    108:                 break;
                    109:             case 0xa0: /* Mirror off.  */
                    110:                 s->mirror = 0;
                    111:                 break;
                    112:             case 0xa1: /* Mirror off.  */
                    113:                 s->mirror = 1;
                    114:                 break;
                    115:             case 0xa4: /* Entire display off.  */
                    116:                 s->flash = 0;
                    117:                 break;
                    118:             case 0xa5: /* Entire display on.  */
                    119:                 s->flash = 1;
                    120:                 break;
                    121:             case 0xa6: /* Inverse off.  */
                    122:                 s->inverse = 0;
                    123:                 break;
                    124:             case 0xa7: /* Inverse on.  */
                    125:                 s->inverse = 1;
                    126:                 break;
                    127:             case 0xa8: /* Set multipled ratio (Ignored).  */
                    128:                 s->cmd_state = SSD0303_CMD_SKIP1;
                    129:                 break;
                    130:             case 0xad: /* DC-DC power control.  */
                    131:                 s->cmd_state = SSD0303_CMD_SKIP1;
                    132:                 break;
                    133:             case 0xae: /* Display off.  */
                    134:                 s->enabled = 0;
                    135:                 break;
                    136:             case 0xaf: /* Display on.  */
                    137:                 s->enabled = 1;
                    138:                 break;
                    139:             case 0xb0 ... 0xbf: /* Set Page address.  */
                    140:                 s->row = data & 7;
                    141:                 break;
                    142:             case 0xc0 ... 0xc8: /* Set COM output direction (Ignored).  */
                    143:                 break;
                    144:             case 0xd3: /* Set display offset (Ignored).  */
                    145:                 s->cmd_state = SSD0303_CMD_SKIP1;
                    146:                 break;
                    147:             case 0xd5: /* Set display clock (Ignored).  */
                    148:                 s->cmd_state = SSD0303_CMD_SKIP1;
                    149:                 break;
                    150:             case 0xd8: /* Set color and power mode (Ignored).  */
                    151:                 s->cmd_state = SSD0303_CMD_SKIP1;
                    152:                 break;
                    153:             case 0xd9: /* Set pre-charge period (Ignored).  */
                    154:                 s->cmd_state = SSD0303_CMD_SKIP1;
                    155:                 break;
                    156:             case 0xda: /* Set COM pin configuration (Ignored).  */
                    157:                 s->cmd_state = SSD0303_CMD_SKIP1;
                    158:                 break;
                    159:             case 0xdb: /* Set VCOM dselect level (Ignored).  */
                    160:                 s->cmd_state = SSD0303_CMD_SKIP1;
                    161:                 break;
                    162:             case 0xe3: /* no-op.  */
                    163:                 break;
                    164:             default:
                    165:                 BADF("Unknown command: 0x%x\n", data);
                    166:             }
                    167:             break;
                    168:         case SSD0303_CMD_SKIP1:
                    169:             DPRINTF("skip 0x%02x\n", data);
                    170:             break;
                    171:         }
                    172:         break;
                    173:     }
                    174:     return 0;
                    175: }
                    176: 
                    177: static void ssd0303_event(i2c_slave *i2c, enum i2c_event event)
                    178: {
                    179:     ssd0303_state *s = (ssd0303_state *)i2c;
                    180:     switch (event) {
                    181:     case I2C_FINISH:
                    182:         s->mode = SSD0303_IDLE;
                    183:         break;
                    184:     case I2C_START_RECV:
                    185:     case I2C_START_SEND:
                    186:     case I2C_NACK:
                    187:         /* Nothing to do.  */
                    188:         break;
                    189:     }
                    190: }
                    191: 
                    192: static void ssd0303_update_display(void *opaque)
                    193: {
                    194:     ssd0303_state *s = (ssd0303_state *)opaque;
                    195:     uint8_t *dest;
                    196:     uint8_t *src;
                    197:     int x;
                    198:     int y;
                    199:     int line;
                    200:     char *colors[2];
                    201:     char colortab[MAGNIFY * 8];
                    202:     int dest_width;
                    203:     uint8_t mask;
                    204: 
1.1.1.2 ! root      205:     if (!s->redraw)
        !           206:         return;
        !           207: 
        !           208:     switch (ds_get_bits_per_pixel(s->ds)) {
        !           209:     case 0:
        !           210:         return;
        !           211:     case 15:
        !           212:         dest_width = 2;
        !           213:         break;
        !           214:     case 16:
        !           215:         dest_width = 2;
        !           216:         break;
        !           217:     case 24:
        !           218:         dest_width = 3;
        !           219:         break;
        !           220:     case 32:
        !           221:         dest_width = 4;
        !           222:         break;
        !           223:     default:
        !           224:         BADF("Bad color depth\n");
        !           225:         return;
        !           226:     }
        !           227:     dest_width *= MAGNIFY;
        !           228:     memset(colortab, 0xff, dest_width);
        !           229:     memset(colortab + dest_width, 0, dest_width);
        !           230:     if (s->flash) {
        !           231:         colors[0] = colortab;
        !           232:         colors[1] = colortab;
        !           233:     } else if (s->inverse) {
        !           234:         colors[0] = colortab;
        !           235:         colors[1] = colortab + dest_width;
        !           236:     } else {
        !           237:         colors[0] = colortab + dest_width;
        !           238:         colors[1] = colortab;
        !           239:     }
        !           240:     dest = ds_get_data(s->ds);
        !           241:     for (y = 0; y < 16; y++) {
        !           242:         line = (y + s->start_line) & 63;
        !           243:         src = s->framebuffer + 132 * (line >> 3) + 36;
        !           244:         mask = 1 << (line & 7);
        !           245:         for (x = 0; x < 96; x++) {
        !           246:             memcpy(dest, colors[(*src & mask) != 0], dest_width);
        !           247:             dest += dest_width;
        !           248:             src++;
1.1       root      249:         }
1.1.1.2 ! root      250:         for (x = 1; x < MAGNIFY; x++) {
        !           251:             memcpy(dest, dest - dest_width * 96, dest_width * 96);
        !           252:             dest += dest_width * 96;
1.1       root      253:         }
                    254:     }
1.1.1.2 ! root      255:     s->redraw = 0;
1.1       root      256:     dpy_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
                    257: }
                    258: 
                    259: static void ssd0303_invalidate_display(void * opaque)
                    260: {
                    261:     ssd0303_state *s = (ssd0303_state *)opaque;
                    262:     s->redraw = 1;
                    263: }
                    264: 
1.1.1.2 ! root      265: static void ssd0303_save(QEMUFile *f, void *opaque)
        !           266: {
        !           267:     ssd0303_state *s = (ssd0303_state *)opaque;
        !           268: 
        !           269:     qemu_put_be32(f, s->row);
        !           270:     qemu_put_be32(f, s->col);
        !           271:     qemu_put_be32(f, s->start_line);
        !           272:     qemu_put_be32(f, s->mirror);
        !           273:     qemu_put_be32(f, s->flash);
        !           274:     qemu_put_be32(f, s->enabled);
        !           275:     qemu_put_be32(f, s->inverse);
        !           276:     qemu_put_be32(f, s->redraw);
        !           277:     qemu_put_be32(f, s->mode);
        !           278:     qemu_put_be32(f, s->cmd_state);
        !           279:     qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer));
        !           280: 
        !           281:     i2c_slave_save(f, &s->i2c);
        !           282: }
        !           283: 
        !           284: static int ssd0303_load(QEMUFile *f, void *opaque, int version_id)
        !           285: {
        !           286:     ssd0303_state *s = (ssd0303_state *)opaque;
        !           287: 
        !           288:     if (version_id != 1)
        !           289:         return -EINVAL;
        !           290: 
        !           291:     s->row = qemu_get_be32(f);
        !           292:     s->col = qemu_get_be32(f);
        !           293:     s->start_line = qemu_get_be32(f);
        !           294:     s->mirror = qemu_get_be32(f);
        !           295:     s->flash = qemu_get_be32(f);
        !           296:     s->enabled = qemu_get_be32(f);
        !           297:     s->inverse = qemu_get_be32(f);
        !           298:     s->redraw = qemu_get_be32(f);
        !           299:     s->mode = qemu_get_be32(f);
        !           300:     s->cmd_state = qemu_get_be32(f);
        !           301:     qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer));
        !           302: 
        !           303:     i2c_slave_load(f, &s->i2c);
        !           304: 
        !           305:     return 0;
        !           306: }
        !           307: 
        !           308: void ssd0303_init(i2c_bus *bus, int address)
1.1       root      309: {
                    310:     ssd0303_state *s;
                    311: 
                    312:     s = (ssd0303_state *)i2c_slave_init(bus, address, sizeof(ssd0303_state));
                    313:     s->i2c.event = ssd0303_event;
                    314:     s->i2c.recv = ssd0303_recv;
                    315:     s->i2c.send = ssd0303_send;
1.1.1.2 ! root      316:     s->ds = graphic_console_init(ssd0303_update_display,
        !           317:                                  ssd0303_invalidate_display,
        !           318:                                  NULL, NULL, s);
        !           319:     qemu_console_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY);
        !           320:     register_savevm("ssd0303_oled", -1, 1, ssd0303_save, ssd0303_load, s);
1.1       root      321: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.