Search
lxdream.org :: lxdream/src/maple/maple.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/maple/maple.c
changeset 450:207461e79f21
prev447:3e095bfcb476
next480:d28c2992f5ee
author nkeynes
date Sun Oct 21 05:31:07 2007 +0000 (16 years ago)
permissions -rw-r--r--
last change Rename mmr_win.c to mmio_win.c
file annotate diff log raw
nkeynes@31
     1
/**
nkeynes@450
     2
 * $Id: maple.c,v 1.11 2007-10-17 11:26:45 nkeynes Exp $
nkeynes@31
     3
 *
nkeynes@31
     4
 * Implements the core Maple bus, including DMA transfers to and from the bus.
nkeynes@31
     5
 *
nkeynes@31
     6
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@31
     7
 *
nkeynes@31
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@31
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@31
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@31
    11
 * (at your option) any later version.
nkeynes@31
    12
 *
nkeynes@31
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@31
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@31
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@31
    16
 * GNU General Public License for more details.
nkeynes@31
    17
 */
nkeynes@35
    18
#define MODULE maple_module
nkeynes@31
    19
nkeynes@1
    20
#include <assert.h>
nkeynes@1
    21
#include "dream.h"
nkeynes@1
    22
#include "mem.h"
nkeynes@1
    23
#include "asic.h"
nkeynes@1
    24
#include "maple.h"
nkeynes@1
    25
nkeynes@15
    26
void maple_init( void );
nkeynes@15
    27
nkeynes@15
    28
struct dreamcast_module maple_module = { "Maple", maple_init, NULL, NULL, NULL,
nkeynes@23
    29
					 NULL, NULL, NULL };
nkeynes@15
    30
nkeynes@144
    31
struct maple_device_class *maple_device_classes[] = { &controller_class, NULL };
nkeynes@144
    32
nkeynes@15
    33
void maple_init( void )
nkeynes@15
    34
{
nkeynes@15
    35
nkeynes@15
    36
}
nkeynes@15
    37
nkeynes@144
    38
maple_device_t maple_new_device( const gchar *name )
nkeynes@144
    39
{
nkeynes@447
    40
    maple_device_class_t clz = maple_get_device_class(name);
nkeynes@447
    41
    if( clz != NULL ) {
nkeynes@447
    42
	return clz->new_device();
nkeynes@447
    43
    } 
nkeynes@447
    44
    return NULL;
nkeynes@447
    45
}
nkeynes@447
    46
nkeynes@447
    47
const maple_device_class_t maple_get_device_class( const gchar *name )
nkeynes@447
    48
{
nkeynes@144
    49
    int i;
nkeynes@144
    50
    for( i=0; maple_device_classes[i] != NULL; i++ ) {
nkeynes@144
    51
	if( g_strcasecmp(maple_device_classes[i]->name, name ) == 0 )
nkeynes@447
    52
	    return maple_device_classes[i];
nkeynes@144
    53
    }
nkeynes@144
    54
    return NULL;
nkeynes@144
    55
}
nkeynes@144
    56
nkeynes@447
    57
const struct maple_device_class **maple_get_device_classes()
nkeynes@447
    58
{
nkeynes@447
    59
    return maple_device_classes;
nkeynes@447
    60
}
nkeynes@447
    61
nkeynes@450
    62
lxdream_config_entry_t maple_get_device_config( maple_device_t dev )
nkeynes@144
    63
{
nkeynes@144
    64
    if( dev->get_config == NULL )
nkeynes@144
    65
	return NULL;
nkeynes@144
    66
    return dev->get_config(dev);
nkeynes@144
    67
}
nkeynes@144
    68
nkeynes@2
    69
/**
nkeynes@2
    70
 * Input data looks like this:
nkeynes@2
    71
 *    0: transfer control word
nkeynes@2
    72
 *      0: length of data in words (not including 3 word header)
nkeynes@2
    73
 *      1: low bit = lightgun mode
nkeynes@2
    74
 *      2: low 2 bits = port # (0..3)
nkeynes@2
    75
 *      3: 0x80 = last packet, 0x00 = normal packet
nkeynes@2
    76
 *    4: output buffer address
nkeynes@2
    77
 *    8: Command word
nkeynes@2
    78
 *      8: command code
nkeynes@2
    79
 *      9: destination address
nkeynes@2
    80
 *     10: source address
nkeynes@2
    81
 *     11: length of data in words (not including 3 word header)
nkeynes@2
    82
 *   12: command-specific data
nkeynes@2
    83
 */
nkeynes@2
    84
nkeynes@2
    85
/**
nkeynes@2
    86
 * array is [port][subperipheral], so [0][0] is main peripheral on port A,
nkeynes@2
    87
 * [1][2] is the second subperipheral on port B and so on.
nkeynes@2
    88
 */
