RASCSI/src/raspberrypi/gpiobus.cpp
Uwe Seimet ea3bb8363a Squashed commit of the following:
commit 94786aec54
Author: Uwe Seimet <48174652+uweseimet@users.noreply.github.com>
Date:   Tue Dec 21 08:43:21 2021 +0100

    Added support for operation meta data, code cleanup (#534)

    * Added messages

    * Comment update

    * Interface update

    * Support for localized descriptions

    * Sort operations

    * Completed meta data

    * rasctl -s returns operation meta data

    * Manpage update

    * Type update

    * Comment update

    * Description updates

    * Comment update

    * Added convenience method

    * Added convenience method

    * Code cleanup

    * Comment update

    * Display permitted values

    * For completeness sake added permitted boolean values

    * Added support for default value

    * Removed redundant message field

    * Description update

    * Description upddate

    * Squashed commit of the following:

    commit 8171c6ea27982c736c30c0db69a7fdde07ee10ce
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:43:14 2021 +0100

        The data type is implicit

    commit fb01dc9d82e8ff7456b05a0cb9d08069adacc64c
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:37:49 2021 +0100

        Renaming

    commit 057dbf1aca7be3f7e76a5ff89a582a276b6d3089
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:29:54 2021 +0100

        Comment update

    commit 5f699aad2f835f72accdb445d1e59f094aeb108f
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:24:25 2021 +0100

        Signature update

    commit cbcf8b09f9d1ba7b82f816269bcfe91d9f00eb6e
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:22:45 2021 +0100

        Signature update

    commit a8148ef802ca809e5a305d2caa69856c9033d932
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:16:46 2021 +0100

        Comment update

    commit ce685a92d4827e131d80d10ecd56e2b3baf173f8
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:15:46 2021 +0100

        Use map instead of list

    commit 454c0438f3589904f5dbe5253963dd200ea416dd
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 10:47:36 2021 +0100

        Updated size check

    commit b386dbba4b0262f4f6f02aecb2a1daeffd41f4a2
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 01:23:43 2021 +0100

        Initial improvements

    * Default value update

    * Comment update

    * Comment update

    * Map operations by ordinal

    * Added safeguard against unknown operations

    * Added cast

    * Data type update

    * Sort map by operation name

    * Renaming

    * Code cleanup

    * Comment update

    * Renaming

    * Comment update

    * Description updates

    * Fixed typo

    * Added operation

    * Logging update

    * Interface comment update

    * Fixed typo

    * Aded operation parameters

    * Updated handling of mandatory parameters

    * Updated assertion handling

    * Added missing condition

    * Removed duplicate cod3

    * Code cleanup

    * Logging update

    * Removed duplicate code

    * Code cleanup

    * Squashed commit of the following:

    commit 4ae273ccbd
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 22:30:22 2021 -0600

        Loopback tester pcb (#545)

    commit 46c5c1966f
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 22:29:59 2021 -0600

        RaSCSI Zero version 1.0 (#546)

    commit d09df31d67
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 20:25:23 2021 -0800

        Remove redundant code from OLED script (#547)

    commit d8828da690
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 21:02:50 2021 -0600

        Added list of sponsors

    commit bcd7e8396d
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:51:45 2021 -0800

        Second attempt at properly creating the manpage dir (#542)

    commit c887edfc8c
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:50:03 2021 -0800

        Remove special elevated privileges for the Web Interface (#536)

        * Use the pi_shutdown method to restart the rascsi service

        * Use the pi_shutdown method to restart the rascsi service

        * Remove modifications to sudoers no longer needed

        * Introduce sleeps attempting to connect to socket; reduce overall number of retries

        * Remove systemd helped methods and the functionality that depends on it

        * Attempts to speed up splash code

        * Remove unneccessary verbosity

        * Attempt to optimize service definition

    commit 801aebfb96
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:47:22 2021 -0800

        More readable message when downloading a file (#531)

    commit 29cf58288f
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:47:03 2021 -0800

        Add a warning notice when ejecting removable media (#526)

    commit 7efa895239
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:46:22 2021 -0800

        Unzip zipfiles before storing to iso (#525)

        * Unzip zipfiles before storing to iso

        * Add helptext

        * Skip unzip for MacZip format

        * Should not be an fstring

    commit 39bc485671
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:28:22 2021 -0800

        Add pip3 to global dependencies; remove duplicates from monitor_rascs… (#523)

        * Add pip3 to global dependencies; remove duplicates from monitor_rascsi dependencies

        * Cleanup

    * Shutdown functionality is only available if started with root permissions

    * Only restrict shutdown parameters, not everything if not root

    * Updated operation count check

commit 693ade2967
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Mon Dec 20 12:04:23 2021 -0800

    Bump Macproxy version to 21.12.2 (#550)

commit 958fb95908
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Mon Dec 20 12:50:14 2021 -0600

    Adjust bus settle delay to match SCSI standard (#544)

    * Move the GCC v10 compiler flags into makefile instead of easyinstall.sh

    * #504 - Update the bus settle time to match the SCSI standard

    Co-authored-by: RaSCSI User <user@rascsi.com>

commit 200bc7251f
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Mon Dec 20 06:20:22 2021 -0800

    More helpful error message when IP does not resolve for OLED screen (#541)

    * More helpful error message

    * Remove confusing fallback IP

    * Tweak message

commit 4ae273ccbd
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 22:30:22 2021 -0600

    Loopback tester pcb (#545)

commit 46c5c1966f
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 22:29:59 2021 -0600

    RaSCSI Zero version 1.0 (#546)

commit d09df31d67
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 20:25:23 2021 -0800

    Remove redundant code from OLED script (#547)

commit d8828da690
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 21:02:50 2021 -0600

    Added list of sponsors

commit bcd7e8396d
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:51:45 2021 -0800

    Second attempt at properly creating the manpage dir (#542)

commit c887edfc8c
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:50:03 2021 -0800

    Remove special elevated privileges for the Web Interface (#536)

    * Use the pi_shutdown method to restart the rascsi service

    * Use the pi_shutdown method to restart the rascsi service

    * Remove modifications to sudoers no longer needed

    * Introduce sleeps attempting to connect to socket; reduce overall number of retries

    * Remove systemd helped methods and the functionality that depends on it

    * Attempts to speed up splash code

    * Remove unneccessary verbosity

    * Attempt to optimize service definition

commit 801aebfb96
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:47:22 2021 -0800

    More readable message when downloading a file (#531)

commit 29cf58288f
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:47:03 2021 -0800

    Add a warning notice when ejecting removable media (#526)

commit 7efa895239
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:46:22 2021 -0800

    Unzip zipfiles before storing to iso (#525)

    * Unzip zipfiles before storing to iso

    * Add helptext

    * Skip unzip for MacZip format

    * Should not be an fstring

commit 39bc485671
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:28:22 2021 -0800

    Add pip3 to global dependencies; remove duplicates from monitor_rascs… (#523)

    * Add pip3 to global dependencies; remove duplicates from monitor_rascsi dependencies

    * Cleanup
2021-12-21 08:53:30 +01:00

1685 lines
37 KiB
C++

//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS
//
// Imported NetBSD support and some optimisation patch by Rin Okuyama.
//
// [ GPIO-SCSI bus ]
//
//---------------------------------------------------------------------------
#include <sys/mman.h>
#include "os.h"
#include "gpiobus.h"
#include "log.h"
#include "rascsi.h"
#ifdef __linux__
//---------------------------------------------------------------------------
//
// imported from bcm_host.c
//
//---------------------------------------------------------------------------
static DWORD get_dt_ranges(const char *filename, DWORD offset)
{
DWORD address = ~0;
FILE *fp = fopen(filename, "rb");
if (fp) {
fseek(fp, offset, SEEK_SET);
BYTE buf[4];
if (fread(buf, 1, sizeof buf, fp) == sizeof buf) {
address =
buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
}
fclose(fp);
}
return address;
}
DWORD bcm_host_get_peripheral_address(void)
{
DWORD address = get_dt_ranges("/proc/device-tree/soc/ranges", 4);
if (address == 0) {
address = get_dt_ranges("/proc/device-tree/soc/ranges", 8);
}
address = (address == (DWORD)~0) ? 0x20000000 : address;
#if 0
printf("Peripheral address : 0x%lx\n", address);
#endif
return address;
}
#endif // __linux__
#ifdef __NetBSD__
// Assume the Raspberry Pi series and estimate the address from CPU
DWORD bcm_host_get_peripheral_address(void)
{
char buf[1024];
size_t len = sizeof(buf);
DWORD address;
if (sysctlbyname("hw.model", buf, &len, NULL, 0) ||
strstr(buf, "ARM1176JZ-S") != buf) {
// Failed to get CPU model || Not BCM2835
// use the address of BCM283[67]
address = 0x3f000000;
} else {
// Use BCM2835 address
address = 0x20000000;
}
printf("Peripheral address : 0x%lx\n", address);
return address;
}
#endif // __NetBSD__
GPIOBUS::GPIOBUS()
{
actmode = TARGET;
baseaddr = 0;
gicc = 0;
gicd = 0;
gpio = 0;
level = 0;
pads = 0;
irpctl = 0;
qa7regs = 0;
signals = 0;
rpitype = 0;
}
GPIOBUS::~GPIOBUS()
{
}
BOOL GPIOBUS::Init(mode_e mode)
{
#if defined(__x86_64__) || defined(__X86__)
// When we're running on x86, there is no hardware to talk to, so just return.
return true;
#else
void *map;
int i;
int j;
int pullmode;
int fd;
#ifdef USE_SEL_EVENT_ENABLE
struct epoll_event ev;
#endif // USE_SEL_EVENT_ENABLE
// Save operation mode
actmode = mode;
// Get the base address
baseaddr = (DWORD)bcm_host_get_peripheral_address();
// Open /dev/mem
fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1) {
LOGERROR("Error: Unable to open /dev/mem. Are you running as root?");
return FALSE;
}
// Map peripheral region memory
map = mmap(NULL, 0x1000100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, baseaddr);
if (map == MAP_FAILED) {
LOGERROR("Error: Unable to map memory");
close(fd);
return FALSE;
}
// Determine the type of raspberry pi from the base address
if (baseaddr == 0xfe000000) {
rpitype = 4;
} else if (baseaddr == 0x3f000000) {
rpitype = 2;
} else {
rpitype = 1;
}
// GPIO
gpio = (DWORD *)map;
gpio += GPIO_OFFSET / sizeof(DWORD);
level = &gpio[GPIO_LEV_0];
// PADS
pads = (DWORD *)map;
pads += PADS_OFFSET / sizeof(DWORD);
// System timer
SysTimer::Init(
(DWORD *)map + SYST_OFFSET / sizeof(DWORD),
(DWORD *)map + ARMT_OFFSET / sizeof(DWORD));
// Interrupt controller
irpctl = (DWORD *)map;
irpctl += IRPT_OFFSET / sizeof(DWORD);
// Quad-A7 control
qa7regs = (DWORD *)map;
qa7regs += QA7_OFFSET / sizeof(DWORD);
// Map GIC memory
if (rpitype == 4) {
map = mmap(NULL, 8192,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, ARM_GICD_BASE);
if (map == MAP_FAILED) {
close(fd);
return FALSE;
}
gicd = (DWORD *)map;
gicc = (DWORD *)map;
gicc += (ARM_GICC_BASE - ARM_GICD_BASE) / sizeof(DWORD);
} else {
gicd = NULL;
gicc = NULL;
}
close(fd);
// Set Drive Strength to 16mA
DrvConfig(7);
// Set pull up/pull down
#if SIGNAL_CONTROL_MODE == 0
pullmode = GPIO_PULLNONE;
#elif SIGNAL_CONTROL_MODE == 1
pullmode = GPIO_PULLUP;
#else
pullmode = GPIO_PULLDOWN;
#endif
// Initialize all signals
for (i = 0; SignalTable[i] >= 0; i++) {
j = SignalTable[i];
PinSetSignal(j, FALSE);
PinConfig(j, GPIO_INPUT);
PullConfig(j, pullmode);
}
// Set control signals
PinSetSignal(PIN_ACT, FALSE);
PinSetSignal(PIN_TAD, FALSE);
PinSetSignal(PIN_IND, FALSE);
PinSetSignal(PIN_DTD, FALSE);
PinConfig(PIN_ACT, GPIO_OUTPUT);
PinConfig(PIN_TAD, GPIO_OUTPUT);
PinConfig(PIN_IND, GPIO_OUTPUT);
PinConfig(PIN_DTD, GPIO_OUTPUT);
// Set the ENABLE signal
// This is used to show that the application is running
PinSetSignal(PIN_ENB, ENB_OFF);
PinConfig(PIN_ENB, GPIO_OUTPUT);
// GPFSEL backup
gpfsel[0] = gpio[GPIO_FSEL_0];
gpfsel[1] = gpio[GPIO_FSEL_1];
gpfsel[2] = gpio[GPIO_FSEL_2];
gpfsel[3] = gpio[GPIO_FSEL_3];
// Initialize SEL signal interrupt
#ifdef USE_SEL_EVENT_ENABLE
// GPIO chip open
fd = open("/dev/gpiochip0", 0);
if (fd == -1) {
LOGERROR("Unable to open /dev/gpiochip0. Is RaSCSI already running?")
return FALSE;
}
// Event request setting
strcpy(selevreq.consumer_label, "RaSCSI");
selevreq.lineoffset = PIN_SEL;
selevreq.handleflags = GPIOHANDLE_REQUEST_INPUT;
#if SIGNAL_CONTROL_MODE < 2
selevreq.eventflags = GPIOEVENT_REQUEST_FALLING_EDGE;
#else
selevreq.eventflags = GPIOEVENT_REQUEST_RISING_EDGE;
#endif // SIGNAL_CONTROL_MODE
//Get event request
if (ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &selevreq) == -1) {
LOGERROR("Unable to register event request. Is RaSCSI already running?")
close(fd);
return FALSE;
}
// Close GPIO chip file handle
close(fd);
// epoll initialization
epfd = epoll_create(1);
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN | EPOLLPRI;
ev.data.fd = selevreq.fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, selevreq.fd, &ev);
#else
// Edge detection setting
#if SIGNAL_CONTROL_MODE == 2
gpio[GPIO_AREN_0] = 1 << PIN_SEL;
#else
gpio[GPIO_AFEN_0] = 1 << PIN_SEL;
#endif // SIGNAL_CONTROL_MODE
// Clear event
gpio[GPIO_EDS_0] = 1 << PIN_SEL;
// Register interrupt handler
setIrqFuncAddress(IrqHandler);
// GPIO interrupt setting
if (rpitype == 4) {
// GIC Invalid
gicd[GICD_CTLR] = 0;
// Route all interupts to core 0
for (i = 0; i < 8; i++) {
gicd[GICD_ICENABLER0 + i] = 0xffffffff;
gicd[GICD_ICPENDR0 + i] = 0xffffffff;
gicd[GICD_ICACTIVER0 + i] = 0xffffffff;
}
for (i = 0; i < 64; i++) {
gicd[GICD_IPRIORITYR0 + i] = 0xa0a0a0a0;
gicd[GICD_ITARGETSR0 + i] = 0x01010101;
}
// Set all interrupts as level triggers
for (i = 0; i < 16; i++) {
gicd[GICD_ICFGR0 + i] = 0;
}
// GIC Invalid
gicd[GICD_CTLR] = 1;
// Enable CPU interface for core 0
gicc[GICC_PMR] = 0xf0;
gicc[GICC_CTLR] = 1;
// Enable interrupts
gicd[GICD_ISENABLER0 + (GIC_GPIO_IRQ / 32)] =
1 << (GIC_GPIO_IRQ % 32);
} else {
// Enable interrupts
irpctl[IRPT_ENB_IRQ_2] = (1 << (GPIO_IRQ % 32));
}
#endif // USE_SEL_EVENT_ENABLE
// Create work table
MakeTable();
// Finally, enable ENABLE
// Show the user that this app is running
SetControl(PIN_ENB, ENB_ON);
return TRUE;
#endif // ifdef __x86_64__ || __X86__
}
void GPIOBUS::Cleanup()
{
#if defined(__x86_64__) || defined(__X86__)
return;
#else
int i;
int pin;
// Release SEL signal interrupt
#ifdef USE_SEL_EVENT_ENABLE
close(selevreq.fd);
#endif // USE_SEL_EVENT_ENABLE
// Set control signals
PinSetSignal(PIN_ENB, FALSE);
PinSetSignal(PIN_ACT, FALSE);
PinSetSignal(PIN_TAD, FALSE);
PinSetSignal(PIN_IND, FALSE);
PinSetSignal(PIN_DTD, FALSE);
PinConfig(PIN_ACT, GPIO_INPUT);
PinConfig(PIN_TAD, GPIO_INPUT);
PinConfig(PIN_IND, GPIO_INPUT);
PinConfig(PIN_DTD, GPIO_INPUT);
// Initialize all signals
for (i = 0; SignalTable[i] >= 0; i++) {
pin = SignalTable[i];
PinSetSignal(pin, FALSE);
PinConfig(pin, GPIO_INPUT);
PullConfig(pin, GPIO_PULLNONE);
}
// Set drive strength back to 8mA
DrvConfig(3);
#endif // ifdef __x86_64__ || __X86__
}
void GPIOBUS::Reset()
{
#if defined(__x86_64__) || defined(__X86__)
return;
#else
int i;
int j;
// Turn off active signal
SetControl(PIN_ACT, ACT_OFF);
// Set all signals to off
for (i = 0;; i++) {
j = SignalTable[i];
if (j < 0) {
break;
}
SetSignal(j, OFF);
}
if (actmode == TARGET) {
// Target mode
// Set target signal to input
SetControl(PIN_TAD, TAD_IN);
SetMode(PIN_BSY, IN);
SetMode(PIN_MSG, IN);
SetMode(PIN_CD, IN);
SetMode(PIN_REQ, IN);
SetMode(PIN_IO, IN);
// Set the initiator signal to input
SetControl(PIN_IND, IND_IN);
SetMode(PIN_SEL, IN);
SetMode(PIN_ATN, IN);
SetMode(PIN_ACK, IN);
SetMode(PIN_RST, IN);
// Set data bus signals to input
SetControl(PIN_DTD, DTD_IN);
SetMode(PIN_DT0, IN);
SetMode(PIN_DT1, IN);
SetMode(PIN_DT2, IN);
SetMode(PIN_DT3, IN);
SetMode(PIN_DT4, IN);
SetMode(PIN_DT5, IN);
SetMode(PIN_DT6, IN);
SetMode(PIN_DT7, IN);
SetMode(PIN_DP, IN);
} else {
// Initiator mode
// Set target signal to input
SetControl(PIN_TAD, TAD_IN);
SetMode(PIN_BSY, IN);
SetMode(PIN_MSG, IN);
SetMode(PIN_CD, IN);
SetMode(PIN_REQ, IN);
SetMode(PIN_IO, IN);
// Set the initiator signal to output
SetControl(PIN_IND, IND_OUT);
SetMode(PIN_SEL, OUT);
SetMode(PIN_ATN, OUT);
SetMode(PIN_ACK, OUT);
SetMode(PIN_RST, OUT);
// Set the data bus signals to output
SetControl(PIN_DTD, DTD_OUT);
SetMode(PIN_DT0, OUT);
SetMode(PIN_DT1, OUT);
SetMode(PIN_DT2, OUT);
SetMode(PIN_DT3, OUT);
SetMode(PIN_DT4, OUT);
SetMode(PIN_DT5, OUT);
SetMode(PIN_DT6, OUT);
SetMode(PIN_DT7, OUT);
SetMode(PIN_DP, OUT);
}
// Initialize all signals
signals = 0;
#endif // ifdef __x86_64__ || __X86__
}
//---------------------------------------------------------------------------
//
// ENB signal setting
//
//---------------------------------------------------------------------------
void GPIOBUS::SetENB(BOOL ast)
{
PinSetSignal(PIN_ENB, ast ? ENB_ON : ENB_OFF);
}
//---------------------------------------------------------------------------
//
// Get BSY signal
//
//---------------------------------------------------------------------------
bool GPIOBUS::GetBSY()
{
return GetSignal(PIN_BSY);
}
//---------------------------------------------------------------------------
//
// Set BSY signal
//
//---------------------------------------------------------------------------
void GPIOBUS::SetBSY(bool ast)
{
// Set BSY signal
SetSignal(PIN_BSY, ast);
if (actmode == TARGET) {
if (ast) {
// Turn on ACTIVE signal
SetControl(PIN_ACT, ACT_ON);
// Set Target signal to output
SetControl(PIN_TAD, TAD_OUT);
SetMode(PIN_BSY, OUT);
SetMode(PIN_MSG, OUT);
SetMode(PIN_CD, OUT);
SetMode(PIN_REQ, OUT);
SetMode(PIN_IO, OUT);
} else {
// Turn off the ACTIVE signal
SetControl(PIN_ACT, ACT_OFF);
// Set the target signal to input
SetControl(PIN_TAD, TAD_IN);
SetMode(PIN_BSY, IN);
SetMode(PIN_MSG, IN);
SetMode(PIN_CD, IN);
SetMode(PIN_REQ, IN);
SetMode(PIN_IO, IN);
}
}
}
//---------------------------------------------------------------------------
//
// Get SEL signal
//
//---------------------------------------------------------------------------
BOOL GPIOBUS::GetSEL()
{
return GetSignal(PIN_SEL);
}
//---------------------------------------------------------------------------
//
// Set SEL signal
//
//---------------------------------------------------------------------------
void GPIOBUS::SetSEL(BOOL ast)
{
if (actmode == INITIATOR && ast) {
// Turn on ACTIVE signal
SetControl(PIN_ACT, ACT_ON);
}
// Set SEL signal
SetSignal(PIN_SEL, ast);
}
//---------------------------------------------------------------------------
//
// Get ATN signal
//
//---------------------------------------------------------------------------
BOOL GPIOBUS::GetATN()
{
return GetSignal(PIN_ATN);
}
//---------------------------------------------------------------------------
//
// Get ATN signal
//
//---------------------------------------------------------------------------
void GPIOBUS::SetATN(BOOL ast)
{
SetSignal(PIN_ATN, ast);
}
//---------------------------------------------------------------------------
//
// Get ACK signal
//
//---------------------------------------------------------------------------
BOOL GPIOBUS::GetACK()
{
return GetSignal(PIN_ACK);
}
//---------------------------------------------------------------------------
//
// Set ACK signal
//
//---------------------------------------------------------------------------
void GPIOBUS::SetACK(BOOL ast)
{
SetSignal(PIN_ACK, ast);
}
//---------------------------------------------------------------------------
//
// Get ACK signal
//
//---------------------------------------------------------------------------
BOOL GPIOBUS::GetACT()
{
return GetSignal(PIN_ACT);
}
//---------------------------------------------------------------------------
//
// Set ACK signal
//
//---------------------------------------------------------------------------
void GPIOBUS::SetACT(BOOL ast)
{
SetSignal(PIN_ACT, ast);
}
//---------------------------------------------------------------------------
//
// Get RST signal
//
//---------------------------------------------------------------------------
BOOL GPIOBUS::GetRST()
{
return GetSignal(PIN_RST);
}
//---------------------------------------------------------------------------
//
// Set RST signal
//
//---------------------------------------------------------------------------
void GPIOBUS::SetRST(BOOL ast)
{
SetSignal(PIN_RST, ast);
}
//---------------------------------------------------------------------------
//
// Get MSG signal
//
//---------------------------------------------------------------------------
BOOL GPIOBUS::GetMSG()
{
return GetSignal(PIN_MSG);
}
//---------------------------------------------------------------------------
//
// Set MSG signal
//
//---------------------------------------------------------------------------
void GPIOBUS::SetMSG(BOOL ast)
{
SetSignal(PIN_MSG, ast);
}
//---------------------------------------------------------------------------
//
// Get CD signal
//
//---------------------------------------------------------------------------
BOOL GPIOBUS::GetCD()
{
return GetSignal(PIN_CD);
}
//---------------------------------------------------------------------------
//
// Set CD Signal
//
//---------------------------------------------------------------------------
void GPIOBUS::SetCD(BOOL ast)
{
SetSignal(PIN_CD, ast);
}
//---------------------------------------------------------------------------
//
// Get IO Signal
//
//---------------------------------------------------------------------------
BOOL GPIOBUS::GetIO()
{
BOOL ast = GetSignal(PIN_IO);
if (actmode == INITIATOR) {
// Change the data input/output direction by IO signal
if (ast) {
SetControl(PIN_DTD, DTD_IN);
SetMode(PIN_DT0, IN);
SetMode(PIN_DT1, IN);
SetMode(PIN_DT2, IN);
SetMode(PIN_DT3, IN);
SetMode(PIN_DT4, IN);
SetMode(PIN_DT5, IN);
SetMode(PIN_DT6, IN);
SetMode(PIN_DT7, IN);
SetMode(PIN_DP, IN);
} else {
SetControl(PIN_DTD, DTD_OUT);
SetMode(PIN_DT0, OUT);
SetMode(PIN_DT1, OUT);
SetMode(PIN_DT2, OUT);
SetMode(PIN_DT3, OUT);
SetMode(PIN_DT4, OUT);
SetMode(PIN_DT5, OUT);
SetMode(PIN_DT6, OUT);
SetMode(PIN_DT7, OUT);
SetMode(PIN_DP, OUT);
}
}
return ast;
}
//---------------------------------------------------------------------------
//
// Set IO signal
//
//---------------------------------------------------------------------------
void GPIOBUS::SetIO(BOOL ast)
{
SetSignal(PIN_IO, ast);
if (actmode == TARGET) {
// Change the data input/output direction by IO signal
if (ast) {
SetControl(PIN_DTD, DTD_OUT);
SetDAT(0);
SetMode(PIN_DT0, OUT);
SetMode(PIN_DT1, OUT);
SetMode(PIN_DT2, OUT);
SetMode(PIN_DT3, OUT);
SetMode(PIN_DT4, OUT);
SetMode(PIN_DT5, OUT);
SetMode(PIN_DT6, OUT);
SetMode(PIN_DT7, OUT);
SetMode(PIN_DP, OUT);
} else {
SetControl(PIN_DTD, DTD_IN);
SetMode(PIN_DT0, IN);
SetMode(PIN_DT1, IN);
SetMode(PIN_DT2, IN);
SetMode(PIN_DT3, IN);
SetMode(PIN_DT4, IN);
SetMode(PIN_DT5, IN);
SetMode(PIN_DT6, IN);
SetMode(PIN_DT7, IN);
SetMode(PIN_DP, IN);
}
}
}
//---------------------------------------------------------------------------
//
// Get REQ signal
//
//---------------------------------------------------------------------------
BOOL GPIOBUS::GetREQ()
{
return GetSignal(PIN_REQ);
}
//---------------------------------------------------------------------------
//
// Set REQ signal
//
//---------------------------------------------------------------------------
void GPIOBUS::SetREQ(BOOL ast)
{
SetSignal(PIN_REQ, ast);
}
//---------------------------------------------------------------------------
//
// Get data signals
//
//---------------------------------------------------------------------------
BYTE GPIOBUS::GetDAT()
{
DWORD data = Aquire();
data =
((data >> (PIN_DT0 - 0)) & (1 << 0)) |
((data >> (PIN_DT1 - 1)) & (1 << 1)) |
((data >> (PIN_DT2 - 2)) & (1 << 2)) |
((data >> (PIN_DT3 - 3)) & (1 << 3)) |
((data >> (PIN_DT4 - 4)) & (1 << 4)) |
((data >> (PIN_DT5 - 5)) & (1 << 5)) |
((data >> (PIN_DT6 - 6)) & (1 << 6)) |
((data >> (PIN_DT7 - 7)) & (1 << 7));
return (BYTE)data;
}
//---------------------------------------------------------------------------
//
// Set data signals
//
//---------------------------------------------------------------------------
void GPIOBUS::SetDAT(BYTE dat)
{
// Write to port
#if SIGNAL_CONTROL_MODE == 0
DWORD fsel = gpfsel[0];
fsel &= tblDatMsk[0][dat];
fsel |= tblDatSet[0][dat];
if (fsel != gpfsel[0]) {
gpfsel[0] = fsel;
gpio[GPIO_FSEL_0] = fsel;
}
fsel = gpfsel[1];
fsel &= tblDatMsk[1][dat];
fsel |= tblDatSet[1][dat];
if (fsel != gpfsel[1]) {
gpfsel[1] = fsel;
gpio[GPIO_FSEL_1] = fsel;
}
fsel = gpfsel[2];
fsel &= tblDatMsk[2][dat];
fsel |= tblDatSet[2][dat];
if (fsel != gpfsel[2]) {
gpfsel[2] = fsel;
gpio[GPIO_FSEL_2] = fsel;
}
#else
gpio[GPIO_CLR_0] = tblDatMsk[dat];
gpio[GPIO_SET_0] = tblDatSet[dat];
#endif // SIGNAL_CONTROL_MODE
}
//---------------------------------------------------------------------------
//
// Get data parity signal
//
//---------------------------------------------------------------------------
BOOL GPIOBUS::GetDP()
{
return GetSignal(PIN_DP);
}
//---------------------------------------------------------------------------
//
// Receive command handshake
//
//---------------------------------------------------------------------------
int GPIOBUS::CommandHandShake(BYTE *buf)
{
int count;
// Only works in TARGET mode
if (actmode != TARGET) {
return 0;
}
// IRQs disabled
DisableIRQ();
// Get the first command byte
int i = 0;
// Assert REQ signal
SetSignal(PIN_REQ, ON);
// Wait for ACK signal
BOOL ret = WaitSignal(PIN_ACK, TRUE);
// Wait until the signal line stabilizes
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
// Get data
*buf = GetDAT();
// Disable REQ signal
SetSignal(PIN_REQ, OFF);
// Timeout waiting for ACK assertion
if (!ret) {
goto irq_enable_exit;
}
// Wait for ACK to clear
ret = WaitSignal(PIN_ACK, FALSE);
// Timeout waiting for ACK to clear
if (!ret) {
goto irq_enable_exit;
}
count = GetCommandByteCount(*buf);
// Increment buffer pointer
buf++;
for (i = 1; i < count; i++) {
// Assert REQ signal
SetSignal(PIN_REQ, ON);
// Wait for ACK signal
ret = WaitSignal(PIN_ACK, TRUE);
// Wait until the signal line stabilizes
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
// Get data
*buf = GetDAT();
// Clear the REQ signal
SetSignal(PIN_REQ, OFF);
// Check for timeout waiting for ACK assertion
if (!ret) {
break;
}
// Wait for ACK to clear
ret = WaitSignal(PIN_ACK, FALSE);
// Check for timeout waiting for ACK to clear
if (!ret) {
break;
}
// Advance the buffer pointer to receive the next byte
buf++;
}
irq_enable_exit:
// IRQs enabled
EnableIRQ();
// returned the number of bytes received
return i;
}
//---------------------------------------------------------------------------
//
// Data reception handshake
//
//---------------------------------------------------------------------------
int GPIOBUS::ReceiveHandShake(BYTE *buf, int count)
{
int i;
BOOL ret;
DWORD phase;
// Disable IRQs
DisableIRQ();
if (actmode == TARGET) {
for (i = 0; i < count; i++) {
// Assert the REQ signal
SetSignal(PIN_REQ, ON);
// Wait for ACK
ret = WaitSignal(PIN_ACK, TRUE);
// Wait until the signal line stabilizes
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
// Get data
*buf = GetDAT();
// Clear the REQ signal
SetSignal(PIN_REQ, OFF);
// Check for timeout waiting for ACK signal
if (!ret) {
break;
}
// Wait for ACK to clear
ret = WaitSignal(PIN_ACK, FALSE);
// Check for timeout waiting for ACK to clear
if (!ret) {
break;
}
// Advance the buffer pointer to receive the next byte
buf++;
}
} else {
// Get phase
phase = Aquire() & GPIO_MCI;
for (i = 0; i < count; i++) {
// Wait for the REQ signal to be asserted
ret = WaitSignal(PIN_REQ, TRUE);
// Check for timeout waiting for REQ signal
if (!ret) {
break;
}
// Phase error
if ((signals & GPIO_MCI) != phase) {
break;
}
// Wait until the signal line stabilizes
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
// Get data
*buf = GetDAT();
// Assert the ACK signal
SetSignal(PIN_ACK, ON);
// Wait for REQ to clear
ret = WaitSignal(PIN_REQ, FALSE);
// Clear the ACK signal
SetSignal(PIN_ACK, OFF);
// Check for timeout waiting for REQ to clear
if (!ret) {
break;
}
// Phase error
if ((signals & GPIO_MCI) != phase) {
break;
}
// Advance the buffer pointer to receive the next byte
buf++;
}
}
// Re-enable IRQ
EnableIRQ();
// Return the number of bytes received
return i;
}
//---------------------------------------------------------------------------
//
// Data transmission handshake
//
//---------------------------------------------------------------------------
int GPIOBUS::SendHandShake(BYTE *buf, int count, int delay_after_bytes)
{
int i;
// Disable IRQs
DisableIRQ();
if (actmode == TARGET) {
for (i = 0; i < count; i++) {
if(i==delay_after_bytes){
LOGTRACE("%s DELAYING for %dus after %d bytes", __PRETTY_FUNCTION__, SCSI_DELAY_SEND_DATA_DAYNAPORT_US, (int)delay_after_bytes);
SysTimer::SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US);
}
// Set the DATA signals
SetDAT(*buf);
// Wait for ACK to clear
BOOL ret = WaitSignal(PIN_ACK, FALSE);
// Check for timeout waiting for ACK to clear
if (!ret) {
break;
}
// Already waiting for ACK to clear
// Assert the REQ signal
SetSignal(PIN_REQ, ON);
// Wait for ACK
ret = WaitSignal(PIN_ACK, TRUE);
// Clear REQ signal
SetSignal(PIN_REQ, OFF);
// Check for timeout waiting for ACK to clear
if (!ret) {
break;
}
// Advance the data buffer pointer to receive the next byte
buf++;
}
// Wait for ACK to clear
WaitSignal(PIN_ACK, FALSE);
} else {
// Get Phase
DWORD phase = Aquire() & GPIO_MCI;
for (i = 0; i < count; i++) {
if(i==delay_after_bytes){
LOGTRACE("%s DELAYING for %dus after %d bytes", __PRETTY_FUNCTION__, SCSI_DELAY_SEND_DATA_DAYNAPORT_US, (int)delay_after_bytes);
SysTimer::SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US);
}
// Set the DATA signals
SetDAT(*buf);
// Wait for REQ to be asserted
BOOL ret = WaitSignal(PIN_REQ, TRUE);
// Check for timeout waiting for REQ to be asserted
if (!ret) {
break;
}
// Phase error
if ((signals & GPIO_MCI) != phase) {
break;
}
// Already waiting for REQ assertion
// Assert the ACK signal
SetSignal(PIN_ACK, ON);
// Wait for REQ to clear
ret = WaitSignal(PIN_REQ, FALSE);
// Clear the ACK signal
SetSignal(PIN_ACK, OFF);
// Check for timeout waiting for REQ to clear
if (!ret) {
break;
}
// Phase error
if ((signals & GPIO_MCI) != phase) {
break;
}
// Advance the data buffer pointer to receive the next byte
buf++;
}
}
// Re-enable IRQ
EnableIRQ();
// Return number of transmissions
return i;
}
#ifdef USE_SEL_EVENT_ENABLE
//---------------------------------------------------------------------------
//
// SEL signal event polling
//
//---------------------------------------------------------------------------
int GPIOBUS::PollSelectEvent()
{
// clear errno
errno = 0;
struct epoll_event epev;
struct gpioevent_data gpev;
if (epoll_wait(epfd, &epev, 1, -1) <= 0) {
LOGWARN("%s epoll_wait failed", __PRETTY_FUNCTION__);
return -1;
}
if (read(selevreq.fd, &gpev, sizeof(gpev)) < 0) {
LOGWARN("%s read failed", __PRETTY_FUNCTION__);
return -1;
}
return 0;
}
//---------------------------------------------------------------------------
//
// Cancel SEL signal event
//
//---------------------------------------------------------------------------
void GPIOBUS::ClearSelectEvent()
{
}
#endif // USE_SEL_EVENT_ENABLE
//---------------------------------------------------------------------------
//
// Signal table
//
//---------------------------------------------------------------------------
const int GPIOBUS::SignalTable[19] = {
PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3,
PIN_DT4, PIN_DT5, PIN_DT6, PIN_DT7, PIN_DP,
PIN_SEL,PIN_ATN, PIN_RST, PIN_ACK,
PIN_BSY, PIN_MSG, PIN_CD, PIN_IO, PIN_REQ,
-1
};
//---------------------------------------------------------------------------
//
// Create work table
//
//---------------------------------------------------------------------------
void GPIOBUS::MakeTable(void)
{
const int pintbl[] = {
PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3, PIN_DT4,
PIN_DT5, PIN_DT6, PIN_DT7, PIN_DP
};
int i;
int j;
BOOL tblParity[256];
#if SIGNAL_CONTROL_MODE == 0
int index;
int shift;
#else
DWORD gpclr;
DWORD gpset;
#endif
// Create parity table
for (i = 0; i < 0x100; i++) {
DWORD bits = (DWORD)i;
DWORD parity = 0;
for (j = 0; j < 8; j++) {
parity ^= bits & 1;
bits >>= 1;
}
parity = ~parity;
tblParity[i] = parity & 1;
}
#if SIGNAL_CONTROL_MODE == 0
// Mask and setting data generation
memset(tblDatMsk, 0xff, sizeof(tblDatMsk));
memset(tblDatSet, 0x00, sizeof(tblDatSet));
for (i = 0; i < 0x100; i++) {
// Bit string for inspection
DWORD bits = (DWORD)i;
// Get parity
if (tblParity[i]) {
bits |= (1 << 8);
}
// Bit check
for (j = 0; j < 9; j++) {
// Index and shift amount calculation
index = pintbl[j] / 10;
shift = (pintbl[j] % 10) * 3;
// Mask data
tblDatMsk[index][i] &= ~(0x7 << shift);
// Setting data
if (bits & 1) {
tblDatSet[index][i] |= (1 << shift);
}
bits >>= 1;
}
}
#else
// Mask and setting data generation
memset(tblDatMsk, 0x00, sizeof(tblDatMsk));
memset(tblDatSet, 0x00, sizeof(tblDatSet));
for (i = 0; i < 0x100; i++) {
// bit string for inspection
DWORD bits = (DWORD)i;
// get parity
if (tblParity[i]) {
bits |= (1 << 8);
}
#if SIGNAL_CONTROL_MODE == 1
// Negative logic is inverted
bits = ~bits;
#endif
// Create GPIO register information
gpclr = 0;
gpset = 0;
for (j = 0; j < 9; j++) {
if (bits & 1) {
gpset |= (1 << pintbl[j]);
} else {
gpclr |= (1 << pintbl[j]);
}
bits >>= 1;
}
tblDatMsk[i] = gpclr;
tblDatSet[i] = gpset;
}
#endif
}
//---------------------------------------------------------------------------
//
// Control signal setting
//
//---------------------------------------------------------------------------
void GPIOBUS::SetControl(int pin, BOOL ast)
{
PinSetSignal(pin, ast);
}
//---------------------------------------------------------------------------
//
// Input/output mode setting
//
//---------------------------------------------------------------------------
void GPIOBUS::SetMode(int pin, int mode)
{
#if SIGNAL_CONTROL_MODE == 0
if (mode == OUT) {
return;
}
#endif // SIGNAL_CONTROL_MODE
int index = pin / 10;
int shift = (pin % 10) * 3;
DWORD data = gpfsel[index];
data &= ~(0x7 << shift);
if (mode == OUT) {
data |= (1 << shift);
}
gpio[index] = data;
gpfsel[index] = data;
}
//---------------------------------------------------------------------------
//
// Get input signal value
//
//---------------------------------------------------------------------------
BOOL GPIOBUS::GetSignal(int pin)
{
return (signals >> pin) & 1;
}
//---------------------------------------------------------------------------
//
// Set output signal value
//
//---------------------------------------------------------------------------
void GPIOBUS::SetSignal(int pin, BOOL ast)
{
#if SIGNAL_CONTROL_MODE == 0
int index = pin / 10;
int shift = (pin % 10) * 3;
DWORD data = gpfsel[index];
if (ast) {
data |= (1 << shift);
} else {
data &= ~(0x7 << shift);
}
gpio[index] = data;
gpfsel[index] = data;
#elif SIGNAL_CONTROL_MODE == 1
if (ast) {
gpio[GPIO_CLR_0] = 0x1 << pin;
} else {
gpio[GPIO_SET_0] = 0x1 << pin;
}
#elif SIGNAL_CONTROL_MODE == 2
if (ast) {
gpio[GPIO_SET_0] = 0x1 << pin;
} else {
gpio[GPIO_CLR_0] = 0x1 << pin;
}
#endif // SIGNAL_CONTROL_MODE
}
//---------------------------------------------------------------------------
//
// Wait for signal change
//
//---------------------------------------------------------------------------
BOOL GPIOBUS::WaitSignal(int pin, BOOL ast)
{
// Get current time
DWORD now = SysTimer::GetTimerLow();
// Calculate timeout (3000ms)
DWORD timeout = 3000 * 1000;
// end immediately if the signal has changed
do {
// Immediately upon receiving a reset
Aquire();
if (GetRST()) {
return FALSE;
}
// Check for the signal edge
if (((signals >> pin) ^ ~ast) & 1) {
return TRUE;
}
} while ((SysTimer::GetTimerLow() - now) < timeout);
// We timed out waiting for the signal
return FALSE;
}
//---------------------------------------------------------------------------
//
// Disable IRQ
//
//---------------------------------------------------------------------------
void GPIOBUS::DisableIRQ()
{
if (rpitype == 4) {
// RPI4 is disabled by GICC
giccpmr = gicc[GICC_PMR];
gicc[GICC_PMR] = 0;
} else if (rpitype == 2) {
// RPI2,3 disable core timer IRQ
tintcore = sched_getcpu() + QA7_CORE0_TINTC;
tintctl = qa7regs[tintcore];
qa7regs[tintcore] = 0;
} else {
// Stop system timer interrupt with interrupt controller
irptenb = irpctl[IRPT_ENB_IRQ_1];
irpctl[IRPT_DIS_IRQ_1] = irptenb & 0xf;
}
}
//---------------------------------------------------------------------------
//
// Enable IRQ
//
//---------------------------------------------------------------------------
void GPIOBUS::EnableIRQ()
{
if (rpitype == 4) {
// RPI4 enables interrupts via the GICC
gicc[GICC_PMR] = giccpmr;
} else if (rpitype == 2) {
// RPI2,3 re-enable core timer IRQ
qa7regs[tintcore] = tintctl;
} else {
// Restart the system timer interrupt with the interrupt controller
irpctl[IRPT_ENB_IRQ_1] = irptenb & 0xf;
}
}
//---------------------------------------------------------------------------
//
// Pin direction setting (input/output)
//
//---------------------------------------------------------------------------
void GPIOBUS::PinConfig(int pin, int mode)
{
// Check for invalid pin
if (pin < 0) {
return;
}
int index = pin / 10;
DWORD mask = ~(0x7 << ((pin % 10) * 3));
gpio[index] = (gpio[index] & mask) | ((mode & 0x7) << ((pin % 10) * 3));
}
//---------------------------------------------------------------------------
//
// Pin pull-up/pull-down setting
//
//---------------------------------------------------------------------------
void GPIOBUS::PullConfig(int pin, int mode)
{
DWORD pull;
// Check for invalid pin
if (pin < 0) {
return;
}
if (rpitype == 4) {
switch (mode) {
case GPIO_PULLNONE:
pull = 0;
break;
case GPIO_PULLUP:
pull = 1;
break;
case GPIO_PULLDOWN:
pull = 2;
break;
default:
return;
}
pin &= 0x1f;
int shift = (pin & 0xf) << 1;
DWORD bits = gpio[GPIO_PUPPDN0 + (pin >> 4)];
bits &= ~(3 << shift);
bits |= (pull << shift);
gpio[GPIO_PUPPDN0 + (pin >> 4)] = bits;
} else {
pin &= 0x1f;
gpio[GPIO_PUD] = mode & 0x3;
SysTimer::SleepUsec(2);
gpio[GPIO_CLK_0] = 0x1 << pin;
SysTimer::SleepUsec(2);
gpio[GPIO_PUD] = 0;
gpio[GPIO_CLK_0] = 0;
}
}
//---------------------------------------------------------------------------
//
// Set output pin
//
//---------------------------------------------------------------------------
void GPIOBUS::PinSetSignal(int pin, BOOL ast)
{
// Check for invalid pin
if (pin < 0) {
return;
}
if (ast) {
gpio[GPIO_SET_0] = 0x1 << pin;
} else {
gpio[GPIO_CLR_0] = 0x1 << pin;
}
}
//---------------------------------------------------------------------------
//
// Set the signal drive strength
//
//---------------------------------------------------------------------------
void GPIOBUS::DrvConfig(DWORD drive)
{
DWORD data = pads[PAD_0_27];
pads[PAD_0_27] = (0xFFFFFFF8 & data) | drive | 0x5a000000;
}
//---------------------------------------------------------------------------
//
// Generic Phase Acquisition (Doesn't read GPIO)
//
//---------------------------------------------------------------------------
BUS::phase_t GPIOBUS::GetPhaseRaw(DWORD raw_data)
{
// Selection Phase
if (GetPinRaw(raw_data, PIN_SEL))
{
if(GetPinRaw(raw_data, PIN_IO)){
return BUS::reselection;
}else{
return BUS::selection;
}
}
// Bus busy phase
if (!GetPinRaw(raw_data, PIN_BSY)) {
return BUS::busfree;
}
// Get target phase from bus signal line
DWORD mci = GetPinRaw(raw_data, PIN_MSG) ? 0x04 : 0x00;
mci |= GetPinRaw(raw_data, PIN_CD) ? 0x02 : 0x00;
mci |= GetPinRaw(raw_data, PIN_IO) ? 0x01 : 0x00;
return GetPhase(mci);
}
//---------------------------------------------------------------------------
//
// Get the number of bytes for a command
//
// TODO The command length should be determined based on the bytes transferred in the COMMAND phase
//
//---------------------------------------------------------------------------
int GPIOBUS::GetCommandByteCount(BYTE opcode) {
if (opcode == 0x88 || opcode == 0x8A || opcode == 0x8F || opcode == 0x91 || opcode == 0x9E || opcode == 0x9F) {
return 16;
}
else if (opcode == 0xA0) {
return 12;
}
else if (opcode >= 0x20 && opcode <= 0x7D) {
return 10;
} else {
return 6;
}
}
//---------------------------------------------------------------------------
//
// System timer address
//
//---------------------------------------------------------------------------
volatile DWORD* SysTimer::systaddr;
//---------------------------------------------------------------------------
//
// ARM timer address
//
//---------------------------------------------------------------------------
volatile DWORD* SysTimer::armtaddr;
//---------------------------------------------------------------------------
//
// Core frequency
//
//---------------------------------------------------------------------------
volatile DWORD SysTimer::corefreq;
//---------------------------------------------------------------------------
//
// Initialize the system timer
//
//---------------------------------------------------------------------------
void SysTimer::Init(DWORD *syst, DWORD *armt)
{
// RPI Mailbox property interface
// Get max clock rate
// Tag: 0x00030004
//
// Request: Length: 4
// Value: u32: clock id
// Response: Length: 8
// Value: u32: clock id, u32: rate (in Hz)
//
// Clock id
// 0x000000004: CORE
DWORD maxclock[32] = { 32, 0, 0x00030004, 8, 0, 4, 0, 0 };
// Save the base address
systaddr = syst;
armtaddr = armt;
// Change the ARM timer to free run mode
armtaddr[ARMT_CTRL] = 0x00000282;
// Get the core frequency
corefreq = 0;
int fd = open("/dev/vcio", O_RDONLY);
if (fd >= 0) {
ioctl(fd, _IOWR(100, 0, char *), maxclock);
corefreq = maxclock[6] / 1000000;
}
close(fd);
}
//---------------------------------------------------------------------------
//
// Get system timer low byte
//
//---------------------------------------------------------------------------
DWORD SysTimer::GetTimerLow() {
return systaddr[SYST_CLO];
}
//---------------------------------------------------------------------------
//
// Get system timer high byte
//
//---------------------------------------------------------------------------
DWORD SysTimer::GetTimerHigh() {
return systaddr[SYST_CHI];
}
//---------------------------------------------------------------------------
//
// Sleep in nanoseconds
//
//---------------------------------------------------------------------------
void SysTimer::SleepNsec(DWORD nsec)
{
// If time is 0, don't do anything
if (nsec == 0) {
return;
}
// Calculate the timer difference
DWORD diff = corefreq * nsec / 1000;
// Return if the difference in time is too small
if (diff == 0) {
return;
}
// Start
DWORD start = armtaddr[ARMT_FREERUN];
// Loop until timer has elapsed
while ((armtaddr[ARMT_FREERUN] - start) < diff);
}
//---------------------------------------------------------------------------
//
// Sleep in microseconds
//
//---------------------------------------------------------------------------
void SysTimer::SleepUsec(DWORD usec)
{
// If time is 0, don't do anything
if (usec == 0) {
return;
}
DWORD now = GetTimerLow();
while ((GetTimerLow() - now) < usec);
}