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

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: 
                    205:     if (s->redraw) {
                    206:         switch (s->ds->depth) {
                    207:         case 0:
                    208:             return;
                    209:         case 15:
                    210:             dest_width = 2;
                    211:             break;
                    212:         case 16:
                    213:             dest_width = 2;
                    214:             break;
                    215:         case 24:
                    216:             dest_width = 3;
                    217:             break;
                    218:         case 32:
                    219:             dest_width = 4;
                    220:             break;
                    221:         default:
                    222:             BADF("Bad color depth\n");
                    223:             return;
                    224:         }
                    225:         dest_width *= MAGNIFY;
                    226:         memset(colortab, 0xff, dest_width);
                    227:         memset(colortab + dest_width, 0, dest_width);
                    228:         if (s->flash) {
                    229:             colors[0] = colortab;
                    230:             colors[1] = colortab;
                    231:         } else if (s->inverse) {
                    232:             colors[0] = colortab;
                    233:             colors[1] = colortab + dest_width;
                    234:         } else {
                    235:             colors[0] = colortab + dest_width;
                    236:             colors[1] = colortab;
                    237:         }
                    238:         dest = s->ds->data;
                    239:         for (y = 0; y < 16; y++) {
                    240:             line = (y + s->start_line) & 63;
                    241:             src = s->framebuffer + 132 * (line >> 3) + 36;
                    242:             mask = 1 << (line & 7);
                    243:             for (x = 0; x < 96; x++) {
                    244:                 memcpy(dest, colors[(*src & mask) != 0], dest_width);
                    245:                 dest += dest_width;
                    246:                 src++;
                    247:             }
                    248:             for (x = 1; x < MAGNIFY; x++) {
                    249:                 memcpy(dest, dest - dest_width * 96, dest_width * 96);
                    250:                 dest += dest_width * 96;
                    251:             }
                    252:         }
                    253:     }
                    254:     dpy_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
                    255: }
                    256: 
                    257: static void ssd0303_invalidate_display(void * opaque)
                    258: {
                    259:     ssd0303_state *s = (ssd0303_state *)opaque;
                    260:     s->redraw = 1;
                    261: }
                    262: 
                    263: void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address)
                    264: {
                    265:     ssd0303_state *s;
                    266: 
                    267:     s = (ssd0303_state *)i2c_slave_init(bus, address, sizeof(ssd0303_state));
                    268:     s->ds = ds;
                    269:     s->i2c.event = ssd0303_event;
                    270:     s->i2c.recv = ssd0303_recv;
                    271:     s->i2c.send = ssd0303_send;
                    272:     graphic_console_init(ds, ssd0303_update_display, ssd0303_invalidate_display,
                    273:                          NULL, s);
                    274:     dpy_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY);
                    275: }

unix.superglobalmegacorp.com

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