Commit a728de13 authored by Ben Avison's avatar Ben Avison
Browse files

Initial import of SDIOLib

parents
s/** gitlab-language=armasm linguist-language=armasm linguist-detectable=true
c/** gitlab-language=c linguist-language=c linguist-detectable=true
**/c/** gitlab-language=c linguist-language=c linguist-detectable=true
h/** gitlab-language=c linguist-language=c linguist-detectable=true
**/h/** gitlab-language=c linguist-language=c linguist-detectable=true
**/cmhg/** gitlab-language=cmhg linguist-language=cmhg linguist-detectable=true
/Makefile.d
/o/
/objs/
/oz/
/Test/FakeLibInt/aif/
/Test/FakeLibInt/aof/
/Test/FakeLibInt/gpa/
/Test/FakeLibInt/h/FakeLibIntHdr
/Test/FakeLibInt/i/
/Test/FakeLibInt/linked/
/Test/FakeLibInt/Makefile.d
/Test/FakeLibInt/o/
/Test/FakeLibInt/objs/
/Test/FakeLibInt/od/
/Test/FakeLibInt/rm/
include:
- project: 'Support/CI'
file: '/SDIOLib.yml'
Copyright (c) 2021 RISC OS Developments Ltd
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# Copyright (c) 2021 RISC OS Developments Ltd
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# Makefile for SDIO glue library
COMPONENT ?= SDIOLib
LIBRARIES = ${LIBRARYZM}
LIBRARY = unused
LIBRARYZM = ${TARGET}
VPATH = include${SEP}linux${SEP}mmc sys${SEP}dev${SEP}sdmmc
HDRS = card sdio_func sdmmcvar pm
OBJS = common common_asm sdio_io sdmmc_io
CFLAGS += ${C_NOWARN_NON_ANSI_INCLUDES}
CINCLUDES = -I${EXPDIR}${SEP}${TARGET}
SOURCES_TO_SYMLINK = $(wildcard include/linux/mmc/h/*) sys/dev/sdmmc/h/sdmmcvar
include CLibrary
ifeq (,${SUFFIX_HEADER})
SUBDIR_HEADER = .h
endif
card.exphdr: card.h
${MKDIR} ${EXPDIR}${SEP}linux${SEP}mmc${SUBDIR_HEADER}
${CP} $^ ${EXPDIR}${SEP}linux${SEP}mmc${SUBDIR_HEADER}${SEP}$*${SUFFIX_HEADER} ${CPFLAGS}
pm.exphdr: pm.h
${MKDIR} ${EXPDIR}${SEP}linux${SEP}mmc${SUBDIR_HEADER}
${CP} $^ ${EXPDIR}${SEP}linux${SEP}mmc${SUBDIR_HEADER}${SEP}$*${SUFFIX_HEADER} ${CPFLAGS}
sdio_func.exphdr: sdio_func.h
${MKDIR} ${EXPDIR}${SEP}linux${SEP}mmc${SUBDIR_HEADER}
${CP} $^ ${EXPDIR}${SEP}linux${SEP}mmc${SUBDIR_HEADER}${SEP}$*${SUFFIX_HEADER} ${CPFLAGS}
sdmmcvar.exphdr: sdmmcvar.h
${MKDIR} ${EXPDIR}${SEP}sys${SEP}dev${SEP}sdmmc${SUBDIR_HEADER}
${CP} $^ ${EXPDIR}${SEP}sys${SEP}dev${SEP}sdmmc${SUBDIR_HEADER}${SEP}$*${SUFFIX_HEADER} ${CPFLAGS}
# Dynamic dependencies:
Dir <Obey$Dir>
amu all_libs THROWBACK=-throwback
Dir <Obey$Dir>
amu clean
stripdepnd
Dir <Obey$Dir>
amu export_hdrs
amu export_libs THROWBACK=-throwback
COMPONENT = FakeLibInt
OBJS = key main
CMHGDEPENDS = key main
CUSTOMRES = no
CFLAGS = ${C_NOWARN_NON_ANSI_INCLUDES}
CDFLAGS = -DDEBUGLIB -DDEBUGLIB_NOBRACKETS
# At time of writing, platform-neutral symbols for SDIOLib have yet to be defined in BuildSys
ifeq (,${MAKE_VERSION})
CINCLUDES = -IC:SDIOLib
LIBS = C:SDIOLib.o.SDIOLib ${SYNCLIB}
else
CINCLUDES = -I${LIBDIR}/SDIOLib
LIBS = ${LIBDIR}/SDIOLib/SDIOLib.a ${SYNCLIB}
endif
include CModule
# Dynamic dependencies:
Dir <Obey$Dir>
amu standalone THROWBACK=-throwback
Dir <Obey$Dir>
amu clean
stripdepnd
/* Copyright (c) 2021 RISC OS Developments Ltd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "swis.h"
#include "Global/Keyboard.h"
#include "Global/RISCOS.h"
#include "Interface/SDIO.h"
#include "FakeLibIntHdr.h"
#include "main.h"
#include "key.h"
static bool on_vector;
static uint8_t bus, slot;
/** Initialise the KeyV routine that fakes SDIO card interrupts */
void key_init(void)
{
/* Since faking an interrupt isn't a feature exposed by SDIOLib, we're
* going to need to go behind its back and call SDIODriver SWIs instead.
* To do that, we need the bus and slot numbers. These aren't exposed by
* SDIOLib either, but we can assume that the first IO card found by an
* SDIOLib enumeration will correspond to the first IO card found by an
* SDIODriver enumeration. */
for (uint32_t slot_key = 0;;)
{
uint32_t slot_details;
if (_swix(SDIO_Enumerate, _INR(0,1)|_OUTR(1,2),
SDIOEnumerate_Slots, slot_key,
&slot_key, &slot_details) != NULL ||
slot_key == 0)
break;
for (uint32_t unit_key = 0;;)
{
uint32_t unit_details;
if (_swix(SDIO_Enumerate, _INR(0,2)|_OUT(1)|_OUT(3),
SDIOEnumerate_Units, unit_key, slot_details,
&unit_key, &unit_details) != NULL ||
unit_key == 0)
break;
if ((unit_details & SDIOEnumerate_UnitMask) == 0)
continue; /* ignore any memory units */
bus = (slot_details & SDIOEnumerate_BusMask) >> SDIOEnumerate_BusShift;
slot = (slot_details & SDIOEnumerate_SlotShift) >> SDIOEnumerate_SlotShift;
_swix(OS_Claim, _INR(0,2), KEYV, keyv_veneer, module_pw);
on_vector = true;
return;
}
}
}
/** Shut down the KeyV routine that fakes SDIO card interrupts */
void key_final(void)
{
if (on_vector)
_swix(OS_Release, _INR(0,2), KEYV, keyv_veneer, module_pw);
}
/** Called on KeyV, fakes an IO card interrupt when right-Shift pressed */
int keyv_handler(_kernel_swi_regs *r, void *pw)
{
(void) pw;
if (r->r[0] == KeyV_KeyDown &&
r->r[1] == KeyNo_ShiftRight)
{
_swix(SDIO_Control, _INR(0,2),
SDIOControl_FakeSDIOCardInt,
(bus << SDIOControl_BusShift) | (slot << SDIOControl_SlotShift),
1);
}
return 1; // always pass on
}
/* Copyright (c) 2021 RISC OS Developments Ltd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <sys/dev/sdmmc/sdmmcvar.h>
#include "swis.h"
#include "FakeLibIntHdr.h"
#include "main.h"
#include "key.h"
/** Module private word */
void *module_pw;
/** SDIOLib handle of the function under test */
static struct sdmmc_function *sf;
/** Which CCCR register was most recently read from the interrupt handler */
static uint8_t reg;
/** The contents of the CCCR register most recently read from the interrupt handler */
static uint8_t value;
/** Our SDIO interrupt handler */
static int interrupt_handler(void *void_sf)
{
struct sdmmc_function *sf = void_sf;
++reg;
sdmmc_enter_lock(sf);
value = sdmmc_io_read_1(sf->sc->sc_fn0, reg);
sdmmc_exit_lock(sf);
/* Trigger a callback to print the result of the read - since OS_Write* isn't re-entrant */
_swix(OS_AddCallBack, _INR(0,1), callback_veneer, module_pw);
return 0; /* result is ignored */
}
/** Transient callback triggered from interrupt handler. Used to perform any
* actions that are invalid from background context, such as calling
* non-reentrant SWIs. */
_kernel_oserror *callback_handler(_kernel_swi_regs *r, void *pw)
{
(void) r;
(void) pw;
printf("[%u]=%02X ", reg, value);
return NULL;
}
/** Module initialisation */
_kernel_oserror *initialise(const char *cmd_tail, int podule_base, void *pw)
{
(void) cmd_tail;
(void) podule_base;
module_pw = pw;
/* Initialise SDIOLib */
sdmmc_lib_init();
/* Latch onto the first IO card we find. In a real driver, you'd check the
* manufacturer and card IDs for a match. You'd also use a proper error if
* the card wasn't found! */
struct sdmmc_attach_args *saa = sdmmc_enumerate_functions(NULL);
if (saa == NULL)
{
sdmmc_lib_final();
return (_kernel_oserror *)"\0\0\0\0SDIO card not found";
}
/* Remember function handle */
sf = saa->sf;
/* Install interrupt handler */
if (sdmmc_intr_establish(sf, interrupt_handler, sf, "Test card interrupt handler") == NULL)
{
sdmmc_lib_final();
return (_kernel_oserror *)"\0\0\0\0Failed to install SDIO card interrupt handler";
}
/* Now get on KeyV */
key_init();
return NULL;
}
/** Module finalisation */
_kernel_oserror *finalise(int fatal, int podule, void *pw)
{
(void) fatal;
(void) podule;
(void) pw;
key_final();
sdmmc_lib_final();
return NULL;
}
/** USR mode entry point when you *RMRun the module */
int main(int argc, char *argv[])
{
(void) argc;
(void) argv;
printf("Test SDIO interrupt dispatch via SDIOLib\n"
"\n"
"Press right-shift to fake an interrupt, or:\n"
"[L]ock slot, [U]nlock slot, [R]ead CCCR register 0,\n"
"[K]eep bus busy with foreground operations for 10 seconds\n"
"A register will be read and printed each time an interrupt handler fires\n"
"Caution: don't presss L twice in a row - that will cause deadlock\n");
while (true)
{
int c, value;
_swi(OS_ReadC, _OUT(0), &c);
switch (c &~ 32)
{
case 'L':
printf("L ");
sdmmc_enter_lock(sf);
break;
case 'U':
printf("U ");
sdmmc_exit_lock(sf);
break;
case 'R':
printf("R");
value = sdmmc_io_read_1(sf->sc->sc_fn0, 0);
printf("[0]=%02X ", value);
break;
case 'K':
printf("K");
sdmmc_exit_lock(sf); /* in case it was left locked - else extra unlock is harmless */
int timeout;
_swi(OS_ReadMonotonicTime, _OUT(0), &timeout);
for (int seconds = 10; seconds > 0; --seconds)
{
timeout += 100;
int time;
do
{
sdmmc_enter_lock(sf);
(void) sdmmc_io_read_1(sf->sc->sc_fn0, 0);
sdmmc_exit_lock(sf);
_swix(OS_ReadMonotonicTime, _OUT(0), &time);
} while ((timeout - time) > 0);
printf(".");
}
printf(" ");
break;
}
}
}
title-string: FakeCardInt
help-string: FakeCardInt 0.01
initialisation-code: initialise
module-is-runnable:
finalisation-code: finalise
generic-veneers: callback_veneer/callback_handler
vector-handlers: keyv_veneer/keyv_handler
/* Copyright (c) 2021 RISC OS Developments Ltd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef KEY_H
#define KEY_H
void key_init(void);
void key_final(void);
#endif /* sentry KEY_H */
/* Copyright (c) 2021 RISC OS Developments Ltd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef MAIN_H
#define MAIN_H
extern void *module_pw;
#endif /* sentry MAIN_H */
/* (0.01)
*
* This file is automatically maintained by srccommit, do not edit manually.
*
*/
#define Module_MajorVersion_CMHG 0.01
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 06 Dec 2021
#define Module_MajorVersion "0.01"
#define Module_Version 1
#define Module_MinorVersion ""
#define Module_Date "06 Dec 2021"
#define Module_ApplicationDate "06-Dec-21"
#define Module_ComponentName "SDIOLib"
#define Module_FullVersion "0.01"
#define Module_HelpVersion "0.01 (06 Dec 2021)"
#define Module_LibraryVersionInfo "0:1"
This diff is collapsed.
/* Copyright (c) 2021 RISC OS Developments Ltd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* SDIO interface
*
* Implements functions compatible with those declared in
* Linux's include/linux/mmc/sdio_func.h
*/
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <include/linux/mmc/card.h>
#include <include/linux/mmc/sdio_func.h>
#include "swis.h"
#include "Global/NewErrors.h"
#include "Interface/SDIO.h"
#include "common.h"
#define MIN(a,b) ((a)<(b)?(a):(b))
#define DEFAULT_ENABLE_TIMEOUT 1000
/* Error numbers copied from Linux's errno-base.h and errno.h */
#define EIO 5 /* I/O error */
#define EINVAL 22 /* Invalid argument */
#define ERANGE 34 /* Math result not representable */
#define ETIME 62 /* Timer expired */
#define EILSEQ 84 /* Illegal byte sequence */
#define ETIMEDOUT 110 /* Connection timed out */
/** Attempt to map RISC OS errors to the Linux equivalents. */
static int translate_error(_kernel_oserror *e)
{
if (!e)
return 0;
switch (e->errnum)
{
case ErrorNumber_SDIO_QueueTO:
case ErrorNumber_SDIO_OpTO:
case ErrorNumber_SDIO_CMDTO:
case ErrorNumber_SDIO_DATTO:
return -EIO;
case ErrorNumber_SDIO_CTO:
return -ETIMEDOUT;
case ErrorNumber_SDIO_CCRC:
case ErrorNumber_SDIO_CEB:
case ErrorNumber_SDIO_CIE:
return -EILSEQ;
case ErrorNumber_SDIO_DTO:
return -ETIMEDOUT;
case ErrorNumber_SDIO_DCRC:
case ErrorNumber_SDIO_DEB:
return -EILSEQ;
case ErrorNumber_SDIO_IODevE00: /* Device error - Out of range */
return -ERANGE;
case ErrorNumber_SDIO_IODevE01: /* Device error - Invalid function */
return -EINVAL;
case ErrorNumber_SDIO_IODevE03: /* Device error - Generic error */
return -EIO;
default:
return -EINVAL;
}
}
/** Callback for recording card data in OS-specific data structure. */
static void init_card(void *void_card)
{
struct mmc_card *card = void_card;
/* Nothing to do (yet?) */
(void) card;
}
/** Callback for recording function data in OS-specific data structure. */
static void init_function(void *void_func, void *void_card, uint8_t number, uint16_t manf_id, uint16_t card_id, uint16_t maxblklen)
{
struct sdio_func *func = void_func;
struct mmc_card *card = void_card;
card->sdio_func[number] = func;
func->card = card;
func->num = number;
func->vendor = manf_id;
func->device = card_id;
func->enable_timeout = DEFAULT_ENABLE_TIMEOUT;
func->max_blksize = maxblklen;
}
void mmc_lib_init(void)
{
sdiolib_init(sizeof (struct mmc_card), init_card, sizeof (struct sdio_func), init_function);
}
void mmc_lib_final(void)
{
sdiolib_final();
}
struct mmc_card *mmc_enumerate_cards(struct mmc_card *previous)
{
struct sdio_func *func;
if (previous == NULL)
func = sdiolib_enumerate_functions(NULL);
else
{
/* Stepping one function along from this card's last function should go to
* the first function of the next card */
for (int num = 6;; --num)
if ((func = previous->sdio_func[num]) != NULL)
break;
func = sdiolib_enumerate_functions(func);
}
return func ? func->card : NULL;
}
struct sdio_func *sdio_enumerate_functions(struct sdio_func *previous)
{
return sdiolib_enumerate_functions(previous);
}
/** Acquire exclusive use of a slot (sleeping thread if possible). */
void sdio_claim_host(struct sdio_func *func)
{
sdiolib_lock(func);
}
/** Release exclusive use of a slot. */
void sdio_release_host(struct sdio_func *func)
{
sdiolib_unlock(func);
}
/** Enable function in CCCR and poll repeatedly (up to the timeout set in
* func->enable_timeout) for it to be reported ready in the CCCR. */
int sdio_enable_func(struct sdio_func *func)
{
uint8_t enabled;
_kernel_oserror *e = sdiolib_io_rw_direct_read(func, true, CCCR_IO_ENABLE, &enabled);
if (!e)
{
enabled |= 1u << func->num;
e = sdiolib_io_rw_direct_write(func, true, CCCR_IO_ENABLE, enabled);
}
int32_t timeout, time;
_swix(OS_ReadMonotonicTime, _OUT(0), &time);
timeout = time + 1 + (func->enable_timeout + 9) / 10;
while (!e && time - timeout < 0)
{
uint8_t ready;
e = sdiolib_io_rw_direct_read(func, true, CCCR_IO_READY, &ready);
if (!e && (ready & (1u << func->num)))