nkeynes@2
    89
maple_device_t maple_devices[4][6];
nkeynes@2
    90
int maple_periph_mask[4];
nkeynes@2
    91
#define GETBYTE(n) ((uint32_t)(buf[n]))
nkeynes@2
    92
#define GETWORD(n) (*((uint32_t *)(buf+(n))))
nkeynes@2
    93
#define PUTBYTE(n,x) (buf[n] = (char)x)
nkeynes@2
    94
#define PUTWORD(n,x) (*((uint32_t *)(return_buf+(n))) = (x))
nkeynes@2
    95
nkeynes@144
    96
maple_device_t maple_get_device( unsigned int port, unsigned int periph ) {
nkeynes@144
    97
    if( port >= 4 )
nkeynes@144
    98
	return NULL;
nkeynes@144
    99
    if( periph >= 6 )
nkeynes@144
   100
	return NULL;
nkeynes@144
   101
    return maple_devices[port][periph];
nkeynes@144
   102
}
nkeynes@144
   103
nkeynes@1
   104
void maple_handle_buffer( uint32_t address ) {
nkeynes@2
   105
    unsigned char *buf = (unsigned char *)mem_get_region(address);
nkeynes@1
   106
    if( buf == NULL ) {
nkeynes@1
   107
        ERROR( "Invalid or unmapped buffer passed to maple (0x%08X)", address );
nkeynes@1
   108
    } else {
nkeynes@2
   109
        unsigned int last = 0;
nkeynes@2
   110
        int i = 0, count;
nkeynes@2
   111
        for( count=0; !last; count++ ) {
nkeynes@2
   112
            unsigned int port, length, gun, periph, periph_id, out_length;
nkeynes@2
   113
            unsigned int cmd, recv_addr, send_addr;
nkeynes@2
   114
            uint32_t return_addr;
nkeynes@2
   115
            unsigned char *return_buf;
nkeynes@1
   116
            
nkeynes@2
   117
            last = GETBYTE(3) & 0x80; /* indicates last packet */
nkeynes@2
   118
            port = GETBYTE(2) & 0x03;
nkeynes@2
   119
            gun = GETBYTE(1) & 0x01;
nkeynes@2
   120
            length = GETBYTE(0) & 0xFF;
nkeynes@2
   121
            return_addr = GETWORD(4);
nkeynes@447
   122
nkeynes@447
   123
            if( (return_addr & 0x1C000000) != 0x0C000000 ) {
nkeynes@447
   124
		ERROR( "Bad return address in maple packet: %08X", return_addr );
nkeynes@447
   125
		break;
nkeynes@2
   126
            }
nkeynes@2
   127
            return_buf = mem_get_region(return_addr);
nkeynes@2
   128
            cmd = GETBYTE(8);
nkeynes@2
   129
            recv_addr = GETBYTE(9);
nkeynes@2
   130
            send_addr = GETBYTE(10);
nkeynes@2
   131
            /* Sanity checks */
nkeynes@2
   132
            if( GETBYTE(11) != length ||
nkeynes@447
   133
                send_addr >> 6 != port ||
nkeynes@2
   134
                recv_addr >> 6 != port ||
nkeynes@2
   135
                return_buf == NULL ) {
nkeynes@447
   136
		ERROR( "Received bad packet: %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X",
nkeynes@447
   137
		       buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
nkeynes@447
   138
		       buf[8], buf[9], buf[10], buf[11] );
nkeynes@447
   139
		break;
nkeynes@2
   140
            }
nkeynes@2
   141
            periph = 0;
nkeynes@2
   142
            periph_id = recv_addr & 0x3F;
nkeynes@2
   143
            if( periph_id != 0x20 ) {
nkeynes@2
   144
                for( i=0;i<5;i++ ) {
nkeynes@2
   145
                    if( periph_id == (1<<i) ) {
nkeynes@2
   146
                        periph = i+1;
nkeynes@2
   147
                        break;
nkeynes@2
   148
                    }
nkeynes@2
   149
                }
nkeynes@2
   150
                if( periph == 0 ) { /* Bad setting */
nkeynes@2
   151
                    /* ERROR */
nkeynes@2
   152
                }
nkeynes@2
   153
            }
nkeynes@2
   154
nkeynes@2
   155
            maple_device_t dev = maple_devices[port][periph];
nkeynes@2
   156
            if( dev == NULL ) {
nkeynes@2
   157
                /* no device attached */
nkeynes@2
   158
                *((uint32_t *)return_buf) = -1;
nkeynes@2
   159
            } else {
nkeynes@2
   160
                int status, func, block;
nkeynes@2
   161
                out_length = 0;
nkeynes@2
   162
                switch( cmd ) {
nkeynes@2
   163
                    case MAPLE_CMD_INFO:
nkeynes@2
   164
                        status = MAPLE_RESP_INFO;
nkeynes@2
   165
                        memcpy( return_buf+4, dev->ident, 112 );
nkeynes@2
   166
                        out_length = 0x1C;
nkeynes@2
   167
                        break;
nkeynes@2
   168
                    case MAPLE_CMD_EXT_INFO:
nkeynes@2
   169
                        status = MAPLE_RESP_EXT_INFO;
nkeynes@2
   170
                        memcpy( return_buf+4, dev->ident, 192 );
nkeynes@2
   171
                        out_length = 0x30;
nkeynes@2
   172
                        break;
nkeynes@2
   173
                    case MAPLE_CMD_RESET:
nkeynes@2
   174
                        if( dev->reset == NULL )
nkeynes@2
   175
                            status = MAPLE_RESP_ACK;
nkeynes@2
   176
                        else status = dev->reset(dev);
nkeynes@2
   177
                        break;
nkeynes@2
   178
                    case MAPLE_CMD_SHUTDOWN:
nkeynes@2
   179
                        if( dev->shutdown == NULL )
nkeynes@2
   180
                            status = MAPLE_RESP_ACK;
nkeynes@2
   181
                        else status = dev->shutdown(dev);
nkeynes@2
   182
                        break;
nkeynes@2
   183
                    case MAPLE_CMD_GET_COND:
nkeynes@2
   184
                        func = GETWORD(12);
nkeynes@2
   185
                        if( dev->get_condition == NULL )
nkeynes@2
   186
                            status = MAPLE_ERR_CMD_UNKNOWN;
nkeynes@2
   187
                        else status = dev->get_condition(dev, func,
nkeynes@2
   188
                                                         return_buf+8,
nkeynes@2
   189
                                                         &out_length );
nkeynes@121
   190
			out_length++;
nkeynes@2
   191
                        if( status == 0 ) {
nkeynes@2
   192
                            status = MAPLE_RESP_DATA;
nkeynes@2
   193
                            PUTWORD(4,func);
nkeynes@2
   194
                        }
nkeynes@2
   195
                        break;
nkeynes@2
   196
                    case MAPLE_CMD_SET_COND:
nkeynes@2
   197
                        func = GETWORD(12);
nkeynes@2
   198
                        if( dev->set_condition == NULL )
nkeynes@2
   199
                            status = MAPLE_ERR_CMD_UNKNOWN;
nkeynes@2
   200
                        else status = dev->set_condition(dev, func,
nkeynes@2
   201
                                                         buf+16,
nkeynes@2
   202
                                                         length);
nkeynes@2
   203
                        if( status == 0 )
nkeynes@2
   204
                            status = MAPLE_RESP_ACK;
nkeynes@2
   205
                        break;
nkeynes@2
   206
                    case MAPLE_CMD_READ_BLOCK:
nkeynes@2
   207
                        func = GETWORD(12);
nkeynes@2
   208
                        block = GETWORD(16);
nkeynes@2
   209
                        if( dev->read_block == NULL )
nkeynes@2
   210
                            status = MAPLE_ERR_CMD_UNKNOWN;
nkeynes@2
   211
                        else status = dev->read_block(dev, func, block,
nkeynes@2
   212
                                                      return_buf+12,
nkeynes@2
   213
                                                      &out_length );
nkeynes@2
   214
                        if( status == 0 ) {
nkeynes@2
   215
                            status = MAPLE_RESP_DATA;
nkeynes@2
   216
                            PUTWORD(4,func);
nkeynes@2
   217
                            PUTWORD(8,block);
nkeynes@2
   218
                        }
nkeynes@2
   219
                        break;
nkeynes@2
   220
                    case MAPLE_CMD_WRITE_BLOCK:
nkeynes@2
   221
                        func = GETWORD(12);
nkeynes@2
   222
                        block = GETWORD(16);
nkeynes@2
   223
                        if( dev->write_block == NULL )
nkeynes@2
   224
                            status = MAPLE_ERR_CMD_UNKNOWN;
nkeynes@2
   225
                        else {
nkeynes@2
   226
                            status = dev->write_block(dev, func, block, 
nkeynes@2
   227
                                                      buf+20, length);
nkeynes@2
   228
                            if( status == 0 )
nkeynes@2
   229
                                status = MAPLE_RESP_ACK;
nkeynes@2
   230
                        }
nkeynes@2
   231
                        break;
nkeynes@2
   232
                    default:
nkeynes@2
   233
                        status = MAPLE_ERR_CMD_UNKNOWN;
nkeynes@2
   234
                }
nkeynes@2
   235
                return_buf[0] = status;
nkeynes@2
   236
                return_buf[1] = send_addr;
nkeynes@2
   237
                return_buf[2] = recv_addr;
nkeynes@2
   238
                if( periph == 0 )
nkeynes@2
   239
                    return_buf[2] |= maple_periph_mask[port];
nkeynes@2
   240
                return_buf[3] = out_length;
nkeynes@2
   241
            }
nkeynes@2
   242
            buf += 12 + (length<<2);
nkeynes@447
   243
	    address += 12 + (length<<2);
nkeynes@2
   244
        }
nkeynes@2
   245
        asic_event( EVENT_MAPLE_DMA );
nkeynes@1
   246
    }
nkeynes@1
   247
}
nkeynes@2
   248
