Search
lxdream.org :: lxdream/src/maple/maple.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/maple/maple.c
changeset 121:795fec623ce9
prev35:21a4be098304
next144:7f0714e89aaa
author nkeynes
date Mon Mar 20 12:00:15 2006 +0000 (14 years ago)
permissions -rw-r--r--
last change Fix incorrect response length for condition queries
view annotate diff log raw
     1 /**
     2  * $Id: maple.c,v 1.7 2006-03-20 12:00:15 nkeynes Exp $
     3  *
     4  * Implements the core Maple bus, including DMA transfers to and from the bus.
     5  *
     6  * Copyright (c) 2005 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    18 #define MODULE maple_module
    20 #include <assert.h>
    21 #include "dream.h"
    22 #include "mem.h"
    23 #include "asic.h"
    24 #include "maple.h"
    26 void maple_init( void );
    28 struct dreamcast_module maple_module = { "Maple", maple_init, NULL, NULL, NULL,
    29 					 NULL, NULL, NULL };
    31 void maple_init( void )
    32 {
    34 }
    36 /**
    37  * Input data looks like this:
    38  *    0: transfer control word
    39  *      0: length of data in words (not including 3 word header)
    40  *      1: low bit = lightgun mode
    41  *      2: low 2 bits = port # (0..3)
    42  *      3: 0x80 = last packet, 0x00 = normal packet
    43  *    4: output buffer address
    44  *    8: Command word
    45  *      8: command code
    46  *      9: destination address
    47  *     10: source address
    48  *     11: length of data in words (not including 3 word header)
    49  *   12: command-specific data
    50  */
    52 /**
    53  * array is [port][subperipheral], so [0][0] is main peripheral on port A,
    54  * [1][2] is the second subperipheral on port B and so on.
    55  */
    56 maple_device_t maple_devices[4][6];
    57 int maple_periph_mask[4];
    58 #define GETBYTE(n) ((uint32_t)(buf[n]))
    59 #define GETWORD(n) (*((uint32_t *)(buf+(n))))
    60 #define PUTBYTE(n,x) (buf[n] = (char)x)
    61 #define PUTWORD(n,x) (*((uint32_t *)(return_buf+(n))) = (x))
    63 void maple_handle_buffer( uint32_t address ) {
    64     unsigned char *buf = (unsigned char *)mem_get_region(address);
    65     if( buf == NULL ) {
    66         ERROR( "Invalid or unmapped buffer passed to maple (0x%08X)", address );
    67     } else {
    68         unsigned int last = 0;
    69         int i = 0, count;
    70         for( count=0; !last; count++ ) {
    71             unsigned int port, length, gun, periph, periph_id, out_length;
    72             unsigned int cmd, recv_addr, send_addr;
    73             uint32_t return_addr;
    74             unsigned char *return_buf;
    76             last = GETBYTE(3) & 0x80; /* indicates last packet */
    77             port = GETBYTE(2) & 0x03;
    78             gun = GETBYTE(1) & 0x01;
    79             length = GETBYTE(0) & 0xFF;
    80             return_addr = GETWORD(4);
    81             if( return_addr == 0 ) {
    82                 /* ERROR */
    83             }
    84             return_buf = mem_get_region(return_addr);
    85             cmd = GETBYTE(8);
    86             recv_addr = GETBYTE(9);
    87             send_addr = GETBYTE(10);
    88             /* Sanity checks */
    89             if( GETBYTE(11) != length ||
    90                 send_addr != (port<<6) ||
    91                 recv_addr >> 6 != port ||
    92                 return_buf == NULL ) {
    93                 /* ERROR */
    94             }
    95             periph = 0;
    96             periph_id = recv_addr & 0x3F;
    97             if( periph_id != 0x20 ) {
    98                 for( i=0;i<5;i++ ) {
    99                     if( periph_id == (1<<i) ) {
   100                         periph = i+1;
   101                         break;
   102                     }
   103                 }
   104                 if( periph == 0 ) { /* Bad setting */
   105                     /* ERROR */
   106                 }
   107             }
   109             INFO( "Maple packet %d: Cmd %d on port %d device %d", count, cmd, port, periph );
   110             maple_device_t dev = maple_devices[port][periph];
   111             if( dev == NULL ) {
   112                 /* no device attached */
   113                 *((uint32_t *)return_buf) = -1;
   114             } else {
   115                 int status, func, block;
   116                 out_length = 0;
   117                 switch( cmd ) {
   118                     case MAPLE_CMD_INFO:
   119                         status = MAPLE_RESP_INFO;
   120                         memcpy( return_buf+4, dev->ident, 112 );
   121                         out_length = 0x1C;
   122                         break;
   123                     case MAPLE_CMD_EXT_INFO:
   124                         status = MAPLE_RESP_EXT_INFO;
   125                         memcpy( return_buf+4, dev->ident, 192 );
   126                         out_length = 0x30;
   127                         break;
   128                     case MAPLE_CMD_RESET:
   129                         if( dev->reset == NULL )
   130                             status = MAPLE_RESP_ACK;
   131                         else status = dev->reset(dev);
   132                         break;
   133                     case MAPLE_CMD_SHUTDOWN:
   134                         if( dev->shutdown == NULL )
   135                             status = MAPLE_RESP_ACK;
   136                         else status = dev->shutdown(dev);
   137                         break;
   138                     case MAPLE_CMD_GET_COND:
   139                         func = GETWORD(12);
   140                         if( dev->get_condition == NULL )
   141                             status = MAPLE_ERR_CMD_UNKNOWN;
   142                         else status = dev->get_condition(dev, func,
   143                                                          return_buf+8,
   144                                                          &out_length );
   145 			out_length++;
   146                         if( status == 0 ) {
   147                             status = MAPLE_RESP_DATA;
   148                             PUTWORD(4,func);
   149                         }
   150                         break;
   151                     case MAPLE_CMD_SET_COND:
   152                         func = GETWORD(12);
   153                         if( dev->set_condition == NULL )
   154                             status = MAPLE_ERR_CMD_UNKNOWN;
   155                         else status = dev->set_condition(dev, func,
   156                                                          buf+16,
   157                                                          length);
   158                         if( status == 0 )
   159                             status = MAPLE_RESP_ACK;
   160                         break;
   161                     case MAPLE_CMD_READ_BLOCK:
   162                         func = GETWORD(12);
   163                         block = GETWORD(16);
   164                         if( dev->read_block == NULL )
   165                             status = MAPLE_ERR_CMD_UNKNOWN;
   166                         else status = dev->read_block(dev, func, block,
   167                                                       return_buf+12,
   168                                                       &out_length );
   169                         if( status == 0 ) {
   170                             status = MAPLE_RESP_DATA;
   171                             PUTWORD(4,func);
   172                             PUTWORD(8,block);
   173                         }
   174                         break;
   175                     case MAPLE_CMD_WRITE_BLOCK:
   176                         func = GETWORD(12);
   177                         block = GETWORD(16);
   178                         if( dev->write_block == NULL )
   179                             status = MAPLE_ERR_CMD_UNKNOWN;
   180                         else {
   181                             status = dev->write_block(dev, func, block, 
   182                                                       buf+20, length);
   183                             if( status == 0 )
   184                                 status = MAPLE_RESP_ACK;
   185                         }
   186                         break;
   187                     default:
   188                         status = MAPLE_ERR_CMD_UNKNOWN;
   189                 }
   190                 return_buf[0] = status;
   191                 return_buf[1] = send_addr;
   192                 return_buf[2] = recv_addr;
   193                 if( periph == 0 )
   194                     return_buf[2] |= maple_periph_mask[port];
   195                 return_buf[3] = out_length;
   196             }
   197             buf += 12 + (length<<2);
   198         }
   199         asic_event( EVENT_MAPLE_DMA );
   200     }
   201 }
   203 void maple_attach_device( maple_device_t dev, unsigned int port,
   204                           unsigned int periph ) {
   205     assert( port < 4 );
   206     assert( periph < 6 );
   208     if( maple_devices[port][periph] != NULL ) {
   209         /* Detach existing peripheral first */
   210         maple_detach_device( port, periph );
   211     }
   213     maple_devices[port][periph] = dev;
   214     if( periph != 0 )
   215         maple_periph_mask[port] |= (1<<(periph-1));
   216     else maple_periph_mask[port] |= 0x20;
   217     if( dev->attach != NULL ) {
   218         dev->attach( dev );
   219     }
   220 }
   222 void maple_detach_device( unsigned int port, unsigned int periph ) {
   223     assert( port < 4 );
   224     assert( periph < 6 );
   226     maple_device_t dev = maple_devices[port][periph];
   227     if( dev == NULL ) /* already detached */
   228         return;
   229     maple_devices[port][periph] = NULL;
   230     if( dev->detach != NULL ) {
   231         dev->detach(dev);
   232     }
   233     if( periph == 0 ) {
   234         /* If we detach the main peripheral, we also have to detach all the
   235          * subperipherals, or the system could get quite confused
   236          */
   237         int i;
   238         maple_periph_mask[port] = 0;
   239         for( i=1; i<6; i++ ) {
   240             maple_detach_device(port,i);
   241         }
   242     } else {
   243         maple_periph_mask[port] &= (~(1<<(periph-1)));
   244     }
   246 }
.