Annotation of qemu/hw/pl181.c, revision 1.1.1.8

1.1       root        1: /*
                      2:  * Arm PrimeCell PL181 MultiMedia Card Interface
                      3:  *
                      4:  * Copyright (c) 2007 CodeSourcery.
                      5:  * Written by Paul Brook
                      6:  *
1.1.1.7   root        7:  * This code is licensed under the GPL.
1.1       root        8:  */
                      9: 
1.1.1.6   root       10: #include "blockdev.h"
1.1.1.3   root       11: #include "sysbus.h"
1.1       root       12: #include "sd.h"
                     13: 
                     14: //#define DEBUG_PL181 1
                     15: 
                     16: #ifdef DEBUG_PL181
1.1.1.3   root       17: #define DPRINTF(fmt, ...) \
                     18: do { printf("pl181: " fmt , ## __VA_ARGS__); } while (0)
1.1       root       19: #else
1.1.1.3   root       20: #define DPRINTF(fmt, ...) do {} while(0)
1.1       root       21: #endif
                     22: 
                     23: #define PL181_FIFO_LEN 16
                     24: 
                     25: typedef struct {
1.1.1.3   root       26:     SysBusDevice busdev;
1.1.1.8 ! root       27:     MemoryRegion iomem;
1.1       root       28:     SDState *card;
                     29:     uint32_t clock;
                     30:     uint32_t power;
                     31:     uint32_t cmdarg;
                     32:     uint32_t cmd;
                     33:     uint32_t datatimer;
                     34:     uint32_t datalength;
                     35:     uint32_t respcmd;
                     36:     uint32_t response[4];
                     37:     uint32_t datactrl;
                     38:     uint32_t datacnt;
                     39:     uint32_t status;
                     40:     uint32_t mask[2];
1.1.1.8 ! root       41:     int32_t fifo_pos;
        !            42:     int32_t fifo_len;
1.1       root       43:     /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives
                     44:        while it is reading the FIFO.  We hack around this be defering
                     45:        subsequent transfers until after the driver polls the status word.
                     46:        http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
                     47:      */
1.1.1.8 ! root       48:     int32_t linux_hack;
1.1       root       49:     uint32_t fifo[PL181_FIFO_LEN];
                     50:     qemu_irq irq[2];
1.1.1.7   root       51:     /* GPIO outputs for 'card is readonly' and 'card inserted' */
                     52:     qemu_irq cardstatus[2];
1.1       root       53: } pl181_state;
                     54: 
1.1.1.8 ! root       55: static const VMStateDescription vmstate_pl181 = {
        !            56:     .name = "pl181",
        !            57:     .version_id = 1,
        !            58:     .minimum_version_id = 1,
        !            59:     .fields = (VMStateField[]) {
        !            60:         VMSTATE_UINT32(clock, pl181_state),
        !            61:         VMSTATE_UINT32(power, pl181_state),
        !            62:         VMSTATE_UINT32(cmdarg, pl181_state),
        !            63:         VMSTATE_UINT32(cmd, pl181_state),
        !            64:         VMSTATE_UINT32(datatimer, pl181_state),
        !            65:         VMSTATE_UINT32(datalength, pl181_state),
        !            66:         VMSTATE_UINT32(respcmd, pl181_state),
        !            67:         VMSTATE_UINT32_ARRAY(response, pl181_state, 4),
        !            68:         VMSTATE_UINT32(datactrl, pl181_state),
        !            69:         VMSTATE_UINT32(datacnt, pl181_state),
        !            70:         VMSTATE_UINT32(status, pl181_state),
        !            71:         VMSTATE_UINT32_ARRAY(mask, pl181_state, 2),
        !            72:         VMSTATE_INT32(fifo_pos, pl181_state),
        !            73:         VMSTATE_INT32(fifo_len, pl181_state),
        !            74:         VMSTATE_INT32(linux_hack, pl181_state),
        !            75:         VMSTATE_UINT32_ARRAY(fifo, pl181_state, PL181_FIFO_LEN),
        !            76:         VMSTATE_END_OF_LIST()
        !            77:     }
        !            78: };
        !            79: 
1.1       root       80: #define PL181_CMD_INDEX     0x3f
                     81: #define PL181_CMD_RESPONSE  (1 << 6)
                     82: #define PL181_CMD_LONGRESP  (1 << 7)
                     83: #define PL181_CMD_INTERRUPT (1 << 8)
                     84: #define PL181_CMD_PENDING   (1 << 9)
                     85: #define PL181_CMD_ENABLE    (1 << 10)
                     86: 
                     87: #define PL181_DATA_ENABLE             (1 << 0)
                     88: #define PL181_DATA_DIRECTION          (1 << 1)
                     89: #define PL181_DATA_MODE               (1 << 2)
                     90: #define PL181_DATA_DMAENABLE          (1 << 3)
                     91: 
                     92: #define PL181_STATUS_CMDCRCFAIL       (1 << 0)
                     93: #define PL181_STATUS_DATACRCFAIL      (1 << 1)
                     94: #define PL181_STATUS_CMDTIMEOUT       (1 << 2)
                     95: #define PL181_STATUS_DATATIMEOUT      (1 << 3)
                     96: #define PL181_STATUS_TXUNDERRUN       (1 << 4)
                     97: #define PL181_STATUS_RXOVERRUN        (1 << 5)
                     98: #define PL181_STATUS_CMDRESPEND       (1 << 6)
                     99: #define PL181_STATUS_CMDSENT          (1 << 7)
                    100: #define PL181_STATUS_DATAEND          (1 << 8)
                    101: #define PL181_STATUS_DATABLOCKEND     (1 << 10)
                    102: #define PL181_STATUS_CMDACTIVE        (1 << 11)
                    103: #define PL181_STATUS_TXACTIVE         (1 << 12)
                    104: #define PL181_STATUS_RXACTIVE         (1 << 13)
                    105: #define PL181_STATUS_TXFIFOHALFEMPTY  (1 << 14)
                    106: #define PL181_STATUS_RXFIFOHALFFULL   (1 << 15)
                    107: #define PL181_STATUS_TXFIFOFULL       (1 << 16)
                    108: #define PL181_STATUS_RXFIFOFULL       (1 << 17)
                    109: #define PL181_STATUS_TXFIFOEMPTY      (1 << 18)
                    110: #define PL181_STATUS_RXFIFOEMPTY      (1 << 19)
                    111: #define PL181_STATUS_TXDATAAVLBL      (1 << 20)
                    112: #define PL181_STATUS_RXDATAAVLBL      (1 << 21)
                    113: 
                    114: #define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
                    115:                              |PL181_STATUS_TXFIFOHALFEMPTY \
                    116:                              |PL181_STATUS_TXFIFOFULL \
                    117:                              |PL181_STATUS_TXFIFOEMPTY \
                    118:                              |PL181_STATUS_TXDATAAVLBL)
                    119: #define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
                    120:                              |PL181_STATUS_RXFIFOHALFFULL \
                    121:                              |PL181_STATUS_RXFIFOFULL \
                    122:                              |PL181_STATUS_RXFIFOEMPTY \
                    123:                              |PL181_STATUS_RXDATAAVLBL)
                    124: 
                    125: static const unsigned char pl181_id[] =
                    126: { 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
                    127: 
                    128: static void pl181_update(pl181_state *s)
                    129: {
                    130:     int i;
                    131:     for (i = 0; i < 2; i++) {
                    132:         qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
                    133:     }
                    134: }
                    135: 
                    136: static void pl181_fifo_push(pl181_state *s, uint32_t value)
                    137: {
                    138:     int n;
                    139: 
                    140:     if (s->fifo_len == PL181_FIFO_LEN) {
                    141:         fprintf(stderr, "pl181: FIFO overflow\n");
                    142:         return;
                    143:     }
                    144:     n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
                    145:     s->fifo_len++;
                    146:     s->fifo[n] = value;
                    147:     DPRINTF("FIFO push %08x\n", (int)value);
                    148: }
                    149: 
                    150: static uint32_t pl181_fifo_pop(pl181_state *s)
                    151: {
                    152:     uint32_t value;
                    153: 
                    154:     if (s->fifo_len == 0) {
                    155:         fprintf(stderr, "pl181: FIFO underflow\n");
                    156:         return 0;
                    157:     }
                    158:     value = s->fifo[s->fifo_pos];
                    159:     s->fifo_len--;
                    160:     s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
                    161:     DPRINTF("FIFO pop %08x\n", (int)value);
                    162:     return value;
                    163: }
                    164: 
                    165: static void pl181_send_command(pl181_state *s)
                    166: {
1.1.1.3   root      167:     SDRequest request;
1.1       root      168:     uint8_t response[16];
                    169:     int rlen;
                    170: 
                    171:     request.cmd = s->cmd & PL181_CMD_INDEX;
                    172:     request.arg = s->cmdarg;
                    173:     DPRINTF("Command %d %08x\n", request.cmd, request.arg);
                    174:     rlen = sd_do_command(s->card, &request, response);
                    175:     if (rlen < 0)
                    176:         goto error;
                    177:     if (s->cmd & PL181_CMD_RESPONSE) {
                    178: #define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \
                    179:                   | (response[n + 2] << 8) | response[n + 3])
                    180:         if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
                    181:             goto error;
                    182:         if (rlen != 4 && rlen != 16)
                    183:             goto error;
                    184:         s->response[0] = RWORD(0);
                    185:         if (rlen == 4) {
                    186:             s->response[1] = s->response[2] = s->response[3] = 0;
                    187:         } else {
                    188:             s->response[1] = RWORD(4);
                    189:             s->response[2] = RWORD(8);
                    190:             s->response[3] = RWORD(12) & ~1;
                    191:         }
                    192:         DPRINTF("Response received\n");
                    193:         s->status |= PL181_STATUS_CMDRESPEND;
                    194: #undef RWORD
                    195:     } else {
                    196:         DPRINTF("Command sent\n");
                    197:         s->status |= PL181_STATUS_CMDSENT;
                    198:     }
                    199:     return;
                    200: 
                    201: error:
                    202:     DPRINTF("Timeout\n");
                    203:     s->status |= PL181_STATUS_CMDTIMEOUT;
                    204: }
                    205: 
                    206: /* Transfer data between the card and the FIFO.  This is complicated by
                    207:    the FIFO holding 32-bit words and the card taking data in single byte
                    208:    chunks.  FIFO bytes are transferred in little-endian order.  */
                    209: 
                    210: static void pl181_fifo_run(pl181_state *s)
                    211: {
                    212:     uint32_t bits;
1.1.1.5   root      213:     uint32_t value = 0;
1.1       root      214:     int n;
                    215:     int is_read;
                    216: 
                    217:     is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
                    218:     if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
                    219:             && !s->linux_hack) {
1.1.1.5   root      220:         if (is_read) {
                    221:             n = 0;
                    222:             while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
1.1       root      223:                 value |= (uint32_t)sd_read_data(s->card) << (n * 8);
1.1.1.5   root      224:                 s->datacnt--;
1.1       root      225:                 n++;
                    226:                 if (n == 4) {
                    227:                     pl181_fifo_push(s, value);
                    228:                     n = 0;
1.1.1.5   root      229:                     value = 0;
1.1       root      230:                 }
1.1.1.5   root      231:             }
                    232:             if (n != 0) {
                    233:                 pl181_fifo_push(s, value);
                    234:             }
                    235:         } else { /* write */
                    236:             n = 0;
                    237:             while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
1.1       root      238:                 if (n == 0) {
                    239:                     value = pl181_fifo_pop(s);
                    240:                     n = 4;
                    241:                 }
1.1.1.5   root      242:                 n--;
                    243:                 s->datacnt--;
1.1       root      244:                 sd_write_data(s->card, value & 0xff);
                    245:                 value >>= 8;
                    246:             }
                    247:         }
                    248:     }
                    249:     s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
                    250:     if (s->datacnt == 0) {
                    251:         s->status |= PL181_STATUS_DATAEND;
                    252:         /* HACK: */
                    253:         s->status |= PL181_STATUS_DATABLOCKEND;
                    254:         DPRINTF("Transfer Complete\n");
                    255:     }
                    256:     if (s->datacnt == 0 && s->fifo_len == 0) {
                    257:         s->datactrl &= ~PL181_DATA_ENABLE;
                    258:         DPRINTF("Data engine idle\n");
                    259:     } else {
                    260:         /* Update FIFO bits.  */
                    261:         bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
                    262:         if (s->fifo_len == 0) {
                    263:             bits |= PL181_STATUS_TXFIFOEMPTY;
                    264:             bits |= PL181_STATUS_RXFIFOEMPTY;
                    265:         } else {
                    266:             bits |= PL181_STATUS_TXDATAAVLBL;
                    267:             bits |= PL181_STATUS_RXDATAAVLBL;
                    268:         }
                    269:         if (s->fifo_len == 16) {
                    270:             bits |= PL181_STATUS_TXFIFOFULL;
                    271:             bits |= PL181_STATUS_RXFIFOFULL;
                    272:         }
                    273:         if (s->fifo_len <= 8) {
                    274:             bits |= PL181_STATUS_TXFIFOHALFEMPTY;
                    275:         }
                    276:         if (s->fifo_len >= 8) {
                    277:             bits |= PL181_STATUS_RXFIFOHALFFULL;
                    278:         }
                    279:         if (s->datactrl & PL181_DATA_DIRECTION) {
                    280:             bits &= PL181_STATUS_RX_FIFO;
                    281:         } else {
                    282:             bits &= PL181_STATUS_TX_FIFO;
                    283:         }
                    284:         s->status |= bits;
                    285:     }
                    286: }
                    287: 
