File:  [Qemu by Fabrice Bellard] / qemu / hw / parallel.c
Revision 1.1.1.10 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:27:52 2018 UTC (23 months, 2 weeks ago) by root
Branches: qemu, MAIN
CVS tags: qemu1001, HEAD
qemu 1.0.1

    1: /*
    2:  * QEMU Parallel PORT emulation
    3:  *
    4:  * Copyright (c) 2003-2005 Fabrice Bellard
    5:  * Copyright (c) 2007 Marko Kohtala
    6:  *
    7:  * Permission is hereby granted, free of charge, to any person obtaining a copy
    8:  * of this software and associated documentation files (the "Software"), to deal
    9:  * in the Software without restriction, including without limitation the rights
   10:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   11:  * copies of the Software, and to permit persons to whom the Software is
   12:  * furnished to do so, subject to the following conditions:
   13:  *
   14:  * The above copyright notice and this permission notice shall be included in
   15:  * all copies or substantial portions of the Software.
   16:  *
   17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   18:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   19:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   20:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   21:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   22:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   23:  * THE SOFTWARE.
   24:  */
   25: #include "hw.h"
   26: #include "qemu-char.h"
   27: #include "isa.h"
   28: #include "pc.h"
   29: #include "sysemu.h"
   30: 
   31: //#define DEBUG_PARALLEL
   32: 
   33: #ifdef DEBUG_PARALLEL
   34: #define pdebug(fmt, ...) printf("pp: " fmt, ## __VA_ARGS__)
   35: #else
   36: #define pdebug(fmt, ...) ((void)0)
   37: #endif
   38: 
   39: #define PARA_REG_DATA 0
   40: #define PARA_REG_STS 1
   41: #define PARA_REG_CTR 2
   42: #define PARA_REG_EPP_ADDR 3
   43: #define PARA_REG_EPP_DATA 4
   44: 
   45: /*
   46:  * These are the definitions for the Printer Status Register
   47:  */
   48: #define PARA_STS_BUSY	0x80	/* Busy complement */
   49: #define PARA_STS_ACK	0x40	/* Acknowledge */
   50: #define PARA_STS_PAPER	0x20	/* Out of paper */
   51: #define PARA_STS_ONLINE	0x10	/* Online */
   52: #define PARA_STS_ERROR	0x08	/* Error complement */
   53: #define PARA_STS_TMOUT	0x01	/* EPP timeout */
   54: 
   55: /*
   56:  * These are the definitions for the Printer Control Register
   57:  */
   58: #define PARA_CTR_DIR	0x20	/* Direction (1=read, 0=write) */
   59: #define PARA_CTR_INTEN	0x10	/* IRQ Enable */
   60: #define PARA_CTR_SELECT	0x08	/* Select In complement */
   61: #define PARA_CTR_INIT	0x04	/* Initialize Printer complement */
   62: #define PARA_CTR_AUTOLF	0x02	/* Auto linefeed complement */
   63: #define PARA_CTR_STROBE	0x01	/* Strobe complement */
   64: 
   65: #define PARA_CTR_SIGNAL (PARA_CTR_SELECT|PARA_CTR_INIT|PARA_CTR_AUTOLF|PARA_CTR_STROBE)
   66: 
   67: typedef struct ParallelState {
   68:     uint8_t dataw;
   69:     uint8_t datar;
   70:     uint8_t status;
   71:     uint8_t control;
   72:     qemu_irq irq;
   73:     int irq_pending;
   74:     CharDriverState *chr;
   75:     int hw_driver;
   76:     int epp_timeout;
   77:     uint32_t last_read_offset; /* For debugging */
   78:     /* Memory-mapped interface */
   79:     int it_shift;
   80: } ParallelState;
   81: 
   82: typedef struct ISAParallelState {
   83:     ISADevice dev;
   84:     uint32_t index;
   85:     uint32_t iobase;
   86:     uint32_t isairq;
   87:     ParallelState state;
   88: } ISAParallelState;
   89: 
   90: static void parallel_update_irq(ParallelState *s)
   91: {
   92:     if (s->irq_pending)
   93:         qemu_irq_raise(s->irq);
   94:     else
   95:         qemu_irq_lower(s->irq);
   96: }
   97: 
   98: static void
   99: parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val)
  100: {
  101:     ParallelState *s = opaque;
  102: 
  103:     pdebug("write addr=0x%02x val=0x%02x\n", addr, val);
  104: 
  105:     addr &= 7;
  106:     switch(addr) {
  107:     case PARA_REG_DATA:
  108:         s->dataw = val;
  109:         parallel_update_irq(s);
  110:         break;
  111:     case PARA_REG_CTR:
  112:         val |= 0xc0;
  113:         if ((val & PARA_CTR_INIT) == 0 ) {
  114:             s->status = PARA_STS_BUSY;
  115:             s->status |= PARA_STS_ACK;
  116:             s->status |= PARA_STS_ONLINE;
  117:             s->status |= PARA_STS_ERROR;
  118:         }
  119:         else if (val & PARA_CTR_SELECT) {
  120:             if (val & PARA_CTR_STROBE) {
  121:                 s->status &= ~PARA_STS_BUSY;
  122:                 if ((s->control & PARA_CTR_STROBE) == 0)
  123:                     qemu_chr_fe_write(s->chr, &s->dataw, 1);
  124:             } else {
  125:                 if (s->control & PARA_CTR_INTEN) {
  126:                     s->irq_pending = 1;
  127:                 }
  128:             }
  129:         }
  130:         parallel_update_irq(s);
  131:         s->control = val;
  132:         break;
  133:     }
  134: }
  135: 
  136: static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
  137: {
  138:     ParallelState *s = opaque;
  139:     uint8_t parm = val;
  140:     int dir;
  141: 
  142:     /* Sometimes programs do several writes for timing purposes on old
  143:        HW. Take care not to waste time on writes that do nothing. */
  144: 
  145:     s->last_read_offset = ~0U;
  146: 
  147:     addr &= 7;
  148:     switch(addr) {
  149:     case PARA_REG_DATA:
  150:         if (s->dataw == val)
  151:             return;
  152:         pdebug("wd%02x\n", val);
  153:         qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
  154:         s->dataw = val;
  155:         break;
  156:     case PARA_REG_STS:
  157:         pdebug("ws%02x\n", val);
  158:         if (val & PARA_STS_TMOUT)
  159:             s->epp_timeout = 0;
  160:         break;
  161:     case PARA_REG_CTR:
  162:         val |= 0xc0;
  163:         if (s->control == val)
  164:             return;
  165:         pdebug("wc%02x\n", val);
  166: 
  167:         if ((val & PARA_CTR_DIR) != (s->control & PARA_CTR_DIR)) {
  168:             if (val & PARA_CTR_DIR) {
  169:                 dir = 1;
  170:             } else {
  171:                 dir = 0;
  172:             }
  173:             qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_DATA_DIR, &dir);
  174:             parm &= ~PARA_CTR_DIR;
  175:         }
  176: 
  177:         qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
  178:         s->control = val;
  179:         break;
  180:     case PARA_REG_EPP_ADDR:
  181:         if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
  182:             /* Controls not correct for EPP address cycle, so do nothing */
  183:             pdebug("wa%02x s\n", val);
  184:         else {
  185:             struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
  186:             if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
  187:                 s->epp_timeout = 1;
  188:                 pdebug("wa%02x t\n", val);
  189:             }
  190:             else
  191:                 pdebug("wa%02x\n", val);
  192:         }
  193:         break;
  194:     case PARA_REG_EPP_DATA:
  195:         if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
  196:             /* Controls not correct for EPP data cycle, so do nothing */
  197:             pdebug("we%02x s\n", val);
  198:         else {
  199:             struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
  200:             if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
  201:                 s->epp_timeout = 1;
  202:                 pdebug("we%02x t\n", val);
  203:             }
  204:             else
  205:                 pdebug("we%02x\n", val);
  206:         }
  207:         break;
  208:     }
  209: }
  210: 
  211: static void
  212: parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val)
  213: {
  214:     ParallelState *s = opaque;
  215:     uint16_t eppdata = cpu_to_le16(val);
  216:     int err;
  217:     struct ParallelIOArg ioarg = {
  218:         .buffer = &eppdata, .count = sizeof(eppdata)
  219:     };
  220:     if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
  221:         /* Controls not correct for EPP data cycle, so do nothing */
  222:         pdebug("we%04x s\n", val);
  223:         return;
  224:     }
  225:     err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
  226:     if (err) {
  227:         s->epp_timeout = 1;
  228:         pdebug("we%04x t\n", val);
  229:     }
  230:     else
  231:         pdebug("we%04x\n", val);
  232: }
  233: 
  234: static void
  235: parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val)
  236: {
  237:     ParallelState *s = opaque;
  238:     uint32_t eppdata = cpu_to_le32(val);
  239:     int err;
  240:     struct ParallelIOArg ioarg = {
  241:         .buffer = &eppdata, .count = sizeof(eppdata)
  242:     };
  243:     if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
  244:         /* Controls not correct for EPP data cycle, so do nothing */
  245:         pdebug("we%08x s\n", val);
  246:         return;
  247:     }
  248:     err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
  249:     if (err) {
  250:         s->epp_timeout = 1;
  251:         pdebug("we%08x t\n", val);
  252:     }
  253:     else
  254:         pdebug("we%08x\n", val);
  255: }
  256: 
  257: static uint32_t parallel_ioport_read_sw(void *opaque, uint32_t addr)
  258: {
  259:     ParallelState *s = opaque;
  260:     uint32_t ret = 0xff;
  261: 
  262:     addr &= 7;
  263:     switch(addr) {
  264:     case PARA_REG_DATA:
  265:         if (s->control & PARA_CTR_DIR)
  266:             ret = s->datar;
  267:         else
  268:             ret = s->dataw;
  269:         break;
  270:     case PARA_REG_STS:
  271:         ret = s->status;
  272:         s->irq_pending = 0;
  273:         if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
  274:             /* XXX Fixme: wait 5 microseconds */
  275:             if (s->status & PARA_STS_ACK)
  276:                 s->status &= ~PARA_STS_ACK;
  277:             else {
  278:                 /* XXX Fixme: wait 5 microseconds */
  279:                 s->status |= PARA_STS_ACK;
  280:                 s->status |= PARA_STS_BUSY;
  281:             }
  282:         }
  283:         parallel_update_irq(s);
  284:         break;
  285:     case PARA_REG_CTR:
  286:         ret = s->control;
  287:         break;
  288:     }
  289:     pdebug("read addr=0x%02x val=0x%02x\n", addr, ret);
  290:     return ret;
  291: }
  292: 
  293: static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
  294: {
  295:     ParallelState *s = opaque;
  296:     uint8_t ret = 0xff;
  297:     addr &= 7;
  298:     switch(addr) {
  299:     case PARA_REG_DATA:
  300:         qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret);
  301:         if (s->last_read_offset != addr || s->datar != ret)
  302:             pdebug("rd%02x\n", ret);
  303:         s->datar = ret;
  304:         break;
  305:     case PARA_REG_STS:
  306:         qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret);
  307:         ret &= ~PARA_STS_TMOUT;
  308:         if (s->epp_timeout)
  309:             ret |= PARA_STS_TMOUT;
  310:         if (s->last_read_offset != addr || s->status != ret)
  311:             pdebug("rs%02x\n", ret);
  312:         s->status = ret;
  313:         break;
  314:     case PARA_REG_CTR:
  315:         /* s->control has some bits fixed to 1. It is zero only when
  316:            it has not been yet written to.  */
  317:         if (s->control == 0) {
  318:             qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
  319:             if (s->last_read_offset != addr)
  320:                 pdebug("rc%02x\n", ret);
  321:             s->control = ret;
  322:         }
  323:         else {
  324:             ret = s->control;
  325:             if (s->last_read_offset != addr)
  326:                 pdebug("rc%02x\n", ret);
  327:         }
  328:         break;
  329:     case PARA_REG_EPP_ADDR:
  330:         if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
  331:             /* Controls not correct for EPP addr cycle, so do nothing */
  332:             pdebug("ra%02x s\n", ret);
  333:         else {
  334:             struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
  335:             if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
  336:                 s->epp_timeout = 1;
  337:                 pdebug("ra%02x t\n", ret);
  338:             }
  339:             else
  340:                 pdebug("ra%02x\n", ret);
  341:         }
  342:         break;
  343:     case PARA_REG_EPP_DATA:
  344:         if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
  345:             /* Controls not correct for EPP data cycle, so do nothing */
  346:             pdebug("re%02x s\n", ret);
  347:         else {
  348:             struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
  349:             if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
  350:                 s->epp_timeout = 1;
  351:                 pdebug("re%02x t\n", ret);
  352:             }
  353:             else
  354:                 pdebug("re%02x\n", ret);
  355:         }
  356:         break;
  357:     }
  358:     s->last_read_offset = addr;
  359:     return ret;
  360: }
  361: 
  362: static uint32_t
  363: parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr)
  364: {
  365:     ParallelState *s = opaque;
  366:     uint32_t ret;
  367:     uint16_t eppdata = ~0;
  368:     int err;
  369:     struct ParallelIOArg ioarg = {
  370:         .buffer = &eppdata, .count = sizeof(eppdata)
  371:     };
  372:     if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
  373:         /* Controls not correct for EPP data cycle, so do nothing */
  374:         pdebug("re%04x s\n", eppdata);
  375:         return eppdata;
  376:     }
  377:     err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
  378:     ret = le16_to_cpu(eppdata);
  379: 
  380:     if (err) {
  381:         s->epp_timeout = 1;
  382:         pdebug("re%04x t\n", ret);
  383:     }
  384:     else
  385:         pdebug("re%04x\n", ret);
  386:     return ret;
  387: }
  388: 
  389: static uint32_t
  390: parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr)
  391: {
  392:     ParallelState *s = opaque;
  393:     uint32_t ret;
  394:     uint32_t eppdata = ~0U;
  395:     int err;
  396:     struct ParallelIOArg ioarg = {
  397:         .buffer = &eppdata, .count = sizeof(eppdata)
  398:     };
  399:     if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
  400:         /* Controls not correct for EPP data cycle, so do nothing */
  401:         pdebug("re%08x s\n", eppdata);
  402:         return eppdata;
  403:     }
  404:     err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
  405:     ret = le32_to_cpu(eppdata);
  406: 
  407:     if (err) {
  408:         s->epp_timeout = 1;
  409:         pdebug("re%08x t\n", ret);
  410:     }
  411:     else
  412:         pdebug("re%08x\n", ret);
  413:     return ret;
  414: }
  415: 
  416: static void parallel_ioport_ecp_write(void *opaque, uint32_t addr, uint32_t val)
  417: {
  418:     pdebug("wecp%d=%02x\n", addr & 7, val);
  419: }
  420: 
  421: static uint32_t parallel_ioport_ecp_read(void *opaque, uint32_t addr)
  422: {
  423:     uint8_t ret = 0xff;
  424: 
  425:     pdebug("recp%d:%02x\n", addr & 7, ret);
  426:     return ret;
  427: }
  428: 
  429: static void parallel_reset(void *opaque)
  430: {
  431:     ParallelState *s = opaque;
  432: 
  433:     s->datar = ~0;
  434:     s->dataw = ~0;
  435:     s->status = PARA_STS_BUSY;
  436:     s->status |= PARA_STS_ACK;
  437:     s->status |= PARA_STS_ONLINE;
  438:     s->status |= PARA_STS_ERROR;
  439:     s->status |= PARA_STS_TMOUT;
  440:     s->control = PARA_CTR_SELECT;
  441:     s->control |= PARA_CTR_INIT;
  442:     s->control |= 0xc0;
  443:     s->irq_pending = 0;
  444:     s->hw_driver = 0;
  445:     s->epp_timeout = 0;
  446:     s->last_read_offset = ~0U;
  447: }
  448: 
  449: static const int isa_parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
  450: 
  451: static const MemoryRegionPortio isa_parallel_portio_hw_list[] = {
  452:     { 0, 8, 1,
  453:       .read = parallel_ioport_read_hw,
  454:       .write = parallel_ioport_write_hw },
  455:     { 4, 1, 2,
  456:       .read = parallel_ioport_eppdata_read_hw2,
  457:       .write = parallel_ioport_eppdata_write_hw2 },
  458:     { 4, 1, 4,
  459:       .read = parallel_ioport_eppdata_read_hw4,
  460:       .write = parallel_ioport_eppdata_write_hw4 },
  461:     { 0x400, 8, 1,
  462:       .read = parallel_ioport_ecp_read,
  463:       .write = parallel_ioport_ecp_write },
  464:     PORTIO_END_OF_LIST(),
  465: };
  466: 
  467: static const MemoryRegionPortio isa_parallel_portio_sw_list[] = {
  468:     { 0, 8, 1,
  469:       .read = parallel_ioport_read_sw,
  470:       .write = parallel_ioport_write_sw },
  471:     PORTIO_END_OF_LIST(),
  472: };
  473: 
  474: static int parallel_isa_initfn(ISADevice *dev)
  475: {
  476:     static int index;
  477:     ISAParallelState *isa = DO_UPCAST(ISAParallelState, dev, dev);
  478:     ParallelState *s = &isa->state;
  479:     int base;
  480:     uint8_t dummy;
  481: 
  482:     if (!s->chr) {
  483:         fprintf(stderr, "Can't create parallel device, empty char device\n");
  484:         exit(1);
  485:     }
  486: 
  487:     if (isa->index == -1)
  488:         isa->index = index;
  489:     if (isa->index >= MAX_PARALLEL_PORTS)
  490:         return -1;
  491:     if (isa->iobase == -1)
  492:         isa->iobase = isa_parallel_io[isa->index];
  493:     index++;
  494: 
  495:     base = isa->iobase;
  496:     isa_init_irq(dev, &s->irq, isa->isairq);
  497:     qemu_register_reset(parallel_reset, s);
  498: 
  499:     if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
  500:         s->hw_driver = 1;
  501:         s->status = dummy;
  502:     }
  503: 
  504:     isa_register_portio_list(dev, base,
  505:                              (s->hw_driver
  506:                               ? &isa_parallel_portio_hw_list[0]
  507:                               : &isa_parallel_portio_sw_list[0]),
  508:                              s, "parallel");
  509:     return 0;
  510: }
  511: 
  512: /* Memory mapped interface */
  513: static uint32_t parallel_mm_readb (void *opaque, target_phys_addr_t addr)
  514: {
  515:     ParallelState *s = opaque;
  516: 
  517:     return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFF;
  518: }
  519: 
  520: static void parallel_mm_writeb (void *opaque,
  521:                                 target_phys_addr_t addr, uint32_t value)
  522: {
  523:     ParallelState *s = opaque;
  524: 
  525:     parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFF);
  526: }
  527: 
  528: static uint32_t parallel_mm_readw (void *opaque, target_phys_addr_t addr)
  529: {
  530:     ParallelState *s = opaque;
  531: 
  532:     return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFFFF;
  533: }
  534: 
  535: static void parallel_mm_writew (void *opaque,
  536:                                 target_phys_addr_t addr, uint32_t value)
  537: {
  538:     ParallelState *s = opaque;
  539: 
  540:     parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFFFF);
  541: }
  542: 
  543: static uint32_t parallel_mm_readl (void *opaque, target_phys_addr_t addr)
  544: {
  545:     ParallelState *s = opaque;
  546: 
  547:     return parallel_ioport_read_sw(s, addr >> s->it_shift);
  548: }
  549: 
  550: static void parallel_mm_writel (void *opaque,
  551:                                 target_phys_addr_t addr, uint32_t value)
  552: {
  553:     ParallelState *s = opaque;
  554: 
  555:     parallel_ioport_write_sw(s, addr >> s->it_shift, value);
  556: }
  557: 
  558: static CPUReadMemoryFunc * const parallel_mm_read_sw[] = {
  559:     &parallel_mm_readb,
  560:     &parallel_mm_readw,
  561:     &parallel_mm_readl,
  562: };
  563: 
  564: static CPUWriteMemoryFunc * const parallel_mm_write_sw[] = {
  565:     &parallel_mm_writeb,
  566:     &parallel_mm_writew,
  567:     &parallel_mm_writel,
  568: };
  569: 
  570: /* If fd is zero, it means that the parallel device uses the console */
  571: bool parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
  572:                       CharDriverState *chr)
  573: {
  574:     ParallelState *s;
  575:     int io_sw;
  576: 
  577:     s = g_malloc0(sizeof(ParallelState));
  578:     s->irq = irq;
  579:     s->chr = chr;
  580:     s->it_shift = it_shift;
  581:     qemu_register_reset(parallel_reset, s);
  582: 
  583:     io_sw = cpu_register_io_memory(parallel_mm_read_sw, parallel_mm_write_sw,
  584:                                    s, DEVICE_NATIVE_ENDIAN);
  585:     cpu_register_physical_memory(base, 8 << it_shift, io_sw);
  586:     return true;
  587: }
  588: 
  589: static ISADeviceInfo parallel_isa_info = {
  590:     .qdev.name  = "isa-parallel",
  591:     .qdev.size  = sizeof(ISAParallelState),
  592:     .init       = parallel_isa_initfn,
  593:     .qdev.props = (Property[]) {
  594:         DEFINE_PROP_UINT32("index", ISAParallelState, index,   -1),
  595:         DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase,  -1),
  596:         DEFINE_PROP_UINT32("irq",   ISAParallelState, isairq,  7),
  597:         DEFINE_PROP_CHR("chardev",  ISAParallelState, state.chr),
  598:         DEFINE_PROP_END_OF_LIST(),
  599:     },
  600: };
  601: 
  602: static void parallel_register_devices(void)
  603: {
  604:     isa_qdev_register(&parallel_isa_info);
  605: }
  606: 
  607: device_init(parallel_register_devices)

unix.superglobalmegacorp.com