|
|
The udi_cmos driver uses PIO to read and write values on the CMOS RAM device. This is done by first specifying the I/O characteristics of the device.
"cmos_udi.c PIO device properties" |
---|
/* * PIO properties of the physical I/O registers on the CMOS device. */ #define CMOS_REGSET 1 /* first (and only) register set */ #define CMOS_BASE 0 /* base address within this regset */ #define CMOS_LENGTH 2 /* two bytes worth of registers */ #define CMOS_PACE 5 /* wait 5 microseconds between accesses * (not really need for this device, * but illustrates use of pacing) */ |
The above definitions are used in calls to udi_pio_map in the driver subroutines to establish device characteristics for the CMOS RAM device. This is called from a driver subroutine defined later. The set of definition needed for a given device are usually quite specific to that device.
"cmos_udi.c PIO offsets" |
---|
/* * PIO offsets for various device registers, relative to the base of * the device's register set. */ #define CMOS_ADDR 0 /* address register */ #define CMOS_DATA 1 /* data register */ |
The address and data register definitions are used in the transaction lists described below.
"cmos_udi.c other device properties" |
---|
/* * Other device properties. */ #define CMOS_DEVSIZE 0x40 /* # data bytes supported by device */ #define CMOS_RDONLY_SZ 0x0E /* first 14 bytes are read-only */ |
The device size definitions are used in binding, transfer, and write subroutine calls defined later in the driver, to avoid overflowing the device or writing to read-only device memory.
"cmos_udi.c sample code (cont.)" |
---|
/* * PIO trans lists for access to the CMOS device. */ static udi_pio_trans_t cmos_trans_read[] = { /* R0 <- SCRATCH_ADDR {offset into scratch of address} */ { UDI_PIO_LOAD_IMM+UDI_PIO_R0, UDI_PIO_2BYTE, SCRATCH_ADDR }, /* R1 <- address */ { UDI_PIO_LOAD+UDI_PIO_SCRATCH+UDI_PIO_R0, UDI_PIO_1BYTE, UDI_PIO_R1 }, /* R0 <- SCRATCH_COUNT {offset into scratch of count} */ { UDI_PIO_LOAD_IMM+UDI_PIO_R0, UDI_PIO_2BYTE, SCRATCH_COUNT }, /* R2 <- count */ { UDI_PIO_LOAD+UDI_PIO_SCRATCH+UDI_PIO_R0, UDI_PIO_1BYTE, UDI_PIO_R2 }, /* R0 <- 0 {current buffer offset} */ { UDI_PIO_LOAD_IMM+UDI_PIO_R0, UDI_PIO_2BYTE, 0 }, /* begin main loop */ { UDI_PIO_LABEL, 0, 1 }, /* output address from R1 to address register */ { UDI_PIO_OUT+UDI_PIO_DIRECT+UDI_PIO_R1, UDI_PIO_1BYTE, CMOS_ADDR }, /* input value from data register into next buffer location */ { UDI_PIO_IN+UDI_PIO_BUF+UDI_PIO_R0, UDI_PIO_1BYTE, CMOS_DATA }, /* decrement count (in R2) */ { UDI_PIO_ADD_IMM+UDI_PIO_R2, UDI_PIO_1BYTE, (udi_ubit8_t)-1 }, /* if count is zero, we're done */ { UDI_PIO_CSKIP+UDI_PIO_R2, UDI_PIO_1BYTE, UDI_PIO_NZ }, { UDI_PIO_END_IMM, UDI_PIO_2BYTE, 0 }, /* increment address and buffer offset */ { UDI_PIO_ADD_IMM+UDI_PIO_R1, UDI_PIO_1BYTE, 1 }, { UDI_PIO_ADD_IMM+UDI_PIO_R0, UDI_PIO_1BYTE, 1 }, /* go back to main loop */ { UDI_PIO_BRANCH, 0, 1 } }; static udi_pio_trans_t cmos_trans_write[] = { /* R0 <- SCRATCH_ADDR {offset into scratch of address} */ { UDI_PIO_LOAD_IMM+UDI_PIO_R0, UDI_PIO_2BYTE, SCRATCH_ADDR }, /* R1 <- address */ { UDI_PIO_LOAD+UDI_PIO_SCRATCH+UDI_PIO_R0, UDI_PIO_1BYTE, UDI_PIO_R1 }, /* R0 <- SCRATCH_COUNT {offset into scratch of count} */ { UDI_PIO_LOAD_IMM+UDI_PIO_R0, UDI_PIO_2BYTE, SCRATCH_COUNT }, /* R2 <- count */ { UDI_PIO_LOAD+UDI_PIO_SCRATCH+UDI_PIO_R0, UDI_PIO_1BYTE, UDI_PIO_R2 }, /* R0 <- 0 {current buffer offset} */ { UDI_PIO_LOAD_IMM+UDI_PIO_R0, UDI_PIO_2BYTE, 0 }, /* begin main loop */ { UDI_PIO_LABEL, 0, 1 }, /* output address from R1 to address register */ { UDI_PIO_OUT+UDI_PIO_DIRECT+UDI_PIO_R1, UDI_PIO_1BYTE, CMOS_ADDR }, /* output value from next buffer location to data register */ { UDI_PIO_OUT+UDI_PIO_BUF+UDI_PIO_R0, UDI_PIO_1BYTE, CMOS_DATA }, /* decrement count (in R2) */ { UDI_PIO_ADD_IMM+UDI_PIO_R2, UDI_PIO_1BYTE, (udi_ubit8_t)-1 }, /* if count is zero, we're done */ { UDI_PIO_CSKIP+UDI_PIO_R2, UDI_PIO_1BYTE, UDI_PIO_NZ }, { UDI_PIO_END_IMM, UDI_PIO_2BYTE, 0 }, /* increment address and buffer offset */ { UDI_PIO_ADD_IMM+UDI_PIO_R1, UDI_PIO_1BYTE, 1 }, { UDI_PIO_ADD_IMM+UDI_PIO_R0, UDI_PIO_1BYTE, 1 }, /* go back to main loop */ { UDI_PIO_BRANCH, 0, 1 } }; PIO transaction lists for cmos_udi
|
The figure above shows the transaction lists for the read and write PIO operations to the CMOS RAM device. Each of the array members of the cmos_trans_read[] array contains three values that specifies an atomic operation on the device. When the trans_read PIO transaction handle is specified with the udi_pio_trans environment call, the list of operations specified in the cmos_trans_read[] array is performed on the device. This is done in the driver subroutines described later.
Similar processing occurs with the cmos_trans_write[] array when the trans_write transaction handle is passed to udi_pio_trans.
As with device characteristics, the transaction lists necessary for any device are unique to that device.
The operation, register, and address mode constants used in the transaction lists ared defined in the Physical I/O Specification description of which documents transaction list syntax. The remainder are defined in the driver code.
Each cmos_trans_read[] and cmos_trans_write[] array element is a udi_pio_trans_t structure with three members:
typedef struct { udi_ubit8_t pio_op ; udi_ubit8_t tran_size ; udi_ubit16_t operand ; } udi_pio_trans_t ;
Simply put, these specify a PIO operation (such as a logical OR of a register and an operand), a transaction size specifying the size of the result of the operation, and any operand required by the PIO operation.
The cmos_trans_read[] PIO list, described below in detail, reads a data value from CMOS RAM and copies it to the scratch space in the control block passed as part of the channel operation invoking the PIO read.
Note that the UDI environment provides eight special registers for use in constructing transaction operations. We'll refer to these internal UDI registers in the same manner as the UDI Specification does, using the notations R0 through R7. We'll refer to registers on the device by spelling out the word ``register'' before the number.
addr
element in the
cmos_gio_xfer_scratch_t control block scratch space.
count
element in the
cmos_gio_xfer_scratch_t control block scratch space.
UDI_PIO_LABEL sets a label to which a subsequent UDI_PIO_BRANCH can switch control. The tran_size element is unused and must be set to zero. The operand element is set to a unique integer to be used as the operand of a subsequent UDI_PIO_BRANCH.
The transaction list for the cmos_trans_write[] array ia exactly the same as the read array described above, with the exception of transaction 8. In the write operation, a byte is read from the buffer into the CMOS RAM memory at the specified address. UDI_PIO_OUT sets the location on the PIO device at the offset specified by the operand (CMOS_DATA, or the CMOS RAM data register) to the one-byte value in the buffer at the 32-bit buffer offset in R0.
Transaction list usage is discussed further on, in the description of the CMOS RAM driver subroutines. More complex transaction lists will be discussed in the sections of this document on the SCSI HBA and NIC sample drivers.
In the UDI Specifications, see in the Physical I/O Specification for a complete list of operations, operation classes, addressing modes, and transaction list syntax.