nkeynes@2
   249
void maple_attach_device( maple_device_t dev, unsigned int port,
nkeynes@2
   250
                          unsigned int periph ) {
nkeynes@2
   251
    assert( port < 4 );
nkeynes@2
   252
    assert( periph < 6 );
nkeynes@2
   253
nkeynes@2
   254
    if( maple_devices[port][periph] != NULL ) {
nkeynes@2
   255
        /* Detach existing peripheral first */
nkeynes@2
   256
        maple_detach_device( port, periph );
nkeynes@2
   257
    }
nkeynes@2
   258
    
nkeynes@2
   259
    maple_devices[port][periph] = dev;
nkeynes@2
   260
    if( periph != 0 )
nkeynes@2
   261
        maple_periph_mask[port] |= (1<<(periph-1));
nkeynes@2
   262
    else maple_periph_mask[port] |= 0x20;
nkeynes@2
   263
    if( dev->attach != NULL ) {
nkeynes@2
   264
        dev->attach( dev );
nkeynes@2
   265
    }
nkeynes@2
   266
}
nkeynes@2
   267
nkeynes@2
   268
void maple_detach_device( unsigned int port, unsigned int periph ) {
nkeynes@2
   269
    assert( port < 4 );
nkeynes@2
   270
    assert( periph < 6 );
nkeynes@2
   271
nkeynes@2
   272
    maple_device_t dev = maple_devices[port][periph];
nkeynes@2
   273
    if( dev == NULL ) /* already detached */
nkeynes@2
   274
        return;
nkeynes@2
   275
    maple_devices[port][periph] = NULL;
nkeynes@2
   276
    if( dev->detach != NULL ) {
nkeynes@2
   277
        dev->detach(dev);
nkeynes@2
   278
    }
nkeynes@447
   279
    if( dev->destroy != NULL ) {
nkeynes@447
   280
	dev->destroy(dev);
nkeynes@447
   281
    }
nkeynes@2
   282
    if( periph == 0 ) {
nkeynes@2
   283
        /* If we detach the main peripheral, we also have to detach all the
nkeynes@2
   284
         * subperipherals, or the system could get quite confused
nkeynes@2
   285
         */
nkeynes@2
   286
        int i;
nkeynes@2
   287
        maple_periph_mask[port] = 0;
nkeynes@2
   288
        for( i=1; i<6; i++ ) {
nkeynes@2
   289
            maple_detach_device(port,i);
nkeynes@2
   290
        }
nkeynes@2
   291
    } else {
nkeynes@2
   292
        maple_periph_mask[port] &= (~(1<<(periph-1)));
nkeynes@2
   293
    }
nkeynes@144
   294
    
nkeynes@2
   295
}
nkeynes@144
   296
