1
0
Fork 0
forked from Miroirs/x49gp
x50ng/src/s3c2410_sdi.c
2024-10-22 19:36:52 +02:00

810 lines
25 KiB
C

/* $Id: s3c2410_sdi.c,v 1.4 2008/12/11 12:18:17 ecd Exp $
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <errno.h>
#include "x49gp.h"
#include "s3c2410.h"
#include "block.h"
// #define DEBUG_S3C2410_SDI 1
typedef struct {
uint32_t sdicon;
uint32_t sdipre;
uint32_t sdicarg;
uint32_t sdiccon;
uint32_t sdicsta;
uint32_t sdirsp0;
uint32_t sdirsp1;
uint32_t sdirsp2;
uint32_t sdirsp3;
uint32_t sdidtimer;
uint32_t sdibsize;
uint32_t sdidcon;
uint32_t sdidcnt;
uint32_t sdidsta;
uint32_t sdifsta;
uint32_t sdidat;
uint32_t sdiimsk;
unsigned int nr_regs;
s3c2410_offset_t* regs;
x49gp_t* x49gp;
char* filename;
BlockDriverState* bs;
int fd;
unsigned char* read_data;
uint32_t nr_read_data;
uint32_t read_offset;
unsigned int read_index;
unsigned char* write_data;
uint32_t nr_write_data;
uint32_t write_offset;
unsigned int write_index;
int multiple_block;
int acmd;
int card_state;
} s3c2410_sdi_t;
static int s3c2410_sdi_data_init( s3c2410_sdi_t* sdi )
{
s3c2410_offset_t regs[] = {
S3C2410_OFFSET( SDI, SDICON, 0x00000000, sdi->sdicon ), S3C2410_OFFSET( SDI, SDIPRE, 0x00000000, sdi->sdipre ),
S3C2410_OFFSET( SDI, SDICARG, 0x00000000, sdi->sdicarg ), S3C2410_OFFSET( SDI, SDICCON, 0x00000000, sdi->sdiccon ),
S3C2410_OFFSET( SDI, SDICSTA, 0x00000000, sdi->sdicsta ), S3C2410_OFFSET( SDI, SDIRSP0, 0x00000000, sdi->sdirsp0 ),
S3C2410_OFFSET( SDI, SDIRSP1, 0x00000000, sdi->sdirsp1 ), S3C2410_OFFSET( SDI, SDIRSP2, 0x00000000, sdi->sdirsp2 ),
S3C2410_OFFSET( SDI, SDIRSP3, 0x00000000, sdi->sdirsp3 ), S3C2410_OFFSET( SDI, SDIDTIMER, 0x00002000, sdi->sdidtimer ),
S3C2410_OFFSET( SDI, SDIBSIZE, 0x00000000, sdi->sdibsize ), S3C2410_OFFSET( SDI, SDIDCON, 0x00000000, sdi->sdidcon ),
S3C2410_OFFSET( SDI, SDIDCNT, 0x00000000, sdi->sdidcnt ), S3C2410_OFFSET( SDI, SDIDSTA, 0x00000000, sdi->sdidsta ),
S3C2410_OFFSET( SDI, SDIFSTA, 0x00000000, sdi->sdifsta ), S3C2410_OFFSET( SDI, SDIDAT, 0x00000000, sdi->sdidat ),
S3C2410_OFFSET( SDI, SDIIMSK, 0x00000000, sdi->sdiimsk ) };
memset( sdi, 0, sizeof( s3c2410_sdi_t ) );
sdi->regs = malloc( sizeof( regs ) );
if ( NULL == sdi->regs ) {
fprintf( stderr, "%s:%u: Out of memory\n", __FUNCTION__, __LINE__ );
return -ENOMEM;
}
memcpy( sdi->regs, regs, sizeof( regs ) );
sdi->nr_regs = sizeof( regs ) / sizeof( regs[ 0 ] );
return 0;
}
static int sdcard_read( s3c2410_sdi_t* sdi )
{
uint32_t offset;
uint32_t size;
int error;
offset = sdi->read_offset;
size = sdi->nr_read_data;
#ifdef DEBUG_S3C2410_SDI
printf( "SDI: card read %4u at %08x\n", size, offset );
#endif
sdi->nr_read_data = 0;
sdi->read_index = 0;
if ( ( sdi->fd < 0 ) && ( sdi->bs == NULL ) ) {
return -ENODEV;
}
sdi->read_data = malloc( size );
if ( NULL == sdi->read_data ) {
return -ENOMEM;
}
if ( sdi->bs ) {
sdi->nr_read_data = bdrv_pread( sdi->bs, offset, sdi->read_data, size );
} else {
if ( sdi->read_offset != lseek( sdi->fd, offset, SEEK_SET ) ) {
error = errno;
sdi->nr_read_data = 0;
free( sdi->read_data );
sdi->read_data = NULL;
return -error;
}
sdi->nr_read_data = read( sdi->fd, sdi->read_data, size );
}
if ( sdi->nr_read_data != size ) {
error = errno;
sdi->nr_read_data = 0;
free( sdi->read_data );
sdi->read_data = NULL;
return -error;
}
return 0;
}
static int sdcard_write_prepare( s3c2410_sdi_t* sdi )
{
sdi->write_index = 0;
if ( ( sdi->fd < 0 ) && ( sdi->bs == NULL ) ) {
sdi->nr_write_data = 0;
return -ENODEV;
}
sdi->write_data = malloc( sdi->nr_write_data );
if ( NULL == sdi->write_data ) {
sdi->nr_write_data = 0;
return -ENOMEM;
}
return 0;
}
static int sdcard_write( s3c2410_sdi_t* sdi )
{
uint32_t offset;
uint32_t size;
int error;
offset = sdi->write_offset;
size = sdi->nr_write_data;
#ifdef DEBUG_S3C2410_SDI
printf( "SDI: card write %4u at %08x\n", size, offset );
#endif
sdi->write_index = 0;
if ( sdi->bs ) {
error = bdrv_pwrite( sdi->bs, offset, sdi->write_data, size );
} else {
if ( sdi->fd < 0 ) {
free( sdi->write_data );
sdi->write_data = NULL;
return -ENODEV;
}
if ( sdi->write_offset != lseek( sdi->fd, offset, SEEK_SET ) ) {
error = errno;
free( sdi->write_data );
sdi->write_data = NULL;
return -error;
}
error = write( sdi->fd, sdi->write_data, size );
}
if ( error != size ) {
error = errno;
free( sdi->write_data );
sdi->write_data = NULL;
return -error;
}
free( sdi->write_data );
sdi->write_data = NULL;
return 0;
}
static uint32_t s3c2410_sdi_read( void* opaque, target_phys_addr_t offset )
{
s3c2410_sdi_t* sdi = opaque;
s3c2410_offset_t* reg;
unsigned int read_avail, write_avail;
if ( !S3C2410_OFFSET_OK( sdi, offset ) ) {
return ~( 0 );
}
reg = S3C2410_OFFSET_ENTRY( sdi, offset );
switch ( offset ) {
case S3C2410_SDI_SDIDAT:
if ( ( sdi->sdidcon & 0x3000 ) == 0x2000 ) {
read_avail = sdi->nr_read_data - sdi->read_index;
if ( read_avail > 0 ) {
*( reg->datap ) = sdi->read_data[ sdi->read_index++ ] << ( ( sdi->sdicon & 0x10 ) ? 24 : 0 );
if ( ( sdi->nr_read_data - sdi->read_index ) > 0 ) {
*( reg->datap ) |= sdi->read_data[ sdi->read_index++ ] << ( ( sdi->sdicon & 0x10 ) ? 16 : 8 );
}
if ( ( sdi->nr_read_data - sdi->read_index ) > 0 ) {
*( reg->datap ) |= sdi->read_data[ sdi->read_index++ ] << ( ( sdi->sdicon & 0x10 ) ? 8 : 16 );
}
if ( ( sdi->nr_read_data - sdi->read_index ) > 0 ) {
*( reg->datap ) |= sdi->read_data[ sdi->read_index++ ] << ( ( sdi->sdicon & 0x10 ) ? 0 : 24 );
}
if ( sdi->read_index >= sdi->nr_read_data ) {
sdi->read_index = 0;
free( sdi->read_data );
sdi->read_data = NULL;
if ( sdi->multiple_block )
--sdi->multiple_block;
if ( sdi->multiple_block ) {
sdi->read_offset += sdi->nr_read_data;
sdcard_read( sdi );
sdi->sdidsta |= ( 1 << 9 ) | ( 1 << 4 );
} else {
sdi->nr_read_data = 0;
sdi->sdidcon &= ~0x3000;
}
}
read_avail = sdi->nr_read_data - sdi->read_index;
sdi->sdidcnt = read_avail;
} else
*( reg->datap ) = 0;
}
break;
case S3C2410_SDI_SDIFSTA:
*( reg->datap ) = ( 1 << 13 ) | ( 1 << 10 );
read_avail = sdi->nr_read_data - sdi->read_index;
if ( read_avail > 63 )
*( reg->datap ) |= ( 1 << 12 ) | ( 1 << 8 ) | ( 1 << 7 ) | 0x40;
else if ( read_avail > 31 )
*( reg->datap ) |= ( 1 << 12 ) | ( 1 << 9 ) | ( 1 << 7 ) | read_avail;
else
*( reg->datap ) |= ( 1 << 12 ) | ( 1 << 9 ) | read_avail;
break;
case S3C2410_SDI_SDIDSTA:
*( reg->datap ) &= ~( 0x03 );
if ( ( sdi->sdidcon & 0x3000 ) == 0x1000 ) {
*( reg->datap ) |= ( 1 << 3 );
sdi->sdidcon &= ~0x3000; // BACK TO READY STATE
}
read_avail = sdi->nr_read_data - sdi->read_index;
if ( ( ( sdi->sdidcon & 0x3000 ) == 0x2000 ) && read_avail ) {
*( reg->datap ) |= ( 1 << 0 );
}
write_avail = sdi->nr_write_data - sdi->write_index;
if ( ( ( sdi->sdidcon & 0x3000 ) == 0x3000 ) && write_avail ) {
*( reg->datap ) |= ( 1 << 1 );
}
}
#ifdef DEBUG_S3C2410_SDI
printf( "read %s [%08x] %s [%08lx] data %08x\n", "s3c2410-sdi", S3C2410_SDI_BASE, reg->name, ( unsigned long )offset,
*( reg->datap ) );
#endif
return *( reg->datap );
}
static void s3c2410_sdi_write( void* opaque, target_phys_addr_t offset, uint32_t data )
{
s3c2410_sdi_t* sdi = opaque;
s3c2410_offset_t* reg;
unsigned int read_avail, write_avail;
if ( !S3C2410_OFFSET_OK( sdi, offset ) ) {
return;
}
reg = S3C2410_OFFSET_ENTRY( sdi, offset );
#ifdef DEBUG_S3C2410_SDI
printf( "write %s [%08x] %s [%08lx] data %08x\n", "s3c2410-sdi", S3C2410_SDI_BASE, reg->name, ( unsigned long )offset, data );
#endif
switch ( offset ) {
case S3C2410_SDI_SDICON:
*( reg->datap ) = data & ~( 2 );
break;
case S3C2410_SDI_SDICCON:
*( reg->datap ) = data;
#ifdef DEBUG_S3C2410_SDI
printf( "SDI: cmd %02u, start %u, %s response %u, data %u, abort %u\n", data & 0x3f, ( data >> 8 ) & 1,
( data >> 10 ) & 1 ? "long" : "short", ( data >> 9 ) & 1, ( data >> 11 ) & 1, ( data >> 12 ) & 1 );
#endif
if ( data & ( 1 << 8 ) ) {
sdi->sdicsta |= ( 1 << 11 );
} else {
sdi->sdicsta = 0;
sdi->sdirsp0 = 0;
sdi->sdirsp1 = 0;
sdi->sdirsp2 = 0;
sdi->sdirsp3 = 0;
data = 0;
}
sdi->sdicsta &= ~( 1 << 12 );
sdi->sdicsta &= ~( 0xff );
if ( data & ( 1 << 9 ) ) {
sdi->sdicsta |= ( 1 << 9 );
switch ( ( data & 0x3f ) + ( sdi->acmd << 8 ) ) {
case 256:
case 0:
sdi->acmd = 0;
sdi->card_state = 0;
break;
case 1:
sdi->sdicsta |= 0x3f;
sdi->sdirsp0 = 0x80ff8000;
sdi->sdirsp1 = 0xff000000;
break;
case 2:
sdi->card_state = 2;
sdi->sdicsta |= 0x3f;
sdi->sdirsp0 = 0x02000053;
sdi->sdirsp1 = 0x444d3036;
sdi->sdirsp2 = 0x34011234;
sdi->sdirsp3 = 0x567813ff;
break;
case 3:
sdi->card_state = 3;
sdi->sdicsta |= 3;
sdi->sdirsp0 = sdi->card_state << 9;
if ( sdi->card_state == 5 )
sdi->sdirsp0 |= 0x100;
if ( sdi->acmd )
sdi->sdirsp0 |= 0x20;
sdi->sdirsp0 |= 0x12340000; // PUBLISHED RCA NUMBER
sdi->sdirsp1 = 0xff000000;
break;
case 7:
sdi->sdicsta |= 7;
sdi->sdirsp0 = 0x00000900;
sdi->sdirsp1 = 0xff000000;
break;
case 8:
sdi->sdicsta |= 0x400; // SEND TIMEOUT IMMEDIATELY
break;
case 9:
{
/* c_size_mult + 2
* blocks = (c_size + 1) * 2
*
* size = bl_len * blocks;
*/
uint32_t write_bl_len = 9;
uint32_t read_bl_len = 9;
uint32_t c_size_mult = 7;
uint32_t c_size = 4096 - 1;
sdi->sdicsta |= 9;
/* 127 .. 96 */
sdi->sdirsp0 = 0x000f005a;
/* 95 .. 64 */
sdi->sdirsp1 = 0x0f508000 | ( ( c_size & 0xffc ) >> 2 ) | ( ( read_bl_len & 0xf ) << 16 );
/* 63 .. 32 */
sdi->sdirsp2 = 0x2dd47c1f | ( ( c_size & 0x003 ) << 30 ) | ( ( c_size_mult & 7 ) << 15 );
/* 31 .. 0 */
sdi->sdirsp3 = 0x8a0040ff | ( ( write_bl_len & 0xf ) << 22 );
break;
}
case 10:
sdi->sdicsta |= 10;
sdi->sdirsp0 = 0x02000053;
sdi->sdirsp1 = 0x444d3036;
sdi->sdirsp2 = 0x34011234;
sdi->sdirsp3 = 0x567813ff;
break;
case 12:
sdi->multiple_block = 0;
sdi->nr_read_data = sdi->nr_write_data = 0;
sdi->write_index = sdi->read_index = 0;
if ( sdi->read_data ) {
free( sdi->read_data );
sdi->read_data = NULL;
}
sdi->sdidcon &= 0x3000;
sdi->sdicsta |= 12;
sdi->sdirsp0 = 0x00000900;
sdi->sdirsp1 = 0xff000000;
break;
case 16:
sdi->sdicsta |= 16;
sdi->sdicsta |= data & 0x3f;
sdi->sdirsp0 = sdi->card_state << 9;
if ( sdi->card_state == 5 )
sdi->sdirsp0 |= 0x100;
if ( sdi->acmd )
sdi->sdirsp0 |= 0x20;
sdi->sdirsp1 = 0xff000000;
break;
case 18:
sdi->multiple_block = sdi->sdicarg;
/* fall through */
case 17:
sdi->read_offset = sdi->sdicarg;
sdi->nr_read_data = sdi->sdibsize & 0xfff;
sdcard_read( sdi );
read_avail = sdi->nr_read_data - sdi->read_index;
sdi->sdicsta |= data & 0x3f;
sdi->sdirsp0 = 0x00000b00;
sdi->sdirsp1 = 0xff000000;
sdi->sdidcnt = ( 1 << 12 ) | read_avail;
sdi->sdidsta |= ( 1 << 9 ) | ( 1 << 4 );
break;
case 23:
case 25:
sdi->multiple_block = sdi->sdicarg;
/* fall through */
case 24:
sdi->write_offset = sdi->sdicarg;
sdi->nr_write_data = sdi->sdibsize & 0xfff;
sdcard_write_prepare( sdi );
write_avail = sdi->nr_write_data - sdi->write_index;
sdi->sdicsta |= data & 0x3f;
sdi->sdirsp0 = 0x00000d00;
sdi->sdirsp1 = 0xff000000;
sdi->sdidcnt = ( 1 << 12 ) | write_avail;
break;
case 256 + 55:
case 55:
sdi->acmd = 1;
sdi->sdicsta |= data & 0x3f;
sdi->sdirsp0 = sdi->card_state << 9;
if ( sdi->card_state == 5 )
sdi->sdirsp0 |= 0x100;
if ( sdi->acmd )
sdi->sdirsp0 |= 0x20;
sdi->sdirsp1 = 0xff000000;
break;
case 256 + 41:
// ACMD41
sdi->card_state = 1; // READY
sdi->sdicsta |= data & 0x3f;
sdi->sdirsp0 = 0x80ff8000;
sdi->sdirsp1 = 0xff000000;
sdi->acmd = 0;
break;
case 256 + 42:
// ACMD42
sdi->sdicsta |= data & 0x3f;
sdi->sdirsp0 = sdi->card_state << 9;
if ( sdi->card_state == 5 )
sdi->sdirsp0 |= 0x100;
if ( sdi->acmd )
sdi->sdirsp0 |= 0x20;
sdi->sdirsp1 = 0xff000000;
break;
case 256 + 51:
// ACMD51
sdi->sdicsta |= 51;
sdi->sdirsp0 = 0x0;
sdi->sdirsp1 = 0x01050000;
sdi->sdirsp2 = 0x0;
sdi->sdirsp3 = 0x0;
sdi->acmd = 0;
break;
default:
printf( "unhandled SDcard CMD %u\n", ( data & 0x3f ) );
sdi->sdicsta |= ( 1 << 10 );
sdi->sdicsta &= ~( 1 << 9 );
sdi->acmd = 0;
// abort();
break;
}
}
break;
case S3C2410_SDI_SDIDAT:
*( reg->datap ) = data;
if ( ( sdi->sdidcon & 0x3000 ) == 0x3000 ) {
write_avail = sdi->nr_write_data - sdi->write_index;
if ( write_avail > 0 ) {
sdi->write_data[ sdi->write_index++ ] = ( *( reg->datap ) >> ( ( sdi->sdicon & 0x10 ) ? 24 : 0 ) ) & 0xff;
if ( ( sdi->nr_write_data - sdi->write_index ) > 0 ) {
sdi->write_data[ sdi->write_index++ ] = ( *( reg->datap ) >> ( ( sdi->sdicon & 0x10 ) ? 16 : 8 ) ) & 0xff;
}
if ( ( sdi->nr_write_data - sdi->write_index ) > 0 ) {
sdi->write_data[ sdi->write_index++ ] = ( *( reg->datap ) >> ( ( sdi->sdicon & 0x10 ) ? 8 : 16 ) ) & 0xff;
}
if ( ( sdi->nr_write_data - sdi->write_index ) > 0 ) {
sdi->write_data[ sdi->write_index++ ] = ( *( reg->datap ) >> ( ( sdi->sdicon & 0x10 ) ? 0 : 24 ) ) & 0xff;
}
if ( sdi->write_index >= sdi->nr_write_data ) {
sdcard_write( sdi );
if ( sdi->multiple_block )
sdi->multiple_block--;
if ( sdi->multiple_block ) {
sdi->write_offset += sdi->nr_write_data;
sdcard_write_prepare( sdi );
} else {
sdi->nr_write_data = 0;
sdi->sdidcon &= ~0x3000;
}
sdi->sdidsta |= ( 1 << 9 ) | ( 1 << 4 ) | ( 1 << 3 );
}
write_avail = sdi->nr_write_data - sdi->write_index;
sdi->sdidcnt = write_avail;
}
}
break;
case S3C2410_SDI_SDICSTA:
*( reg->datap ) &= ~( data & 0xf00 );
break;
case S3C2410_SDI_SDIDSTA:
*( reg->datap ) &= ~( data & 0x7fc );
break;
case S3C2410_SDI_SDIFSTA:
case S3C2410_SDI_SDIDCNT:
/* ignore */
break;
default:
*( reg->datap ) = data;
break;
}
}
void s3c2410_sdi_unmount( x49gp_t* x49gp )
{
s3c2410_sdi_t* sdi = x49gp->s3c2410_sdi;
if ( sdi->bs ) {
bdrv_delete( sdi->bs );
sdi->bs = NULL;
}
if ( sdi->fd >= 0 ) {
close( sdi->fd );
sdi->fd = -1;
}
g_free( sdi->filename );
sdi->filename = g_strdup( "" );
s3c2410_io_port_f_set_bit( x49gp, 3, 0 );
}
int s3c2410_sdi_mount( x49gp_t* x49gp, char* filename )
{
s3c2410_sdi_t* sdi = x49gp->s3c2410_sdi;
struct stat st;
char vvfat_name[ 1024 ];
int error = 0;
s3c2410_sdi_unmount( x49gp );
g_free( sdi->filename );
sdi->filename = filename;
if ( strcmp( filename, "" ) && ( stat( filename, &st ) == 0 ) ) {
if ( S_ISDIR( st.st_mode ) ) {
sprintf( vvfat_name, "fat:rw:16:%s", filename );
sdi->bs = bdrv_new( "" );
if ( sdi->bs ) {
error = bdrv_open( sdi->bs, vvfat_name, 0 );
if ( error != 0 ) {
fprintf( stderr, "%s:%u: bdrv_open %s: %d\n", __FUNCTION__, __LINE__, vvfat_name, error );
bdrv_delete( sdi->bs );
sdi->bs = NULL;
}
}
} else {
sdi->fd = open( filename, O_RDWR );
if ( sdi->fd < 0 ) {
fprintf( stderr, "%s:%u: open %s: %s\n", __FUNCTION__, __LINE__, filename, strerror( errno ) );
}
}
}
if ( ( sdi->bs != NULL ) || ( sdi->fd >= 0 ) ) {
s3c2410_io_port_f_set_bit( x49gp, 3, 1 );
} else {
s3c2410_io_port_f_set_bit( x49gp, 3, 0 );
}
return error;
}
int s3c2410_sdi_is_mounted( x49gp_t* x49gp )
{
s3c2410_sdi_t* sdi = x49gp->s3c2410_sdi;
return ( sdi->bs != NULL ) || ( sdi->fd >= 0 );
}
static int s3c2410_sdi_load( x49gp_module_t* module, GKeyFile* key )
{
x49gp_t* x49gp = module->x49gp;
s3c2410_sdi_t* sdi = module->user_data;
s3c2410_offset_t* reg;
char *filename, *filepath;
int error, error2;
int i;
#ifdef DEBUG_X49GP_MODULES
printf( "%s: %s:%u\n", module->name, __FUNCTION__, __LINE__ );
#endif
sdi->fd = -1;
sdi->bs = NULL;
sdi->filename = NULL;
error = x49gp_module_get_filename( module, key, "filename", "", &filename, &filepath );
if ( strcmp( filename, "" ) ) {
error2 = s3c2410_sdi_mount( x49gp, filepath );
if ( 0 == error )
error = error2;
} else {
s3c2410_sdi_unmount( x49gp );
}
g_free( sdi->filename );
sdi->filename = filename;
for ( i = 0; i < sdi->nr_regs; i++ ) {
reg = &sdi->regs[ i ];
if ( NULL == reg->name )
continue;
if ( x49gp_module_get_u32( module, key, reg->name, reg->reset, reg->datap ) )
error = -EAGAIN;
}
return error;
}
static int s3c2410_sdi_save( x49gp_module_t* module, GKeyFile* key )
{
s3c2410_sdi_t* sdi = module->user_data;
s3c2410_offset_t* reg;
int i;
#ifdef DEBUG_X49GP_MODULES
printf( "%s: %s:%u\n", module->name, __FUNCTION__, __LINE__ );
#endif
x49gp_module_set_filename( module, key, "filename", sdi->filename );
for ( i = 0; i < sdi->nr_regs; i++ ) {
reg = &sdi->regs[ i ];
if ( NULL == reg->name )
continue;
x49gp_module_set_u32( module, key, reg->name, *( reg->datap ) );
}
return 0;
}
static int s3c2410_sdi_reset( x49gp_module_t* module, x49gp_reset_t reset )
{
s3c2410_sdi_t* sdi = module->user_data;
s3c2410_offset_t* reg;
int i;
#ifdef DEBUG_X49GP_MODULES
printf( "%s: %s:%u\n", module->name, __FUNCTION__, __LINE__ );
#endif
for ( i = 0; i < sdi->nr_regs; i++ ) {
reg = &sdi->regs[ i ];
if ( NULL == reg->name )
continue;
*( reg->datap ) = reg->reset;
}
return 0;
}
static CPUReadMemoryFunc* s3c2410_sdi_readfn[] = { s3c2410_sdi_read, s3c2410_sdi_read, s3c2410_sdi_read };
static CPUWriteMemoryFunc* s3c2410_sdi_writefn[] = { s3c2410_sdi_write, s3c2410_sdi_write, s3c2410_sdi_write };
static int s3c2410_sdi_init( x49gp_module_t* module )
{
s3c2410_sdi_t* sdi;
int iotype;
#ifdef DEBUG_X49GP_MODULES
printf( "%s: %s:%u\n", module->name, __FUNCTION__, __LINE__ );
#endif
sdi = malloc( sizeof( s3c2410_sdi_t ) );
if ( NULL == sdi ) {
fprintf( stderr, "%s: %s:%u: Out of memory\n", module->x49gp->progname, __FUNCTION__, __LINE__ );
return -ENOMEM;
}
if ( s3c2410_sdi_data_init( sdi ) ) {
free( sdi );
return -ENOMEM;
}
module->user_data = sdi;
module->x49gp->s3c2410_sdi = sdi;
sdi->x49gp = module->x49gp;
iotype = cpu_register_io_memory( s3c2410_sdi_readfn, s3c2410_sdi_writefn, sdi );
#ifdef DEBUG_S3C2410_SDI
printf( "%s: iotype %08x\n", __FUNCTION__, iotype );
#endif
cpu_register_physical_memory( S3C2410_SDI_BASE, S3C2410_MAP_SIZE, iotype );
bdrv_init();
return 0;
}
static int s3c2410_sdi_exit( x49gp_module_t* module )
{
s3c2410_sdi_t* sdi;
#ifdef DEBUG_X49GP_MODULES
printf( "%s: %s:%u\n", module->name, __FUNCTION__, __LINE__ );
#endif
if ( module->user_data ) {
sdi = module->user_data;
if ( sdi->regs )
free( sdi->regs );
free( sdi );
}
x49gp_module_unregister( module );
free( module );
return 0;
}
int x49gp_s3c2410_sdi_init( x49gp_t* x49gp )
{
x49gp_module_t* module;
if ( x49gp_module_init( x49gp, "s3c2410-sdi", s3c2410_sdi_init, s3c2410_sdi_exit, s3c2410_sdi_reset, s3c2410_sdi_load, s3c2410_sdi_save,
NULL, &module ) ) {
return -1;
}
return x49gp_module_register( module );
}