1.1.1.8 ! root      288: static uint64_t pl181_read(void *opaque, target_phys_addr_t offset,
        !           289:                            unsigned size)
1.1       root      290: {
                    291:     pl181_state *s = (pl181_state *)opaque;
                    292:     uint32_t tmp;
                    293: 
                    294:     if (offset >= 0xfe0 && offset < 0x1000) {
                    295:         return pl181_id[(offset - 0xfe0) >> 2];
                    296:     }
                    297:     switch (offset) {
                    298:     case 0x00: /* Power */
                    299:         return s->power;
                    300:     case 0x04: /* Clock */
                    301:         return s->clock;
                    302:     case 0x08: /* Argument */
                    303:         return s->cmdarg;
                    304:     case 0x0c: /* Command */
                    305:         return s->cmd;
                    306:     case 0x10: /* RespCmd */
                    307:         return s->respcmd;
                    308:     case 0x14: /* Response0 */
                    309:         return s->response[0];
                    310:     case 0x18: /* Response1 */
                    311:         return s->response[1];
                    312:     case 0x1c: /* Response2 */
                    313:         return s->response[2];
                    314:     case 0x20: /* Response3 */
                    315:         return s->response[3];
                    316:     case 0x24: /* DataTimer */
                    317:         return s->datatimer;
                    318:     case 0x28: /* DataLength */
                    319:         return s->datalength;
                    320:     case 0x2c: /* DataCtrl */
                    321:         return s->datactrl;
                    322:     case 0x30: /* DataCnt */
                    323:         return s->datacnt;
                    324:     case 0x34: /* Status */
                    325:         tmp = s->status;
                    326:         if (s->linux_hack) {
                    327:             s->linux_hack = 0;
                    328:             pl181_fifo_run(s);
                    329:             pl181_update(s);
                    330:         }
                    331:         return tmp;
                    332:     case 0x3c: /* Mask0 */
                    333:         return s->mask[0];
                    334:     case 0x40: /* Mask1 */
                    335:         return s->mask[1];
                    336:     case 0x48: /* FifoCnt */
                    337:         /* The documentation is somewhat vague about exactly what FifoCnt
                    338:            does.  On real hardware it appears to be when decrememnted
1.1.1.8 ! root      339:            when a word is transferred between the FIFO and the serial
1.1       root      340:            data engine.  DataCnt is decremented after each byte is
1.1.1.8 ! root      341:            transferred between the serial engine and the card.
1.1       root      342:            We don't emulate this level of detail, so both can be the same.  */
                    343:         tmp = (s->datacnt + 3) >> 2;
                    344:         if (s->linux_hack) {
                    345:             s->linux_hack = 0;
                    346:             pl181_fifo_run(s);
                    347:             pl181_update(s);
                    348:         }
                    349:         return tmp;
                    350:     case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
                    351:     case 0x90: case 0x94: case 0x98: case 0x9c:
                    352:     case 0xa0: case 0xa4: case 0xa8: case 0xac:
                    353:     case 0xb0: case 0xb4: case 0xb8: case 0xbc:
                    354:         if (s->fifo_len == 0) {
                    355:             fprintf(stderr, "pl181: Unexpected FIFO read\n");
                    356:             return 0;
                    357:         } else {
                    358:             uint32_t value;
                    359:             value = pl181_fifo_pop(s);
                    360:             s->linux_hack = 1;
                    361:             pl181_fifo_run(s);
                    362:             pl181_update(s);
                    363:             return value;
                    364:         }
                    365:     default:
1.1.1.3   root      366:         hw_error("pl181_read: Bad offset %x\n", (int)offset);
1.1       root      367:         return 0;
                    368:     }
                    369: }
                    370: 
                    371: static void pl181_write(void *opaque, target_phys_addr_t offset,
1.1.1.8 ! root      372:                         uint64_t value, unsigned size)
1.1       root      373: {
                    374:     pl181_state *s = (pl181_state *)opaque;
                    375: 
                    376:     switch (offset) {
                    377:     case 0x00: /* Power */
                    378:         s->power = value & 0xff;
                    379:         break;
                    380:     case 0x04: /* Clock */
                    381:         s->clock = value & 0xff;
                    382:         break;
                    383:     case 0x08: /* Argument */
                    384:         s->cmdarg = value;
                    385:         break;
                    386:     case 0x0c: /* Command */
                    387:         s->cmd = value;
                    388:         if (s->cmd & PL181_CMD_ENABLE) {
                    389:             if (s->cmd & PL181_CMD_INTERRUPT) {
                    390:                 fprintf(stderr, "pl181: Interrupt mode not implemented\n");
                    391:                 abort();
                    392:             } if (s->cmd & PL181_CMD_PENDING) {
                    393:                 fprintf(stderr, "pl181: Pending commands not implemented\n");
                    394:                 abort();
                    395:             } else {
                    396:                 pl181_send_command(s);
                    397:                 pl181_fifo_run(s);
                    398:             }
                    399:             /* The command has completed one way or the other.  */
                    400:             s->cmd &= ~PL181_CMD_ENABLE;
                    401:         }
                    402:         break;
                    403:     case 0x24: /* DataTimer */
                    404:         s->datatimer = value;
                    405:         break;
                    406:     case 0x28: /* DataLength */
                    407:         s->datalength = value & 0xffff;
                    408:         break;
                    409:     case 0x2c: /* DataCtrl */
                    410:         s->datactrl = value & 0xff;
                    411:         if (value & PL181_DATA_ENABLE) {
                    412:             s->datacnt = s->datalength;
                    413:             pl181_fifo_run(s);
                    414:         }
                    415:         break;
                    416:     case 0x38: /* Clear */
                    417:         s->status &= ~(value & 0x7ff);
                    418:         break;
                    419:     case 0x3c: /* Mask0 */
                    420:         s->mask[0] = value;
                    421:         break;
                    422:     case 0x40: /* Mask1 */
                    423:         s->mask[1] = value;
                    424:         break;
                    425:     case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
                    426:     case 0x90: case 0x94: case 0x98: case 0x9c:
                    427:     case 0xa0: case 0xa4: case 0xa8: case 0xac:
                    428:     case 0xb0: case 0xb4: case 0xb8: case 0xbc:
                    429:         if (s->datacnt == 0) {
                    430:             fprintf(stderr, "pl181: Unexpected FIFO write\n");
                    431:         } else {
                    432:             pl181_fifo_push(s, value);
                    433:             pl181_fifo_run(s);
                    434:         }
                    435:         break;
                    436:     default:
1.1.1.3   root      437:         hw_error("pl181_write: Bad offset %x\n", (int)offset);
1.1       root      438:     }
                    439:     pl181_update(s);
                    440: }
                    441: 
