Search
lxdream.org :: lxdream/src/maple/maple.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/maple/maple.c
changeset 15:5194dd0fdb60
prev2:42349f6ea216
next23:1ec3acd0594d
author nkeynes
date Mon Dec 12 13:11:11 2005 +0000 (14 years ago)
permissions -rw-r--r--
last change Add dreamcast_module module structure
file annotate diff log raw
nkeynes@1
     1
#include <assert.h>
nkeynes@1
     2
#include "dream.h"
nkeynes@15
     3
#include "modules.h"
nkeynes@1
     4
#include "mem.h"
nkeynes@1
     5
#include "asic.h"
nkeynes@1
     6
#include "maple.h"
nkeynes@1
     7
nkeynes@15
     8
void maple_init( void );
nkeynes@15
     9
nkeynes@15
    10
struct dreamcast_module maple_module = { "Maple", maple_init, NULL, NULL, NULL,
nkeynes@15
    11
					 NULL, NULL };
nkeynes@15
    12
nkeynes@15
    13
void maple_init( void )
nkeynes@15
    14
{
nkeynes@15
    15
nkeynes@15
    16
}
nkeynes@15
    17
nkeynes@2
    18
/**
nkeynes@2
    19
 * Input data looks like this:
nkeynes@2
    20
 *    0: transfer control word
nkeynes@2
    21
 *      0: length of data in words (not including 3 word header)
nkeynes@2
    22
 *      1: low bit = lightgun mode
nkeynes@2
    23
 *      2: low 2 bits = port # (0..3)
nkeynes@2
    24
 *      3: 0x80 = last packet, 0x00 = normal packet
nkeynes@2
    25
 *    4: output buffer address
nkeynes@2
    26
 *    8: Command word
nkeynes@2
    27
 *      8: command code
nkeynes@2
    28
 *      9: destination address
nkeynes@2
    29
 *     10: source address
nkeynes@2
    30
 *     11: length of data in words (not including 3 word header)
nkeynes@2
    31
 *   12: command-specific data
nkeynes@2
    32
 */
nkeynes@2
    33
nkeynes@2
    34
/**
nkeynes@2
    35
 * array is [port][subperipheral], so [0][0] is main peripheral on port A,
nkeynes@2
    36
 * [1][2] is the second subperipheral on port B and so on.
nkeynes@2
    37
 */
nkeynes@2
    38
maple_device_t maple_devices[4][6];
nkeynes@2
    39
int maple_periph_mask[4];
nkeynes@2
    40
#define GETBYTE(n) ((uint32_t)(buf[n]))
nkeynes@2
    41
#define GETWORD(n) (*((uint32_t *)(buf+(n))))
nkeynes@2
    42
#define PUTBYTE(n,x) (buf[n] = (char)x)
nkeynes@2
    43
#define PUTWORD(n,x) (*((uint32_t *)(return_buf+(n))) = (x))
nkeynes@2
    44
nkeynes@1
    45
