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

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

unix.superglobalmegacorp.com

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