1.1.1.8 ! root      442: static const MemoryRegionOps pl181_ops = {
        !           443:     .read = pl181_read,
        !           444:     .write = pl181_write,
        !           445:     .endianness = DEVICE_NATIVE_ENDIAN,
1.1       root      446: };
                    447: 
1.1.1.8 ! root      448: static void pl181_reset(DeviceState *d)
1.1       root      449: {
1.1.1.8 ! root      450:     pl181_state *s = DO_UPCAST(pl181_state, busdev.qdev, d);
1.1       root      451: 
                    452:     s->power = 0;
                    453:     s->cmdarg = 0;
                    454:     s->cmd = 0;
                    455:     s->datatimer = 0;
                    456:     s->datalength = 0;
                    457:     s->respcmd = 0;
                    458:     s->response[0] = 0;
                    459:     s->response[1] = 0;
                    460:     s->response[2] = 0;
                    461:     s->response[3] = 0;
                    462:     s->datatimer = 0;
                    463:     s->datalength = 0;
                    464:     s->datactrl = 0;
                    465:     s->datacnt = 0;
                    466:     s->status = 0;
                    467:     s->linux_hack = 0;
                    468:     s->mask[0] = 0;
                    469:     s->mask[1] = 0;
1.1.1.7   root      470: 
                    471:     /* We can assume our GPIO outputs have been wired up now */
                    472:     sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
1.1       root      473: }
                    474: 