void maple_handle_buffer( uint32_t address ) {
nkeynes@2
    46
    unsigned char *buf = (unsigned char *)mem_get_region(address);
nkeynes@1
    47
    if( buf == NULL ) {
nkeynes@1
    48
        ERROR( "Invalid or unmapped buffer passed to maple (0x%08X)", address );
nkeynes@1
    49
    } else {
nkeynes@2
    50
        unsigned int last = 0;
nkeynes@2
    51
        int i = 0, count;
nkeynes@2
    52
        for( count=0; !last; count++ ) {
nkeynes@2
    53
            unsigned int port, length, gun, periph, periph_id, out_length;
nkeynes@2
    54
            unsigned int cmd, recv_addr, send_addr;
nkeynes@2
    55
            uint32_t return_addr;
nkeynes@2
    56
            unsigned char *return_buf;
nkeynes@1
    57
            
nkeynes@2
    58
            last = GETBYTE(3) & 0x80; /* indicates last packet */
nkeynes@2
    59
            port = GETBYTE(2) & 0x03;
nkeynes@2
    60
            gun = GETBYTE(1) & 0x01;
nkeynes@2
    61
            length = GETBYTE(0) & 0xFF;
nkeynes@2
    62
            return_addr = GETWORD(4);
nkeynes@2
    63
            if( return_addr == 0 ) {
nkeynes@2
    64
                /* ERROR */
nkeynes@2
    65
            }
nkeynes@2
    66
            return_buf = mem_get_region(return_addr);
nkeynes@2
    67
            cmd = GETBYTE(8);
nkeynes@2
    68
            recv_addr = GETBYTE(9);
nkeynes@2
    69
            send_addr = GETBYTE(10);
nkeynes@2
    70
            /* Sanity checks */
nkeynes@2
    71
            if( GETBYTE(11) != length ||
nkeynes@2
    72
                send_addr != (port<<6) ||
nkeynes@2
    73
                recv_addr >> 6 != port ||
nkeynes@2
    74
                return_buf == NULL ) {
nkeynes@2
    75
                /* ERROR */
nkeynes@2
    76
            }
nkeynes@2
    77
            periph = 0;
nkeynes@2
    78
            periph_id = recv_addr & 0x3F;
nkeynes@2
    79
            if( periph_id != 0x20 ) {
nkeynes@2
    80
                for( i=0;i<5;i++ ) {
nkeynes@2
    81
                    if( periph_id == (1<<i) ) {
nkeynes@2
    82
                        periph = i+1;
nkeynes@2
    83
                        break;
nkeynes@2
    84
                    }
nkeynes@2
    85
                }
nkeynes@2
    86
                if( periph == 0 ) { /* Bad setting */
nkeynes@2
    87
                    /* ERROR */
nkeynes@2
    88
                }
nkeynes@2
    89
            }
nkeynes@2
    90
nkeynes@2
    91
            INFO( "Maple packet %d: Cmd %d on port %d device %d", count, cmd, port, periph );
nkeynes@2
    92
            maple_device_t dev = maple_devices[port][periph];
nkeynes@2
    93
            if( dev == NULL ) {
nkeynes@2
    94
                /* no device attached */
nkeynes@2
    95
                *((uint32_t *)return_buf) = -1;
nkeynes@2
    96
            } else {
nkeynes@2
    97
                int status, func, block;
nkeynes@2
    98
                out_length = 0;
nkeynes@2
    99
                switch( cmd ) {
nkeynes@2
   100
                    case MAPLE_CMD_INFO:
nkeynes@2
   101
                        status = MAPLE_RESP_INFO;
nkeynes@2
   102
                        memcpy( return_buf+4, dev->ident, 112 );
nkeynes@2
   103
                        out_length = 0x1C;
nkeynes@2
   104
                        break;
nkeynes@2
   105
                    case MAPLE_CMD_EXT_INFO:
nkeynes@2
   106
                        status = MAPLE_RESP_EXT_INFO;
nkeynes@2
   107
                        memcpy( return_buf+4, dev->ident, 192 );
nkeynes@2
   108
                        out_length = 0x30;
nkeynes@2
   109
                        break;
nkeynes@2
   110
                    case MAPLE_CMD_RESET:
nkeynes@2
   111
                        if( dev->reset == NULL )
nkeynes@2
   112
                            status = MAPLE_RESP_ACK;
nkeynes@2
   113
                        else status = dev->reset(dev);
nkeynes@2
   114
                        break;
nkeynes@2
   115
                    case MAPLE_CMD_SHUTDOWN:
nkeynes@2
   116
                        if( dev->shutdown == NULL )
nkeynes@2
   117
                            status = MAPLE_RESP_ACK;
nkeynes@2
   118
                        else status = dev->shutdown(dev);
nkeynes@2
   119
                        break;
nkeynes@2
   120
                    case MAPLE_CMD_GET_COND:
nkeynes@2
   121
                        func = GETWORD(12);
nkeynes@2
   122
                        if( dev->get_condition == NULL )
nkeynes@2
   123
                            status = MAPLE_ERR_CMD_UNKNOWN;
nkeynes@2
   124
                        else status = dev->get_condition(dev, func,
nkeynes@2
   125
                                                         return_buf+8,
nkeynes@2
   126
                                                         &out_length );
nkeynes@2
   127
                        if( status == 0 ) {
nkeynes@2
   128
                            status = MAPLE_RESP_DATA;
nkeynes@2
   129
                            PUTWORD(4,func);
nkeynes@2
   130
                        }
nkeynes@2
   131
                        break;
nkeynes@2
   132
                    case MAPLE_CMD_SET_COND:
nkeynes@2
   133
                        func = GETWORD(12);
nkeynes@2
   134
                        if( dev->set_condition == NULL )
nkeynes@2
   135
                            status = MAPLE_ERR_CMD_UNKNOWN;
nkeynes@2
   136
                        else status = dev->set_condition(dev, func,
nkeynes@2
   137
                                                         buf+16,
nkeynes@2
   138
                                                         length);
nkeynes@2
   139
                        if( status == 0 )
nkeynes@2
   140
                            status = MAPLE_RESP_ACK;
nkeynes@2
   141
                        break;
nkeynes@2
   142
                    case MAPLE_CMD_READ_BLOCK:
nkeynes@2
   143
                        func = GETWORD(12);
nkeynes@2
   144
                        block = GETWORD(16);
nkeynes@2
   145
                        if( dev->read_block == NULL )
nkeynes@2
   146
                            status = MAPLE_ERR_CMD_UNKNOWN;
nkeynes@2
   147
                        else status = dev->read_block(dev, func, block,
nkeynes@2
   148
                                                      return_buf+12,
nkeynes@2
   149
                                                      &out_length );
nkeynes@2
   150
                        if( status == 0 ) {
nkeynes@2
   151
                            status = MAPLE_RESP_DATA;
nkeynes@2
   152
                            PUTWORD(4,func);
nkeynes@2
   153
                            PUTWORD(8,block);
nkeynes@2
   154
                        }
nkeynes@2
   155
                        break;
nkeynes@2
   156
                    case MAPLE_CMD_WRITE_BLOCK:
nkeynes@2
   157
                        func = GETWORD(12);
nkeynes@2
   158
                        block = GETWORD(16);
nkeynes@2
   159
                        if( dev->write_block == NULL )
nkeynes@2
   160
                            status = MAPLE_ERR_CMD_UNKNOWN;
nkeynes@2
   161
                        else {
nkeynes@2
   162
                            status = dev->write_block(dev, func, block, 
nkeynes@2
   163
                                                      buf+20, length);
nkeynes@2
   164
                            if( status == 0 )
nkeynes@2
   165
                                status = MAPLE_RESP_ACK;
nkeynes@2
   166
                        }
nkeynes@2
   167
                        break;
nkeynes@2
   168
                    default:
nkeynes@2
   169
                        status = MAPLE_ERR_CMD_UNKNOWN;
nkeynes@2
   170
                }
nkeynes@2
   171
                return_buf[0] = status;
nkeynes@2
   172
                return_buf[1] = send_addr;
nkeynes@2
   173
                return_buf[2] = recv_addr;
nkeynes@2
   174
                if( periph == 0 )
nkeynes@2
   175
                    return_buf[2] |= maple_periph_mask[port];
nkeynes@2
   176
                return_buf[3] = out_length;
nkeynes@2
   177
            }
nkeynes@2
   178
            buf += 12 + (length<<2);
nkeynes@2
   179
        }
nkeynes@2
   180
        asic_event( EVENT_MAPLE_DMA );
nkeynes@1
   181
    }
nkeynes@1
   182
}
nkeynes@2
   183