nkeynes@144
   297
void maple_detach_all() {
nkeynes@144
   298
    int i, j;
nkeynes@144
   299
    for( i=0; i<4; i++ ) {
nkeynes@144
   300
	for( j=0; j<6; j++ ) {
nkeynes@144
   301
	    if( maple_devices[i][j] != NULL ) {
nkeynes@144
   302
		maple_device_t dev = maple_devices[i][j];
nkeynes@144
   303
		if( dev->detach != NULL )
nkeynes@144
   304
		    dev->detach(dev);
nkeynes@144
   305
		if( dev->destroy != NULL )
nkeynes@144
   306
		    dev->destroy(dev);
nkeynes@144
   307
	    }
nkeynes@144
   308
	}
nkeynes@144
   309
	maple_periph_mask[i] = 0;
nkeynes@144
   310
    }
nkeynes@144
   311
}
nkeynes@144
   312
nkeynes@144
   313
void maple_reattach_all() {
nkeynes@144
   314
    int i, j;
nkeynes@144
   315
    for( i=0; i<4; i++ ) {
nkeynes@144
   316
	for( j=0; j<6; j++ ) {
nkeynes@144
   317
	    if( maple_devices[i][j] != NULL ) {
nkeynes@144
   318
		maple_device_t dev = maple_devices[i][j];
nkeynes@144
   319
		if( dev->attach != NULL )
nkeynes@144
   320
		    dev->attach(dev);
nkeynes@144
   321
	    }
nkeynes@144
   322
	}
nkeynes@144
   323
    }
nkeynes@144
   324
}
.