Annotation of qemu/hw/ssd0303.c, revision 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.