1.1.1.4   root      475: static int pl181_init(SysBusDevice *dev)
1.1       root      476: {
1.1.1.3   root      477:     pl181_state *s = FROM_SYSBUS(pl181_state, dev);
1.1.1.6   root      478:     DriveInfo *dinfo;
1.1       root      479: 
1.1.1.8 ! root      480:     memory_region_init_io(&s->iomem, &pl181_ops, s, "pl181", 0x1000);
        !           481:     sysbus_init_mmio(dev, &s->iomem);
1.1.1.3   root      482:     sysbus_init_irq(dev, &s->irq[0]);
                    483:     sysbus_init_irq(dev, &s->irq[1]);
1.1.1.7   root      484:     qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2);
1.1.1.6   root      485:     dinfo = drive_get_next(IF_SD);
                    486:     s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
1.1.1.4   root      487:     return 0;
1.1       root      488: }
1.1.1.3   root      489: 
1.1.1.8 ! root      490: static void pl181_class_init(ObjectClass *klass, void *data)
        !           491: {
        !           492:     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
        !           493:     DeviceClass *k = DEVICE_CLASS(klass);
        !           494: 
        !           495:     sdc->init = pl181_init;
        !           496:     k->vmsd = &vmstate_pl181;
        !           497:     k->reset = pl181_reset;
        !           498:     k->no_user = 1;
        !           499: }
        !           500: 
        !           501: static TypeInfo pl181_info = {
        !           502:     .name          = "pl181",
        !           503:     .parent        = TYPE_SYS_BUS_DEVICE,
        !           504:     .instance_size = sizeof(pl181_state),
        !           505:     .class_init    = pl181_class_init,
        !           506: };
        !           507: 
        !           508: static void pl181_register_types(void)
1.1.1.3   root      509: {
1.1.1.8 ! root      510:     type_register_static(&pl181_info);
1.1.1.3   root      511: }
                    512: 
1.1.1.8 ! root      513: type_init(pl181_register_types)

unix.superglobalmegacorp.com

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