nkeynes@2
   184
void maple_attach_device( maple_device_t dev, unsigned int port,
nkeynes@2
   185
                          unsigned int periph ) {
nkeynes@2
   186
    assert( port < 4 );
nkeynes@2
   187
    assert( periph < 6 );
nkeynes@2
   188
nkeynes@2
   189
    if( maple_devices[port][periph] != NULL ) {
nkeynes@2
   190
        /* Detach existing peripheral first */
nkeynes@2
   191
        maple_detach_device( port, periph );
nkeynes@2
   192
    }
nkeynes@2
   193
    
nkeynes@2
   194
    maple_devices[port][periph] = dev;
nkeynes@2
   195
    if( periph != 0 )
nkeynes@2
   196
        maple_periph_mask[port] |= (1<<(periph-1));
nkeynes@2
   197
    else maple_periph_mask[port] |= 0x20;
nkeynes@2
   198
    if( dev->attach != NULL ) {
nkeynes@2
   199
        dev->attach( dev );
nkeynes@2
   200
    }
nkeynes@2
   201
}
nkeynes@2
   202
nkeynes@2
   203
void maple_detach_device( unsigned int port, unsigned int periph ) {
nkeynes@2
   204
    assert( port < 4 );
nkeynes@2
   205
    assert( periph < 6 );
nkeynes@2
   206
nkeynes@2
   207
    maple_device_t dev = maple_devices[port][periph];
nkeynes@2
   208
    if( dev == NULL ) /* already detached */
nkeynes@2
   209
        return;
nkeynes@2
   210
    maple_devices[port][periph] = NULL;
nkeynes@2
   211
    if( dev->detach != NULL ) {
nkeynes@2
   212
        dev->detach(dev);
nkeynes@2
   213
    }
nkeynes@2
   214
    if( periph == 0 ) {
nkeynes@2
   215
        /* If we detach the main peripheral, we also have to detach all the
nkeynes@2
   216
         * subperipherals, or the system could get quite confused
nkeynes@2
   217
         */
nkeynes@2
   218
        int i;
nkeynes@2
   219
        maple_periph_mask[port] = 0;
nkeynes@2
   220
        for( i=1; i<6; i++ ) {
nkeynes@2
   221
            maple_detach_device(port,i);
nkeynes@2
   222
        }
nkeynes@2
   223
    } else {
nkeynes@2
   224
        maple_periph_mask[port] &= (~(1<<(periph-1)));
nkeynes@2
   225
    }
nkeynes@2
   226
                                    
nkeynes@2
   227
}
.