Annotation of qemu/hw/cbus.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
        !             3:  * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
        !             4:  * Based on reverse-engineering of a linux driver.
        !             5:  *
        !             6:  * Copyright (C) 2008 Nokia Corporation
        !             7:  * Written by Andrzej Zaborowski <[email protected]>
        !             8:  *
        !             9:  * This program is free software; you can redistribute it and/or
        !            10:  * modify it under the terms of the GNU General Public License as
        !            11:  * published by the Free Software Foundation; either version 2 or
        !            12:  * (at your option) version 3 of the License.
        !            13:  *
        !            14:  * This program is distributed in the hope that it will be useful,
        !            15:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            16:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            17:  * GNU General Public License for more details.
        !            18:  *
        !            19:  * You should have received a copy of the GNU General Public License along
        !            20:  * with this program; if not, write to the Free Software Foundation, Inc.,
        !            21:  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
        !            22:  */
        !            23: 
        !            24: #include "qemu-common.h"
        !            25: #include "irq.h"
        !            26: #include "devices.h"
        !            27: #include "sysemu.h"
        !            28: 
        !            29: //#define DEBUG
        !            30: 
        !            31: struct cbus_slave_s;
        !            32: struct cbus_priv_s {
        !            33:     struct cbus_s cbus;
        !            34: 
        !            35:     int sel;
        !            36:     int dat;
        !            37:     int clk;
        !            38:     int bit;
        !            39:     int dir;
        !            40:     uint16_t val;
        !            41:     qemu_irq dat_out;
        !            42: 
        !            43:     int addr;
        !            44:     int reg;
        !            45:     int rw;
        !            46:     enum {
        !            47:         cbus_address,
        !            48:         cbus_value,
        !            49:     } cycle;
        !            50: 
        !            51:     struct cbus_slave_s *slave[8];
        !            52: };
        !            53: 
        !            54: struct cbus_slave_s {
        !            55:     void *opaque;
        !            56:     void (*io)(void *opaque, int rw, int reg, uint16_t *val);
        !            57:     int addr;
        !            58: };
        !            59: 
        !            60: static void cbus_io(struct cbus_priv_s *s)
        !            61: {
        !            62:     if (s->slave[s->addr])
        !            63:         s->slave[s->addr]->io(s->slave[s->addr]->opaque,
        !            64:                         s->rw, s->reg, &s->val);
        !            65:     else
        !            66:         cpu_abort(cpu_single_env, "%s: bad slave address %i\n",
        !            67:                         __FUNCTION__, s->addr);
        !            68: }
        !            69: 
        !            70: static void cbus_cycle(struct cbus_priv_s *s)
        !            71: {
        !            72:     switch (s->cycle) {
        !            73:     case cbus_address:
        !            74:         s->addr = (s->val >> 6) & 7;
        !            75:         s->rw =   (s->val >> 5) & 1;
        !            76:         s->reg =  (s->val >> 0) & 0x1f;
        !            77: 
        !            78:         s->cycle = cbus_value;
        !            79:         s->bit = 15;
        !            80:         s->dir = !s->rw;
        !            81:         s->val = 0;
        !            82: 
        !            83:         if (s->rw)
        !            84:             cbus_io(s);
        !            85:         break;
        !            86: 
        !            87:     case cbus_value:
        !            88:         if (!s->rw)
        !            89:             cbus_io(s);
        !            90: 
        !            91:         s->cycle = cbus_address;
        !            92:         s->bit = 8;
        !            93:         s->dir = 1;
        !            94:         s->val = 0;
        !            95:         break;
        !            96:     }
        !            97: }
        !            98: 
        !            99: static void cbus_clk(void *opaque, int line, int level)
        !           100: {
        !           101:     struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
        !           102: 
        !           103:     if (!s->sel && level && !s->clk) {
        !           104:         if (s->dir)
        !           105:             s->val |= s->dat << (s->bit --);
        !           106:         else
        !           107:             qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
        !           108: 
        !           109:         if (s->bit < 0)
        !           110:             cbus_cycle(s);
        !           111:     }
        !           112: 
        !           113:     s->clk = level;
        !           114: }
        !           115: 
        !           116: static void cbus_dat(void *opaque, int line, int level)
        !           117: {
        !           118:     struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
        !           119: 
        !           120:     s->dat = level;
        !           121: }
        !           122: 
        !           123: static void cbus_sel(void *opaque, int line, int level)
        !           124: {
        !           125:     struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
        !           126: 
        !           127:     if (!level) {
        !           128:         s->dir = 1;
        !           129:         s->bit = 8;
        !           130:         s->val = 0;
        !           131:     }
        !           132: 
        !           133:     s->sel = level;
        !           134: }
        !           135: 
        !           136: struct cbus_s *cbus_init(qemu_irq dat)
        !           137: {
        !           138:     struct cbus_priv_s *s = (struct cbus_priv_s *) qemu_mallocz(sizeof(*s));
        !           139: 
        !           140:     s->dat_out = dat;
        !           141:     s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0];
        !           142:     s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0];
        !           143:     s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0];
        !           144: 
        !           145:     s->sel = 1;
        !           146:     s->clk = 0;
        !           147:     s->dat = 0;
        !           148: 
        !           149:     return &s->cbus;
        !           150: }
        !           151: 
        !           152: void cbus_attach(struct cbus_s *bus, void *slave_opaque)
        !           153: {
        !           154:     struct cbus_slave_s *slave = (struct cbus_slave_s *) slave_opaque;
        !           155:     struct cbus_priv_s *s = (struct cbus_priv_s *) bus;
        !           156: 
        !           157:     s->slave[slave->addr] = slave;
        !           158: }
        !           159: 
        !           160: /* Retu/Vilma */
        !           161: struct cbus_retu_s {
        !           162:     uint16_t irqst;
        !           163:     uint16_t irqen;
        !           164:     uint16_t cc[2];
        !           165:     int channel;
        !           166:     uint16_t result[16];
        !           167:     uint16_t sample;
        !           168:     uint16_t status;
        !           169: 
        !           170:     struct {
        !           171:         uint16_t cal;
        !           172:     } rtc;
        !           173: 
        !           174:     int is_vilma;
        !           175:     qemu_irq irq;
        !           176:     struct cbus_slave_s cbus;
        !           177: };
        !           178: 
        !           179: static void retu_interrupt_update(struct cbus_retu_s *s)
        !           180: {
        !           181:     qemu_set_irq(s->irq, s->irqst & ~s->irqen);
        !           182: }
        !           183: 
        !           184: #define RETU_REG_ASICR         0x00    /* (RO) ASIC ID & revision */
        !           185: #define RETU_REG_IDR           0x01    /* (T)  Interrupt ID */
        !           186: #define RETU_REG_IMR           0x02    /* (RW) Interrupt mask */
        !           187: #define RETU_REG_RTCDSR                0x03    /* (RW) RTC seconds register */
        !           188: #define RETU_REG_RTCHMR                0x04    /* (RO) RTC hours and minutes reg */
        !           189: #define RETU_REG_RTCHMAR       0x05    /* (RW) RTC hours and minutes set reg */
        !           190: #define RETU_REG_RTCCALR       0x06    /* (RW) RTC calibration register */
        !           191: #define RETU_REG_ADCR          0x08    /* (RW) ADC result register */
        !           192: #define RETU_REG_ADCSCR                0x09    /* (RW) ADC sample control register */
        !           193: #define RETU_REG_AFCR          0x0a    /* (RW) AFC register */
        !           194: #define RETU_REG_ANTIFR                0x0b    /* (RW) AntiF register */
        !           195: #define RETU_REG_CALIBR                0x0c    /* (RW) CalibR register*/
        !           196: #define RETU_REG_CCR1          0x0d    /* (RW) Common control register 1 */
        !           197: #define RETU_REG_CCR2          0x0e    /* (RW) Common control register 2 */
        !           198: #define RETU_REG_RCTRL_CLR     0x0f    /* (T)  Regulator clear register */
        !           199: #define RETU_REG_RCTRL_SET     0x10    /* (T)  Regulator set register */
        !           200: #define RETU_REG_TXCR          0x11    /* (RW) TxC register */
        !           201: #define RETU_REG_STATUS                0x16    /* (RO) Status register */
        !           202: #define RETU_REG_WATCHDOG      0x17    /* (RW) Watchdog register */
        !           203: #define RETU_REG_AUDTXR                0x18    /* (RW) Audio Codec Tx register */
        !           204: #define RETU_REG_AUDPAR                0x19    /* (RW) AudioPA register */
        !           205: #define RETU_REG_AUDRXR1       0x1a    /* (RW) Audio receive register 1 */
        !           206: #define RETU_REG_AUDRXR2       0x1b    /* (RW) Audio receive register 2 */
        !           207: #define RETU_REG_SGR1          0x1c    /* (RW) */
        !           208: #define RETU_REG_SCR1          0x1d    /* (RW) */
        !           209: #define RETU_REG_SGR2          0x1e    /* (RW) */
        !           210: #define RETU_REG_SCR2          0x1f    /* (RW) */
        !           211: 
        !           212: /* Retu Interrupt sources */
        !           213: enum {
        !           214:     retu_int_pwr       = 0,    /* Power button */
        !           215:     retu_int_char      = 1,    /* Charger */
        !           216:     retu_int_rtcs      = 2,    /* Seconds */
        !           217:     retu_int_rtcm      = 3,    /* Minutes */
        !           218:     retu_int_rtcd      = 4,    /* Days */
        !           219:     retu_int_rtca      = 5,    /* Alarm */
        !           220:     retu_int_hook      = 6,    /* Hook */
        !           221:     retu_int_head      = 7,    /* Headset */
        !           222:     retu_int_adcs      = 8,    /* ADC sample */
        !           223: };
        !           224: 
        !           225: /* Retu ADC channel wiring */
        !           226: enum {
        !           227:     retu_adc_bsi       = 1,    /* BSI */
        !           228:     retu_adc_batt_temp = 2,    /* Battery temperature */
        !           229:     retu_adc_chg_volt  = 3,    /* Charger voltage */
        !           230:     retu_adc_head_det  = 4,    /* Headset detection */
        !           231:     retu_adc_hook_det  = 5,    /* Hook detection */
        !           232:     retu_adc_rf_gp     = 6,    /* RF GP */
        !           233:     retu_adc_tx_det    = 7,    /* Wideband Tx detection */
        !           234:     retu_adc_batt_volt = 8,    /* Battery voltage */
        !           235:     retu_adc_sens      = 10,   /* Light sensor */
        !           236:     retu_adc_sens_temp = 11,   /* Light sensor temperature */
        !           237:     retu_adc_bbatt_volt        = 12,   /* Backup battery voltage */
        !           238:     retu_adc_self_temp = 13,   /* RETU temperature */
        !           239: };
        !           240: 
        !           241: static inline uint16_t retu_read(struct cbus_retu_s *s, int reg)
        !           242: {
        !           243: #ifdef DEBUG
        !           244:     printf("RETU read at %02x\n", reg);
        !           245: #endif
        !           246: 
        !           247:     switch (reg) {
        !           248:     case RETU_REG_ASICR:
        !           249:         return 0x0215 | (s->is_vilma << 7);
        !           250: 
        !           251:     case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)?  */
        !           252:         return s->irqst;
        !           253: 
        !           254:     case RETU_REG_IMR:
        !           255:         return s->irqen;
        !           256: 
        !           257:     case RETU_REG_RTCDSR:
        !           258:     case RETU_REG_RTCHMR:
        !           259:     case RETU_REG_RTCHMAR:
        !           260:         /* TODO */
        !           261:         return 0x0000;
        !           262: 
        !           263:     case RETU_REG_RTCCALR:
        !           264:         return s->rtc.cal;
        !           265: 
        !           266:     case RETU_REG_ADCR:
        !           267:         return (s->channel << 10) | s->result[s->channel];
        !           268:     case RETU_REG_ADCSCR:
        !           269:         return s->sample;
        !           270: 
        !           271:     case RETU_REG_AFCR:
        !           272:     case RETU_REG_ANTIFR:
        !           273:     case RETU_REG_CALIBR:
        !           274:         /* TODO */
        !           275:         return 0x0000;
        !           276: 
        !           277:     case RETU_REG_CCR1:
        !           278:         return s->cc[0];
        !           279:     case RETU_REG_CCR2:
        !           280:         return s->cc[1];
        !           281: 
        !           282:     case RETU_REG_RCTRL_CLR:
        !           283:     case RETU_REG_RCTRL_SET:
        !           284:     case RETU_REG_TXCR:
        !           285:         /* TODO */
        !           286:         return 0x0000;
        !           287: 
        !           288:     case RETU_REG_STATUS:
        !           289:         return s->status;
        !           290: 
        !           291:     case RETU_REG_WATCHDOG:
        !           292:     case RETU_REG_AUDTXR:
        !           293:     case RETU_REG_AUDPAR:
        !           294:     case RETU_REG_AUDRXR1:
        !           295:     case RETU_REG_AUDRXR2:
        !           296:     case RETU_REG_SGR1:
        !           297:     case RETU_REG_SCR1:
        !           298:     case RETU_REG_SGR2:
        !           299:     case RETU_REG_SCR2:
        !           300:         /* TODO */
        !           301:         return 0x0000;
        !           302: 
        !           303:     default:
        !           304:         cpu_abort(cpu_single_env, "%s: bad register %02x\n",
        !           305:                         __FUNCTION__, reg);
        !           306:     }
        !           307: }
        !           308: 
        !           309: static inline void retu_write(struct cbus_retu_s *s, int reg, uint16_t val)
        !           310: {
        !           311: #ifdef DEBUG
        !           312:     printf("RETU write of %04x at %02x\n", val, reg);
        !           313: #endif
        !           314: 
        !           315:     switch (reg) {
        !           316:     case RETU_REG_IDR:
        !           317:         s->irqst ^= val;
        !           318:         retu_interrupt_update(s);
        !           319:         break;
        !           320: 
        !           321:     case RETU_REG_IMR:
        !           322:         s->irqen = val;
        !           323:         retu_interrupt_update(s);
        !           324:         break;
        !           325: 
        !           326:     case RETU_REG_RTCDSR:
        !           327:     case RETU_REG_RTCHMAR:
        !           328:         /* TODO */
        !           329:         break;
        !           330: 
        !           331:     case RETU_REG_RTCCALR:
        !           332:         s->rtc.cal = val;
        !           333:         break;
        !           334: 
        !           335:     case RETU_REG_ADCR:
        !           336:         s->channel = (val >> 10) & 0xf;
        !           337:         s->irqst |= 1 << retu_int_adcs;
        !           338:         retu_interrupt_update(s);
        !           339:         break;
        !           340:     case RETU_REG_ADCSCR:
        !           341:         s->sample &= ~val;
        !           342:         break;
        !           343: 
        !           344:     case RETU_REG_AFCR:
        !           345:     case RETU_REG_ANTIFR:
        !           346:     case RETU_REG_CALIBR:
        !           347: 
        !           348:     case RETU_REG_CCR1:
        !           349:         s->cc[0] = val;
        !           350:         break;
        !           351:     case RETU_REG_CCR2:
        !           352:         s->cc[1] = val;
        !           353:         break;
        !           354: 
        !           355:     case RETU_REG_RCTRL_CLR:
        !           356:     case RETU_REG_RCTRL_SET:
        !           357:         /* TODO */
        !           358:         break;
        !           359: 
        !           360:     case RETU_REG_WATCHDOG:
        !           361:         if (val == 0 && (s->cc[0] & 2))
        !           362:             qemu_system_shutdown_request();
        !           363:         break;
        !           364: 
        !           365:     case RETU_REG_TXCR:
        !           366:     case RETU_REG_AUDTXR:
        !           367:     case RETU_REG_AUDPAR:
        !           368:     case RETU_REG_AUDRXR1:
        !           369:     case RETU_REG_AUDRXR2:
        !           370:     case RETU_REG_SGR1:
        !           371:     case RETU_REG_SCR1:
        !           372:     case RETU_REG_SGR2:
        !           373:     case RETU_REG_SCR2:
        !           374:         /* TODO */
        !           375:         break;
        !           376: 
        !           377:     default:
        !           378:         cpu_abort(cpu_single_env, "%s: bad register %02x\n",
        !           379:                         __FUNCTION__, reg);
        !           380:     }
        !           381: }
        !           382: 
        !           383: static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
        !           384: {
        !           385:     struct cbus_retu_s *s = (struct cbus_retu_s *) opaque;
        !           386: 
        !           387:     if (rw)
        !           388:         *val = retu_read(s, reg);
        !           389:     else
        !           390:         retu_write(s, reg, *val);
        !           391: }
        !           392: 
        !           393: void *retu_init(qemu_irq irq, int vilma)
        !           394: {
        !           395:     struct cbus_retu_s *s = (struct cbus_retu_s *) qemu_mallocz(sizeof(*s));
        !           396: 
        !           397:     s->irq = irq;
        !           398:     s->irqen = 0xffff;
        !           399:     s->irqst = 0x0000;
        !           400:     s->status = 0x0020;
        !           401:     s->is_vilma = !!vilma;
        !           402:     s->rtc.cal = 0x01;
        !           403:     s->result[retu_adc_bsi] = 0x3c2;
        !           404:     s->result[retu_adc_batt_temp] = 0x0fc;
        !           405:     s->result[retu_adc_chg_volt] = 0x165;
        !           406:     s->result[retu_adc_head_det] = 123;
        !           407:     s->result[retu_adc_hook_det] = 1023;
        !           408:     s->result[retu_adc_rf_gp] = 0x11;
        !           409:     s->result[retu_adc_tx_det] = 0x11;
        !           410:     s->result[retu_adc_batt_volt] = 0x250;
        !           411:     s->result[retu_adc_sens] = 2;
        !           412:     s->result[retu_adc_sens_temp] = 0x11;
        !           413:     s->result[retu_adc_bbatt_volt] = 0x3d0;
        !           414:     s->result[retu_adc_self_temp] = 0x330;
        !           415: 
        !           416:     s->cbus.opaque = s;
        !           417:     s->cbus.io = retu_io;
        !           418:     s->cbus.addr = 1;
        !           419: 
        !           420:     return &s->cbus;
        !           421: }
        !           422: 
        !           423: void retu_key_event(void *retu, int state)
        !           424: {
        !           425:     struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
        !           426:     struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
        !           427: 
        !           428:     s->irqst |= 1 << retu_int_pwr;
        !           429:     retu_interrupt_update(s);
        !           430: 
        !           431:     if (state)
        !           432:         s->status &= ~(1 << 5);
        !           433:     else
        !           434:         s->status |= 1 << 5;
        !           435: }
        !           436: 
        !           437: #if 0
        !           438: static void retu_head_event(void *retu, int state)
        !           439: {
        !           440:     struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
        !           441:     struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
        !           442: 
        !           443:     if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */
        !           444:         /* TODO: reissue the interrupt every 100ms or so.  */
        !           445:         s->irqst |= 1 << retu_int_head;
        !           446:         retu_interrupt_update(s);
        !           447:     }
        !           448: 
        !           449:     if (state)
        !           450:         s->result[retu_adc_head_det] = 50;
        !           451:     else
        !           452:         s->result[retu_adc_head_det] = 123;
        !           453: }
        !           454: 
        !           455: static void retu_hook_event(void *retu, int state)
        !           456: {
        !           457:     struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
        !           458:     struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
        !           459: 
        !           460:     if ((s->cc[0] & 0x500) == 0x500) {
        !           461:         /* TODO: reissue the interrupt every 100ms or so.  */
        !           462:         s->irqst |= 1 << retu_int_hook;
        !           463:         retu_interrupt_update(s);
        !           464:     }
        !           465: 
        !           466:     if (state)
        !           467:         s->result[retu_adc_hook_det] = 50;
        !           468:     else
        !           469:         s->result[retu_adc_hook_det] = 123;
        !           470: }
        !           471: #endif
        !           472: 
        !           473: /* Tahvo/Betty */
        !           474: struct cbus_tahvo_s {
        !           475:     uint16_t irqst;
        !           476:     uint16_t irqen;
        !           477:     uint8_t charger;
        !           478:     uint8_t backlight;
        !           479:     uint16_t usbr;
        !           480:     uint16_t power;
        !           481: 
        !           482:     int is_betty;
        !           483:     qemu_irq irq;
        !           484:     struct cbus_slave_s cbus;
        !           485: };
        !           486: 
        !           487: static void tahvo_interrupt_update(struct cbus_tahvo_s *s)
        !           488: {
        !           489:     qemu_set_irq(s->irq, s->irqst & ~s->irqen);
        !           490: }
        !           491: 
        !           492: #define TAHVO_REG_ASICR                0x00    /* (RO) ASIC ID & revision */
        !           493: #define TAHVO_REG_IDR          0x01    /* (T)  Interrupt ID */
        !           494: #define TAHVO_REG_IDSR         0x02    /* (RO) Interrupt status */
        !           495: #define TAHVO_REG_IMR          0x03    /* (RW) Interrupt mask */
        !           496: #define TAHVO_REG_CHAPWMR      0x04    /* (RW) Charger PWM */
        !           497: #define TAHVO_REG_LEDPWMR      0x05    /* (RW) LED PWM */
        !           498: #define TAHVO_REG_USBR         0x06    /* (RW) USB control */
        !           499: #define TAHVO_REG_RCR          0x07    /* (RW) Some kind of power management */
        !           500: #define TAHVO_REG_CCR1         0x08    /* (RW) Common control register 1 */
        !           501: #define TAHVO_REG_CCR2         0x09    /* (RW) Common control register 2 */
        !           502: #define TAHVO_REG_TESTR1       0x0a    /* (RW) Test register 1 */
        !           503: #define TAHVO_REG_TESTR2       0x0b    /* (RW) Test register 2 */
        !           504: #define TAHVO_REG_NOPR         0x0c    /* (RW) Number of periods */
        !           505: #define TAHVO_REG_FRR          0x0d    /* (RO) FR */
        !           506: 
        !           507: static inline uint16_t tahvo_read(struct cbus_tahvo_s *s, int reg)
        !           508: {
        !           509: #ifdef DEBUG
        !           510:     printf("TAHVO read at %02x\n", reg);
        !           511: #endif
        !           512: 
        !           513:     switch (reg) {
        !           514:     case TAHVO_REG_ASICR:
        !           515:         return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300);       /* 22 in N810 */
        !           516: 
        !           517:     case TAHVO_REG_IDR:
        !           518:     case TAHVO_REG_IDSR:       /* XXX: what does this do?  */
        !           519:         return s->irqst;
        !           520: 
        !           521:     case TAHVO_REG_IMR:
        !           522:         return s->irqen;
        !           523: 
        !           524:     case TAHVO_REG_CHAPWMR:
        !           525:         return s->charger;
        !           526: 
        !           527:     case TAHVO_REG_LEDPWMR:
        !           528:         return s->backlight;
        !           529: 
        !           530:     case TAHVO_REG_USBR:
        !           531:         return s->usbr;
        !           532: 
        !           533:     case TAHVO_REG_RCR:
        !           534:         return s->power;
        !           535: 
        !           536:     case TAHVO_REG_CCR1:
        !           537:     case TAHVO_REG_CCR2:
        !           538:     case TAHVO_REG_TESTR1:
        !           539:     case TAHVO_REG_TESTR2:
        !           540:     case TAHVO_REG_NOPR:
        !           541:     case TAHVO_REG_FRR:
        !           542:         return 0x0000;
        !           543: 
        !           544:     default:
        !           545:         cpu_abort(cpu_single_env, "%s: bad register %02x\n",
        !           546:                         __FUNCTION__, reg);
        !           547:     }
        !           548: }
        !           549: 
        !           550: static inline void tahvo_write(struct cbus_tahvo_s *s, int reg, uint16_t val)
        !           551: {
        !           552: #ifdef DEBUG
        !           553:     printf("TAHVO write of %04x at %02x\n", val, reg);
        !           554: #endif
        !           555: 
        !           556:     switch (reg) {
        !           557:     case TAHVO_REG_IDR:
        !           558:         s->irqst ^= val;
        !           559:         tahvo_interrupt_update(s);
        !           560:         break;
        !           561: 
        !           562:     case TAHVO_REG_IMR:
        !           563:         s->irqen = val;
        !           564:         tahvo_interrupt_update(s);
        !           565:         break;
        !           566: 
        !           567:     case TAHVO_REG_CHAPWMR:
        !           568:         s->charger = val;
        !           569:         break;
        !           570: 
        !           571:     case TAHVO_REG_LEDPWMR:
        !           572:         if (s->backlight != (val & 0x7f)) {
        !           573:             s->backlight = val & 0x7f;
        !           574:             printf("%s: LCD backlight now at %i / 127\n",
        !           575:                             __FUNCTION__, s->backlight);
        !           576:         }
        !           577:         break;
        !           578: 
        !           579:     case TAHVO_REG_USBR:
        !           580:         s->usbr = val;
        !           581:         break;
        !           582: 
        !           583:     case TAHVO_REG_RCR:
        !           584:         s->power = val;
        !           585:         break;
        !           586: 
        !           587:     case TAHVO_REG_CCR1:
        !           588:     case TAHVO_REG_CCR2:
        !           589:     case TAHVO_REG_TESTR1:
        !           590:     case TAHVO_REG_TESTR2:
        !           591:     case TAHVO_REG_NOPR:
        !           592:     case TAHVO_REG_FRR:
        !           593:         break;
        !           594: 
        !           595:     default:
        !           596:         cpu_abort(cpu_single_env, "%s: bad register %02x\n",
        !           597:                         __FUNCTION__, reg);
        !           598:     }
        !           599: }
        !           600: 
        !           601: static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
        !           602: {
        !           603:     struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) opaque;
        !           604: 
        !           605:     if (rw)
        !           606:         *val = tahvo_read(s, reg);
        !           607:     else
        !           608:         tahvo_write(s, reg, *val);
        !           609: }
        !           610: 
        !           611: void *tahvo_init(qemu_irq irq, int betty)
        !           612: {
        !           613:     struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) qemu_mallocz(sizeof(*s));
        !           614: 
        !           615:     s->irq = irq;
        !           616:     s->irqen = 0xffff;
        !           617:     s->irqst = 0x0000;
        !           618:     s->is_betty = !!betty;
        !           619: 
        !           620:     s->cbus.opaque = s;
        !           621:     s->cbus.io = tahvo_io;
        !           622:     s->cbus.addr = 2;
        !           623: 
        !           624:     return &s->cbus;
        !           625: }

unix.superglobalmegacorp.com

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