File:  [Qemu by Fabrice Bellard] / qemu / hw / parallel.c
Revision 1.1.1.9 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:00:12 2018 UTC (23 months, 2 weeks ago) by root
Branches: qemu, MAIN
CVS tags: qemu1000, qemu0151, HEAD
qemu 0.15.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_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_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_ioctl(s->chr, CHR_IOCTL_PP_DATA_DIR, &dir);
  174:             parm &= ~PARA_CTR_DIR;
  175:         }
  176: 
  177:         qemu_chr_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_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_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_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_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_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_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_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_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_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_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_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 int parallel_isa_initfn(ISADevice *dev)
  452: {
  453:     static int index;
  454:     ISAParallelState *isa = DO_UPCAST(ISAParallelState, dev, dev);
  455:     ParallelState *s = &isa->state;
  456:     int base;
  457:     uint8_t dummy;
  458: 
  459:     if (!s->chr) {
  460:         fprintf(stderr, "Can't create parallel device, empty char device\n");
  461:         exit(1);
  462:     }
  463: 
  464:     if (isa->index == -1)
  465:         isa->index = index;
  466:     if (isa->index >= MAX_PARALLEL_PORTS)
  467:         return -1;
  468:     if (isa->iobase == -1)
  469:         isa->iobase = isa_parallel_io[isa->index];
  470:     index++;
  471: 
  472:     base = isa->iobase;
  473:     isa_init_irq(dev, &s->irq, isa->isairq);
  474:     qemu_register_reset(parallel_reset, s);
  475: 
  476:     if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
  477:         s->hw_driver = 1;
  478:         s->status = dummy;
  479:     }
  480: 
  481:     if (s->hw_driver) {
  482:         register_ioport_write(base, 8, 1, parallel_ioport_write_hw, s);
  483:         register_ioport_read(base, 8, 1, parallel_ioport_read_hw, s);
  484:         isa_init_ioport_range(dev, base, 8);
  485: 
  486:         register_ioport_write(base+4, 1, 2, parallel_ioport_eppdata_write_hw2, s);
  487:         register_ioport_read(base+4, 1, 2, parallel_ioport_eppdata_read_hw2, s);
  488:         register_ioport_write(base+4, 1, 4, parallel_ioport_eppdata_write_hw4, s);
  489:         register_ioport_read(base+4, 1, 4, parallel_ioport_eppdata_read_hw4, s);
  490:         isa_init_ioport(dev, base+4);
  491:         register_ioport_write(base+0x400, 8, 1, parallel_ioport_ecp_write, s);
  492:         register_ioport_read(base+0x400, 8, 1, parallel_ioport_ecp_read, s);
  493:         isa_init_ioport_range(dev, base+0x400, 8);
  494:     }
  495:     else {
  496:         register_ioport_write(base, 8, 1, parallel_ioport_write_sw, s);
  497:         register_ioport_read(base, 8, 1, parallel_ioport_read_sw, s);
  498:         isa_init_ioport_range(dev, base, 8);
  499:     }
  500:     return 0;
  501: }
  502: 
  503: /* Memory mapped interface */
  504: static uint32_t parallel_mm_readb (void *opaque, target_phys_addr_t addr)
  505: {
  506:     ParallelState *s = opaque;
  507: 
  508:     return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFF;
  509: }
  510: 
  511: static void parallel_mm_writeb (void *opaque,
  512:                                 target_phys_addr_t addr, uint32_t value)
  513: {
  514:     ParallelState *s = opaque;
  515: 
  516:     parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFF);
  517: }
  518: 
  519: static uint32_t parallel_mm_readw (void *opaque, target_phys_addr_t addr)
  520: {
  521:     ParallelState *s = opaque;
  522: 
  523:     return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFFFF;
  524: }
  525: 
  526: static void parallel_mm_writew (void *opaque,
  527:                                 target_phys_addr_t addr, uint32_t value)
  528: {
  529:     ParallelState *s = opaque;
  530: 
  531:     parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFFFF);
  532: }
  533: 
  534: static uint32_t parallel_mm_readl (void *opaque, target_phys_addr_t addr)
  535: {
  536:     ParallelState *s = opaque;
  537: 
  538:     return parallel_ioport_read_sw(s, addr >> s->it_shift);
  539: }
  540: 
  541: static void parallel_mm_writel (void *opaque,
  542:                                 target_phys_addr_t addr, uint32_t value)
  543: {
  544:     ParallelState *s = opaque;
  545: 
  546:     parallel_ioport_write_sw(s, addr >> s->it_shift, value);
  547: }
  548: 
  549: static CPUReadMemoryFunc * const parallel_mm_read_sw[] = {
  550:     &parallel_mm_readb,
  551:     &parallel_mm_readw,
  552:     &parallel_mm_readl,
  553: };
  554: 
  555: static CPUWriteMemoryFunc * const parallel_mm_write_sw[] = {
  556:     &parallel_mm_writeb,
  557:     &parallel_mm_writew,
  558:     &parallel_mm_writel,
  559: };
  560: 
  561: /* If fd is zero, it means that the parallel device uses the console */
  562: bool parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
  563:                       CharDriverState *chr)
  564: {
  565:     ParallelState *s;
  566:     int io_sw;
  567: 
  568:     s = qemu_mallocz(sizeof(ParallelState));
  569:     s->irq = irq;
  570:     s->chr = chr;
  571:     s->it_shift = it_shift;
  572:     qemu_register_reset(parallel_reset, s);
  573: 
  574:     io_sw = cpu_register_io_memory(parallel_mm_read_sw, parallel_mm_write_sw,
  575:                                    s, DEVICE_NATIVE_ENDIAN);
  576:     cpu_register_physical_memory(base, 8 << it_shift, io_sw);
  577:     return true;
  578: }
  579: 
  580: static ISADeviceInfo parallel_isa_info = {
  581:     .qdev.name  = "isa-parallel",
  582:     .qdev.size  = sizeof(ISAParallelState),
  583:     .init       = parallel_isa_initfn,
  584:     .qdev.props = (Property[]) {
  585:         DEFINE_PROP_UINT32("index", ISAParallelState, index,   -1),
  586:         DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase,  -1),
  587:         DEFINE_PROP_UINT32("irq",   ISAParallelState, isairq,  7),
  588:         DEFINE_PROP_CHR("chardev",  ISAParallelState, state.chr),
  589:         DEFINE_PROP_END_OF_LIST(),
  590:     },
  591: };
  592: 
  593: static void parallel_register_devices(void)
  594: {
  595:     isa_qdev_register(&parallel_isa_info);
  596: }
  597: 
  598: device_init(parallel_register_devices)

unix.superglobalmegacorp.com