adc12bb55aa24fa879bb6d2c23273c1f3bea9633
2 * Copyright (c) 2013 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Copyright (c) 2004-2005 The Regents of The University of Michigan
15 * All rights reserved.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 * A single PCI device configuration space entry.
53 #include "base/inifile.hh"
54 #include "base/intmath.hh"
55 #include "base/misc.hh"
56 #include "base/str.hh"
57 #include "base/trace.hh"
58 #include "debug/PCIDEV.hh"
59 #include "dev/alpha/tsunamireg.h"
60 #include "dev/pciconfigall.hh"
61 #include "dev/pcidev.hh"
62 #include "mem/packet.hh"
63 #include "mem/packet_access.hh"
64 #include "sim/byteswap.hh"
65 #include "sim/core.hh"
68 PciDevice::PciConfigPort::PciConfigPort(PciDevice
*dev
, int busid
, int devid
,
69 int funcid
, Platform
*p
)
70 : SimpleTimingPort(dev
->name() + "-pciconf", dev
), device(dev
),
71 platform(p
), busId(busid
), deviceId(devid
), functionId(funcid
)
73 configAddr
= platform
->calcPciConfigAddr(busId
, deviceId
, functionId
);
78 PciDevice::PciConfigPort::recvAtomic(PacketPtr pkt
)
80 assert(pkt
->getAddr() >= configAddr
&&
81 pkt
->getAddr() < configAddr
+ PCI_CONFIG_SIZE
);
82 // @todo someone should pay for this
83 pkt
->busFirstWordDelay
= pkt
->busLastWordDelay
= 0;
84 return pkt
->isRead() ? device
->readConfig(pkt
) : device
->writeConfig(pkt
);
88 PciDevice::PciConfigPort::getAddrRanges() const
91 if (configAddr
!= ULL(-1))
92 ranges
.push_back(RangeSize(configAddr
, PCI_CONFIG_SIZE
+1));
97 PciDevice::PciDevice(const Params
*p
)
99 PMCAP_BASE(p
->PMCAPBaseOffset
),
100 MSICAP_BASE(p
->MSICAPBaseOffset
),
101 MSIXCAP_BASE(p
->MSIXCAPBaseOffset
),
102 PXCAP_BASE(p
->PXCAPBaseOffset
),
103 platform(p
->platform
),
104 pioDelay(p
->pio_latency
),
105 configDelay(p
->config_latency
),
106 configPort(this, params()->pci_bus
, params()->pci_dev
,
107 params()->pci_func
, params()->platform
)
109 config
.vendor
= htole(p
->VendorID
);
110 config
.device
= htole(p
->DeviceID
);
111 config
.command
= htole(p
->Command
);
112 config
.status
= htole(p
->Status
);
113 config
.revision
= htole(p
->Revision
);
114 config
.progIF
= htole(p
->ProgIF
);
115 config
.subClassCode
= htole(p
->SubClassCode
);
116 config
.classCode
= htole(p
->ClassCode
);
117 config
.cacheLineSize
= htole(p
->CacheLineSize
);
118 config
.latencyTimer
= htole(p
->LatencyTimer
);
119 config
.headerType
= htole(p
->HeaderType
);
120 config
.bist
= htole(p
->BIST
);
122 config
.baseAddr
[0] = htole(p
->BAR0
);
123 config
.baseAddr
[1] = htole(p
->BAR1
);
124 config
.baseAddr
[2] = htole(p
->BAR2
);
125 config
.baseAddr
[3] = htole(p
->BAR3
);
126 config
.baseAddr
[4] = htole(p
->BAR4
);
127 config
.baseAddr
[5] = htole(p
->BAR5
);
128 config
.cardbusCIS
= htole(p
->CardbusCIS
);
129 config
.subsystemVendorID
= htole(p
->SubsystemVendorID
);
130 config
.subsystemID
= htole(p
->SubsystemID
);
131 config
.expansionROM
= htole(p
->ExpansionROM
);
132 config
.capabilityPtr
= htole(p
->CapabilityPtr
);
133 // Zero out the 7 bytes of reserved space in the PCI Config space register.
134 bzero(config
.reserved
, 7*sizeof(uint8_t));
135 config
.interruptLine
= htole(p
->InterruptLine
);
136 config
.interruptPin
= htole(p
->InterruptPin
);
137 config
.minimumGrant
= htole(p
->MinimumGrant
);
138 config
.maximumLatency
= htole(p
->MaximumLatency
);
140 // Initialize the capability lists
141 // These structs are bitunions, meaning the data is stored in host
142 // endianess and must be converted to Little Endian when accessed
145 pmcap
.pid
.cid
= p
->PMCAPCapId
;
146 pmcap
.pid
.next
= p
->PMCAPNextCapability
;
147 pmcap
.pc
= p
->PMCAPCapabilities
;
148 pmcap
.pmcs
= p
->PMCAPCtrlStatus
;
151 msicap
.mid
.cid
= p
->MSICAPCapId
;
152 msicap
.mid
.next
= p
->MSICAPNextCapability
;
153 msicap
.mc
= p
->MSICAPMsgCtrl
;
154 msicap
.ma
= p
->MSICAPMsgAddr
;
155 msicap
.mua
= p
->MSICAPMsgUpperAddr
;
156 msicap
.md
= p
->MSICAPMsgData
;
157 msicap
.mmask
= p
->MSICAPMaskBits
;
158 msicap
.mpend
= p
->MSICAPPendingBits
;
161 msixcap
.mxid
.cid
= p
->MSIXCAPCapId
;
162 msixcap
.mxid
.next
= p
->MSIXCAPNextCapability
;
163 msixcap
.mxc
= p
->MSIXMsgCtrl
;
164 msixcap
.mtab
= p
->MSIXTableOffset
;
165 msixcap
.mpba
= p
->MSIXPbaOffset
;
167 // allocate MSIX structures if MSIXCAP_BASE
168 // indicates the MSIXCAP is being used by having a
169 // non-zero base address.
170 // The MSIX tables are stored by the guest in
171 // little endian byte-order as according the
172 // PCIe specification. Make sure to take the proper
173 // actions when manipulating these tables on the host
174 if (MSIXCAP_BASE
!= 0x0) {
175 int msix_vecs
= msixcap
.mxc
.ts
+ 1;
176 MSIXTable tmp1
= {{0UL,0UL,0UL,0UL}};
177 msix_table
.resize(msix_vecs
, tmp1
);
179 MSIXPbaEntry tmp2
= {0};
180 int pba_size
= msix_vecs
/ MSIXVECS_PER_PBA
;
181 if ((msix_vecs
% MSIXVECS_PER_PBA
) > 0) {
184 msix_pba
.resize(pba_size
, tmp2
);
188 pxcap
.pxid
.cid
= p
->PXCAPCapId
;
189 pxcap
.pxid
.next
= p
->PXCAPNextCapability
;
190 pxcap
.pxcap
= p
->PXCAPCapabilities
;
191 pxcap
.pxdcap
= p
->PXCAPDevCapabilities
;
192 pxcap
.pxdc
= p
->PXCAPDevCtrl
;
193 pxcap
.pxds
= p
->PXCAPDevStatus
;
194 pxcap
.pxlcap
= p
->PXCAPLinkCap
;
195 pxcap
.pxlc
= p
->PXCAPLinkCtrl
;
196 pxcap
.pxls
= p
->PXCAPLinkStatus
;
197 pxcap
.pxdcap2
= p
->PXCAPDevCap2
;
198 pxcap
.pxdc2
= p
->PXCAPDevCtrl2
;
200 BARSize
[0] = p
->BAR0Size
;
201 BARSize
[1] = p
->BAR1Size
;
202 BARSize
[2] = p
->BAR2Size
;
203 BARSize
[3] = p
->BAR3Size
;
204 BARSize
[4] = p
->BAR4Size
;
205 BARSize
[5] = p
->BAR5Size
;
207 legacyIO
[0] = p
->BAR0LegacyIO
;
208 legacyIO
[1] = p
->BAR1LegacyIO
;
209 legacyIO
[2] = p
->BAR2LegacyIO
;
210 legacyIO
[3] = p
->BAR3LegacyIO
;
211 legacyIO
[4] = p
->BAR4LegacyIO
;
212 legacyIO
[5] = p
->BAR5LegacyIO
;
214 for (int i
= 0; i
< 6; ++i
) {
216 BARAddrs
[i
] = p
->LegacyIOBase
+ letoh(config
.baseAddr
[i
]);
217 config
.baseAddr
[i
] = 0;
220 uint32_t barsize
= BARSize
[i
];
221 if (barsize
!= 0 && !isPowerOf2(barsize
)) {
222 fatal("BAR %d size %d is not a power of 2\n", i
, BARSize
[i
]);
227 platform
->registerPciDevice(p
->pci_bus
, p
->pci_dev
, p
->pci_func
,
228 letoh(config
.interruptLine
));
234 if (!configPort
.isConnected())
235 panic("PCI config port on %s not connected to anything!\n", name());
236 configPort
.sendRangeChange();
241 PciDevice::drain(DrainManager
*dm
)
244 count
= pioPort
.drain(dm
) + dmaPort
.drain(dm
) + configPort
.drain(dm
);
246 setDrainState(Drainable::Draining
);
248 setDrainState(Drainable::Drained
);
253 PciDevice::readConfig(PacketPtr pkt
)
255 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
256 if (offset
>= PCI_DEVICE_SPECIFIC
)
257 panic("Device specific PCI config space not implemented!\n");
261 switch (pkt
->getSize()) {
262 case sizeof(uint8_t):
263 pkt
->set
<uint8_t>(config
.data
[offset
]);
265 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
266 params()->pci_dev
, params()->pci_func
, offset
,
267 (uint32_t)pkt
->get
<uint8_t>());
269 case sizeof(uint16_t):
270 pkt
->set
<uint16_t>(*(uint16_t*)&config
.data
[offset
]);
272 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
273 params()->pci_dev
, params()->pci_func
, offset
,
274 (uint32_t)pkt
->get
<uint16_t>());
276 case sizeof(uint32_t):
277 pkt
->set
<uint32_t>(*(uint32_t*)&config
.data
[offset
]);
279 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
280 params()->pci_dev
, params()->pci_func
, offset
,
281 (uint32_t)pkt
->get
<uint32_t>());
284 panic("invalid access size(?) for PCI configspace!\n");
286 pkt
->makeAtomicResponse();
292 PciDevice::getAddrRanges() const
294 AddrRangeList ranges
;
296 for (x
= 0; x
< 6; x
++)
297 if (BARAddrs
[x
] != 0)
298 ranges
.push_back(RangeSize(BARAddrs
[x
],BARSize
[x
]));
303 PciDevice::writeConfig(PacketPtr pkt
)
305 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
306 if (offset
>= PCI_DEVICE_SPECIFIC
)
307 panic("Device specific PCI config space not implemented!\n");
309 switch (pkt
->getSize()) {
310 case sizeof(uint8_t):
312 case PCI0_INTERRUPT_LINE
:
313 config
.interruptLine
= pkt
->get
<uint8_t>();
315 case PCI_CACHE_LINE_SIZE
:
316 config
.cacheLineSize
= pkt
->get
<uint8_t>();
318 case PCI_LATENCY_TIMER
:
319 config
.latencyTimer
= pkt
->get
<uint8_t>();
321 /* Do nothing for these read-only registers */
322 case PCI0_INTERRUPT_PIN
:
323 case PCI0_MINIMUM_GRANT
:
324 case PCI0_MAXIMUM_LATENCY
:
326 case PCI_REVISION_ID
:
329 panic("writing to a read only register");
332 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
333 params()->pci_dev
, params()->pci_func
, offset
,
334 (uint32_t)pkt
->get
<uint8_t>());
336 case sizeof(uint16_t):
339 config
.command
= pkt
->get
<uint8_t>();
342 config
.status
= pkt
->get
<uint8_t>();
344 case PCI_CACHE_LINE_SIZE
:
345 config
.cacheLineSize
= pkt
->get
<uint8_t>();
348 panic("writing to a read only register");
351 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
352 params()->pci_dev
, params()->pci_func
, offset
,
353 (uint32_t)pkt
->get
<uint16_t>());
355 case sizeof(uint32_t):
357 case PCI0_BASE_ADDR0
:
358 case PCI0_BASE_ADDR1
:
359 case PCI0_BASE_ADDR2
:
360 case PCI0_BASE_ADDR3
:
361 case PCI0_BASE_ADDR4
:
362 case PCI0_BASE_ADDR5
:
364 int barnum
= BAR_NUMBER(offset
);
366 if (!legacyIO
[barnum
]) {
367 // convert BAR values to host endianness
368 uint32_t he_old_bar
= letoh(config
.baseAddr
[barnum
]);
369 uint32_t he_new_bar
= letoh(pkt
->get
<uint32_t>());
372 BAR_IO_SPACE(he_old_bar
) ? BAR_IO_MASK
: BAR_MEM_MASK
;
374 // Writing 0xffffffff to a BAR tells the card to set the
375 // value of the bar to a bitmask indicating the size of
377 if (he_new_bar
== 0xffffffff) {
378 he_new_bar
= ~(BARSize
[barnum
] - 1);
380 // does it mean something special to write 0 to a BAR?
381 he_new_bar
&= ~bar_mask
;
383 BARAddrs
[barnum
] = BAR_IO_SPACE(he_old_bar
) ?
384 platform
->calcPciIOAddr(he_new_bar
) :
385 platform
->calcPciMemAddr(he_new_bar
);
386 pioPort
.sendRangeChange();
389 config
.baseAddr
[barnum
] = htole((he_new_bar
& ~bar_mask
) |
390 (he_old_bar
& bar_mask
));
395 case PCI0_ROM_BASE_ADDR
:
396 if (letoh(pkt
->get
<uint32_t>()) == 0xfffffffe)
397 config
.expansionROM
= htole((uint32_t)0xffffffff);
399 config
.expansionROM
= pkt
->get
<uint32_t>();
403 // This could also clear some of the error bits in the Status
404 // register. However they should never get set, so lets ignore
406 config
.command
= pkt
->get
<uint32_t>();
410 DPRINTF(PCIDEV
, "Writing to a read only register");
413 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
414 params()->pci_dev
, params()->pci_func
, offset
,
415 (uint32_t)pkt
->get
<uint32_t>());
418 panic("invalid access size(?) for PCI configspace!\n");
420 pkt
->makeAtomicResponse();
425 PciDevice::serialize(std::ostream
&os
)
427 SERIALIZE_ARRAY(BARSize
, sizeof(BARSize
) / sizeof(BARSize
[0]));
428 SERIALIZE_ARRAY(BARAddrs
, sizeof(BARAddrs
) / sizeof(BARAddrs
[0]));
429 SERIALIZE_ARRAY(config
.data
, sizeof(config
.data
) / sizeof(config
.data
[0]));
431 // serialize the capability list registers
432 paramOut(os
, csprintf("pmcap.pid"), uint16_t(pmcap
.pid
));
433 paramOut(os
, csprintf("pmcap.pc"), uint16_t(pmcap
.pc
));
434 paramOut(os
, csprintf("pmcap.pmcs"), uint16_t(pmcap
.pmcs
));
436 paramOut(os
, csprintf("msicap.mid"), uint16_t(msicap
.mid
));
437 paramOut(os
, csprintf("msicap.mc"), uint16_t(msicap
.mc
));
438 paramOut(os
, csprintf("msicap.ma"), uint32_t(msicap
.ma
));
439 SERIALIZE_SCALAR(msicap
.mua
);
440 paramOut(os
, csprintf("msicap.md"), uint16_t(msicap
.md
));
441 SERIALIZE_SCALAR(msicap
.mmask
);
442 SERIALIZE_SCALAR(msicap
.mpend
);
444 paramOut(os
, csprintf("msixcap.mxid"), uint16_t(msixcap
.mxid
));
445 paramOut(os
, csprintf("msixcap.mxc"), uint16_t(msixcap
.mxc
));
446 paramOut(os
, csprintf("msixcap.mtab"), uint32_t(msixcap
.mtab
));
447 paramOut(os
, csprintf("msixcap.mpba"), uint32_t(msixcap
.mpba
));
449 // Only serialize if we have a non-zero base address
450 if (MSIXCAP_BASE
!= 0x0) {
451 int msix_array_size
= msixcap
.mxc
.ts
+ 1;
452 int pba_array_size
= msix_array_size
/MSIXVECS_PER_PBA
;
453 if ((msix_array_size
% MSIXVECS_PER_PBA
) > 0) {
457 SERIALIZE_SCALAR(msix_array_size
);
458 SERIALIZE_SCALAR(pba_array_size
);
460 for (int i
= 0; i
< msix_array_size
; i
++) {
461 paramOut(os
, csprintf("msix_table[%d].addr_lo", i
),
462 msix_table
[i
].fields
.addr_lo
);
463 paramOut(os
, csprintf("msix_table[%d].addr_hi", i
),
464 msix_table
[i
].fields
.addr_hi
);
465 paramOut(os
, csprintf("msix_table[%d].msg_data", i
),
466 msix_table
[i
].fields
.msg_data
);
467 paramOut(os
, csprintf("msix_table[%d].vec_ctrl", i
),
468 msix_table
[i
].fields
.vec_ctrl
);
470 for (int i
= 0; i
< pba_array_size
; i
++) {
471 paramOut(os
, csprintf("msix_pba[%d].bits", i
),
476 paramOut(os
, csprintf("pxcap.pxid"), uint16_t(pxcap
.pxid
));
477 paramOut(os
, csprintf("pxcap.pxcap"), uint16_t(pxcap
.pxcap
));
478 paramOut(os
, csprintf("pxcap.pxdcap"), uint32_t(pxcap
.pxdcap
));
479 paramOut(os
, csprintf("pxcap.pxdc"), uint16_t(pxcap
.pxdc
));
480 paramOut(os
, csprintf("pxcap.pxds"), uint16_t(pxcap
.pxds
));
481 paramOut(os
, csprintf("pxcap.pxlcap"), uint32_t(pxcap
.pxlcap
));
482 paramOut(os
, csprintf("pxcap.pxlc"), uint16_t(pxcap
.pxlc
));
483 paramOut(os
, csprintf("pxcap.pxls"), uint16_t(pxcap
.pxls
));
484 paramOut(os
, csprintf("pxcap.pxdcap2"), uint32_t(pxcap
.pxdcap2
));
485 paramOut(os
, csprintf("pxcap.pxdc2"), uint32_t(pxcap
.pxdc2
));
489 PciDevice::unserialize(Checkpoint
*cp
, const std::string
§ion
)
491 UNSERIALIZE_ARRAY(BARSize
, sizeof(BARSize
) / sizeof(BARSize
[0]));
492 UNSERIALIZE_ARRAY(BARAddrs
, sizeof(BARAddrs
) / sizeof(BARAddrs
[0]));
493 UNSERIALIZE_ARRAY(config
.data
,
494 sizeof(config
.data
) / sizeof(config
.data
[0]));
496 // unserialize the capability list registers
499 paramIn(cp
, section
, csprintf("pmcap.pid"), tmp16
);
501 paramIn(cp
, section
, csprintf("pmcap.pc"), tmp16
);
503 paramIn(cp
, section
, csprintf("pmcap.pmcs"), tmp16
);
506 paramIn(cp
, section
, csprintf("msicap.mid"), tmp16
);
508 paramIn(cp
, section
, csprintf("msicap.mc"), tmp16
);
510 paramIn(cp
, section
, csprintf("msicap.ma"), tmp32
);
512 UNSERIALIZE_SCALAR(msicap
.mua
);
513 paramIn(cp
, section
, csprintf("msicap.md"), tmp16
);;
515 UNSERIALIZE_SCALAR(msicap
.mmask
);
516 UNSERIALIZE_SCALAR(msicap
.mpend
);
518 paramIn(cp
, section
, csprintf("msixcap.mxid"), tmp16
);
519 msixcap
.mxid
= tmp16
;
520 paramIn(cp
, section
, csprintf("msixcap.mxc"), tmp16
);
522 paramIn(cp
, section
, csprintf("msixcap.mtab"), tmp32
);
523 msixcap
.mtab
= tmp32
;
524 paramIn(cp
, section
, csprintf("msixcap.mpba"), tmp32
);
525 msixcap
.mpba
= tmp32
;
527 // Only allocate if MSIXCAP_BASE is not 0x0
528 if (MSIXCAP_BASE
!= 0x0) {
532 UNSERIALIZE_SCALAR(msix_array_size
);
533 UNSERIALIZE_SCALAR(pba_array_size
);
535 MSIXTable tmp1
= {{0UL, 0UL, 0UL, 0UL}};
536 msix_table
.resize(msix_array_size
, tmp1
);
538 MSIXPbaEntry tmp2
= {0};
539 msix_pba
.resize(pba_array_size
, tmp2
);
541 for (int i
= 0; i
< msix_array_size
; i
++) {
542 paramIn(cp
, section
, csprintf("msix_table[%d].addr_lo", i
),
543 msix_table
[i
].fields
.addr_lo
);
544 paramIn(cp
, section
, csprintf("msix_table[%d].addr_hi", i
),
545 msix_table
[i
].fields
.addr_hi
);
546 paramIn(cp
, section
, csprintf("msix_table[%d].msg_data", i
),
547 msix_table
[i
].fields
.msg_data
);
548 paramIn(cp
, section
, csprintf("msix_table[%d].vec_ctrl", i
),
549 msix_table
[i
].fields
.vec_ctrl
);
551 for (int i
= 0; i
< pba_array_size
; i
++) {
552 paramIn(cp
, section
, csprintf("msix_pba[%d].bits", i
),
557 paramIn(cp
, section
, csprintf("pxcap.pxid"), tmp16
);
559 paramIn(cp
, section
, csprintf("pxcap.pxcap"), tmp16
);
561 paramIn(cp
, section
, csprintf("pxcap.pxdcap"), tmp32
);
562 pxcap
.pxdcap
= tmp32
;
563 paramIn(cp
, section
, csprintf("pxcap.pxdc"), tmp16
);
565 paramIn(cp
, section
, csprintf("pxcap.pxds"), tmp16
);
567 paramIn(cp
, section
, csprintf("pxcap.pxlcap"), tmp32
);
568 pxcap
.pxlcap
= tmp32
;
569 paramIn(cp
, section
, csprintf("pxcap.pxlc"), tmp16
);
571 paramIn(cp
, section
, csprintf("pxcap.pxls"), tmp16
);
573 paramIn(cp
, section
, csprintf("pxcap.pxdcap2"), tmp32
);
574 pxcap
.pxdcap2
= tmp32
;
575 paramIn(cp
, section
, csprintf("pxcap.pxdc2"), tmp32
);
577 pioPort
.sendRangeChange();