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 Wed Oct 17 11:26:45 2007 +0000 (16 years ago)
permissions -rw-r--r--
last change Split config management out to config.[ch]
Manage config filename
Check home dir + sysconfdir for conf file
Initial work on a path settings dialog
view annotate diff log raw
     1 /**
     2  * $Id: maple.c,v 1.11 2007-10-17 11:26:45 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 struct maple_device_class *maple_device_classes[] = { &controller_class, NULL };
    33 void maple_init( void )
    34 {
    36 }
    38 maple_device_t maple_new_device( const gchar *name )
    39 {
    40     maple_device_class_t clz = maple_get_device_class(name);
    41     if( clz != NULL ) {
    42 	return clz->new_device();
    43     } 
    44     return NULL;
    45 }
    47 const maple_device_class_t maple_get_device_class( const gchar *name )
    48 {
    49     int i;
    50     for( i=0; maple_device_classes[i] != NULL; i++ ) {
    51 	if( g_strcasecmp(maple_device_classes[i]->name, name ) == 0 )
    52 	    return maple_device_classes[i];
    53     }
    54     return NULL;
    55 }
    57 const struct maple_device_class **maple_get_device_classes()
    58 {
    59     return maple_device_classes;
    60 }
    62 lxdream_config_entry_t maple_get_device_config( maple_device_t dev )
    63 {
    64     if( dev->get_config == NULL )
    65 	return NULL;
    66     return dev->get_config(dev);
    67 }
    69 /**
    70  * Input data looks like this:
    71  *    0: transfer control word
    72  *      0: length of data in words (not including 3 word header)
    73  *      1: low bit = lightgun mode
    74  *      2: low 2 bits = port # (0..3)
    75  *      3: 0x80 = last packet, 0x00 = normal packet
    76  *    4: output buffer address
    77  *    8: Command word
    78  *      8: command code
    79  *      9: destination address
    80  *     10: source address
    81  *     11: length of data in words (not including 3 word header)
    82  *   12: command-specific data
    83  */
    85 /**
    86  * array is [port][subperipheral], so [0][0] is main peripheral on port A,
    87  * [1][2] is the second subperipheral on port B and so on.
    88  */
    89 maple_device_t maple_devices[4][6];
    90 int maple_periph_mask[4];
    91 #define GETBYTE(n) ((uint32_t)(buf[n]))
    92 #define GETWORD(n) (*((uint32_t *)(buf+(n))))
    93 #define PUTBYTE(n,x) (buf[n] = (char)x)
    94 #define PUTWORD(n,x) (*((uint32_t *)(return_buf+(n))) = (x))
    96 maple_device_t maple_get_device( unsigned int port, unsigned int periph ) {
    97     if( port >= 4 )
    98 	return NULL;
    99     if( periph >= 6 )
   100 	return NULL;
   101     return maple_devices[port][periph];
   102 }
   104 void maple_handle_buffer( uint32_t address ) {
   105     unsigned char *buf = (unsigned char *)mem_get_region(address);
   106     if( buf == NULL ) {
   107         ERROR( "Invalid or unmapped buffer passed to maple (0x%08X)", address );
   108     } else {
   109         unsigned int last = 0;
   110         int i = 0, count;
   111         for( count=0; !last; count++ ) {
   112             unsigned int port, length, gun, periph, periph_id, out_length;
   113             unsigned int cmd, recv_addr, send_addr;
   114             uint32_t return_addr;
   115             unsigned char *return_buf;
   117             last = GETBYTE(3) & 0x80; /* indicates last packet */
   118             port = GETBYTE(2) & 0x03;
   119             gun = GETBYTE(1) & 0x01;
   120             length = GETBYTE(0) & 0xFF;
   121             return_addr = GETWORD(4);
   123             if( (return_addr & 0x1C000000) != 0x0C000000 ) {
   124 		ERROR( "Bad return address in maple packet: %08X", return_addr );
   125 		break;
   126             }
   127             return_buf = mem_get_region(return_addr);
   128             cmd = GETBYTE(8);
   129             recv_addr = GETBYTE(9);
   130             send_addr = GETBYTE(10);
   131             /* Sanity checks */
   132             if( GETBYTE(11) != length ||
   133                 send_addr >> 6 != port ||
   134                 recv_addr >> 6 != port ||
   135                 return_buf == NULL ) {
   136 		ERROR( "Received bad packet: %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X",
   137 		       buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
   138 		       buf[8], buf[9], buf[10], buf[11] );
   139 		break;
   140             }
   141             periph = 0;
   142             periph_id = recv_addr & 0x3F;
   143             if( periph_id != 0x20 ) {
   144                 for( i=0;i<5;i++ ) {
   145                     if( periph_id == (1<<i) ) {
   146                         periph = i+1;
   147                         break;
   148                     }
   149                 }
   150                 if( periph == 0 ) { /* Bad setting */
   151                     /* ERROR */
   152                 }
   153             }
   155             maple_device_t dev = maple_devices[port][periph];
   156             if( dev == NULL ) {
   157                 /* no device attached */
   158                 *((uint32_t *)return_buf) = -1;
   159             } else {
   160                 int status, func, block;
   161                 out_length = 0;
   162                 switch( cmd ) {
   163                     case MAPLE_CMD_INFO:
   164                         status = MAPLE_RESP_INFO;
   165                         memcpy( return_buf+4, dev->ident, 112 );
   166                         out_length = 0x1C;
   167                         break;
   168                     case MAPLE_CMD_EXT_INFO:
   169                         status = MAPLE_RESP_EXT_INFO;
   170                         memcpy( return_buf+4, dev->ident, 192 );
   171                         out_length = 0x30;
   172                         break;
   173                     case MAPLE_CMD_RESET:
   174                         if( dev->reset == NULL )
   175                             status = MAPLE_RESP_ACK;
   176                         else status = dev->reset(dev);
   177                         break;
   178                     case MAPLE_CMD_SHUTDOWN:
   179                         if( dev->shutdown == NULL )
   180                             status = MAPLE_RESP_ACK;
   181                         else status = dev->shutdown(dev);
   182                         break;
   183                     case MAPLE_CMD_GET_COND:
   184                         func = GETWORD(12);
   185                         if( dev->get_condition == NULL )
   186                             status = MAPLE_ERR_CMD_UNKNOWN;
   187                         else status = dev->get_condition(dev, func,
   188                                                          return_buf+8,
   189                                                          &out_length );
   190 			out_length++;
   191                         if( status == 0 ) {
   192                             status = MAPLE_RESP_DATA;
   193                             PUTWORD(4,func);
   194                         }
   195                         break;
   196                     case MAPLE_CMD_SET_COND:
   197                         func = GETWORD(12);
   198                         if( dev->set_condition == NULL )
   199                             status = MAPLE_ERR_CMD_UNKNOWN;
   200                         else status = dev->set_condition(dev, func,
   201                                                          buf+16,
   202                                                          length);
   203                         if( status == 0 )
   204                             status = MAPLE_RESP_ACK;
   205                         break;
   206                     case MAPLE_CMD_READ_BLOCK:
   207                         func = GETWORD(12);
   208                         block = GETWORD(16);
   209                         if( dev->read_block == NULL )
   210                             status = MAPLE_ERR_CMD_UNKNOWN;
   211                         else status = dev->read_block(dev, func, block,
   212                                                       return_buf+12,
   213                                                       &out_length );
   214                         if( status == 0 ) {
   215                             status = MAPLE_RESP_DATA;
   216                             PUTWORD(4,func);
   217                             PUTWORD(8,block);
   218                         }
   219                         break;
   220                     case MAPLE_CMD_WRITE_BLOCK:
   221                         func = GETWORD(12);
   222                         block = GETWORD(16);
   223                         if( dev->write_block == NULL )
   224                             status = MAPLE_ERR_CMD_UNKNOWN;
   225                         else {
   226                             status = dev->write_block(dev, func, block, 
   227                                                       buf+20, length);
   228                             if( status == 0 )
   229                                 status = MAPLE_RESP_ACK;
   230                         }
   231                         break;
   232                     default:
   233                         status = MAPLE_ERR_CMD_UNKNOWN;
   234                 }
   235                 return_buf[0] = status;
   236                 return_buf[1] = send_addr;
   237                 return_buf[2] = recv_addr;
   238                 if( periph == 0 )
   239                     return_buf[2] |= maple_periph_mask[port];
   240                 return_buf[3] = out_length;
   241             }
   242             buf += 12 + (length<<2);
   243 	    address += 12 + (length<<2);
   244         }
   245         asic_event( EVENT_MAPLE_DMA );
   246     }
   247 }
   249 void maple_attach_device( maple_device_t dev, unsigned int port,
   250                           unsigned int periph ) {
   251     assert( port < 4 );
   252     assert( periph < 6 );
   254     if( maple_devices[port][periph] != NULL ) {
   255         /* Detach existing peripheral first */
   256         maple_detach_device( port, periph );
   257     }
   259     maple_devices[port][periph] = dev;
   260     if( periph != 0 )
   261         maple_periph_mask[port] |= (1<<(periph-1));
   262     else maple_periph_mask[port] |= 0x20;
   263     if( dev->attach != NULL ) {
   264         dev->attach( dev );
   265     }
   266 }
   268 void maple_detach_device( unsigned int port, unsigned int periph ) {
   269     assert( port < 4 );
   270     assert( periph < 6 );
   272     maple_device_t dev = maple_devices[port][periph];
   273     if( dev == NULL ) /* already detached */
   274         return;
   275     maple_devices[port][periph] = NULL;
   276     if( dev->detach != NULL ) {
   277         dev->detach(dev);
   278     }
   279     if( dev->destroy != NULL ) {
   280 	dev->destroy(dev);
   281     }
   282     if( periph == 0 ) {
   283         /* If we detach the main peripheral, we also have to detach all the
   284          * subperipherals, or the system could get quite confused
   285          */
   286         int i;
   287         maple_periph_mask[port] = 0;
   288         for( i=1; i<6; i++ ) {
   289             maple_detach_device(port,i);
   290         }
   291     } else {
   292         maple_periph_mask[port] &= (~(1<<(periph-1)));
   293     }
   295 }
   297 void maple_detach_all() {
   298     int i, j;
   299     for( i=0; i<4; i++ ) {
   300 	for( j=0; j<6; j++ ) {
   301 	    if( maple_devices[i][j] != NULL ) {
   302 		maple_device_t dev = maple_devices[i][j];
   303 		if( dev->detach != NULL )
   304 		    dev->detach(dev);
   305 		if( dev->destroy != NULL )
   306 		    dev->destroy(dev);
   307 	    }
   308 	}
   309 	maple_periph_mask[i] = 0;
   310     }
   311 }
   313 void maple_reattach_all() {
   314     int i, j;
   315     for( i=0; i<4; i++ ) {
   316 	for( j=0; j<6; j++ ) {
   317 	    if( maple_devices[i][j] != NULL ) {
   318 		maple_device_t dev = maple_devices[i][j];
   319 		if( dev->attach != NULL )
   320 		    dev->attach(dev);
   321 	    }
   322 	}
   323     }
   324 }
.