Search
lxdream.org :: lxdream/src/maple/maple.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/maple/maple.c
changeset 144:7f0714e89aaa
prev121:795fec623ce9
next159:406161fea392
author nkeynes
date Mon May 15 08:28:52 2006 +0000 (13 years ago)
permissions -rw-r--r--
last change Rename video_driver to display_driver
Add input source to display
Implement configuration file support
Hook controllers up to configuration
view annotate diff log raw
     1 /**
     2  * $Id: maple.c,v 1.8 2006-05-15 08:28:52 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     int i;
    41     for( i=0; maple_device_classes[i] != NULL; i++ ) {
    42 	if( g_strcasecmp(maple_device_classes[i]->name, name ) == 0 )
    43 	    return maple_device_classes[i]->new_device();
    44     }
    45     return NULL;
    46 }
    48 dreamcast_config_entry_t maple_get_device_config( maple_device_t dev )
    49 {
    50     if( dev->get_config == NULL )
    51 	return NULL;
    52     return dev->get_config(dev);
    53 }
    55 /**
    56  * Input data looks like this:
    57  *    0: transfer control word
    58  *      0: length of data in words (not including 3 word header)
    59  *      1: low bit = lightgun mode
    60  *      2: low 2 bits = port # (0..3)
    61  *      3: 0x80 = last packet, 0x00 = normal packet
    62  *    4: output buffer address
    63  *    8: Command word
    64  *      8: command code
    65  *      9: destination address
    66  *     10: source address
    67  *     11: length of data in words (not including 3 word header)
    68  *   12: command-specific data
    69  */
    71 /**
    72  * array is [port][subperipheral], so [0][0] is main peripheral on port A,
    73  * [1][2] is the second subperipheral on port B and so on.
    74  */
    75 maple_device_t maple_devices[4][6];
    76 int maple_periph_mask[4];
    77 #define GETBYTE(n) ((uint32_t)(buf[n]))
    78 #define GETWORD(n) (*((uint32_t *)(buf+(n))))
    79 #define PUTBYTE(n,x) (buf[n] = (char)x)
    80 #define PUTWORD(n,x) (*((uint32_t *)(return_buf+(n))) = (x))
    82 maple_device_t maple_get_device( unsigned int port, unsigned int periph ) {
    83     if( port >= 4 )
    84 	return NULL;
    85     if( periph >= 6 )
    86 	return NULL;
    87     return maple_devices[port][periph];
    88 }
    90 void maple_handle_buffer( uint32_t address ) {
    91     unsigned char *buf = (unsigned char *)mem_get_region(address);
    92     if( buf == NULL ) {
    93         ERROR( "Invalid or unmapped buffer passed to maple (0x%08X)", address );
    94     } else {
    95         unsigned int last = 0;
    96         int i = 0, count;
    97         for( count=0; !last; count++ ) {
    98             unsigned int port, length, gun, periph, periph_id, out_length;
    99             unsigned int cmd, recv_addr, send_addr;
   100             uint32_t return_addr;
   101             unsigned char *return_buf;
   103             last = GETBYTE(3) & 0x80; /* indicates last packet */
   104             port = GETBYTE(2) & 0x03;
   105             gun = GETBYTE(1) & 0x01;
   106             length = GETBYTE(0) & 0xFF;
   107             return_addr = GETWORD(4);
   108             if( return_addr == 0 ) {
   109                 /* ERROR */
   110             }
   111             return_buf = mem_get_region(return_addr);
   112             cmd = GETBYTE(8);
   113             recv_addr = GETBYTE(9);
   114             send_addr = GETBYTE(10);
   115             /* Sanity checks */
   116             if( GETBYTE(11) != length ||
   117                 send_addr != (port<<6) ||
   118                 recv_addr >> 6 != port ||
   119                 return_buf == NULL ) {
   120                 /* ERROR */
   121             }
   122             periph = 0;
   123             periph_id = recv_addr & 0x3F;
   124             if( periph_id != 0x20 ) {
   125                 for( i=0;i<5;i++ ) {
   126                     if( periph_id == (1<<i) ) {
   127                         periph = i+1;
   128                         break;
   129                     }
   130                 }
   131                 if( periph == 0 ) { /* Bad setting */
   132                     /* ERROR */
   133                 }
   134             }
   136             INFO( "Maple packet %d: Cmd %d on port %d device %d", count, cmd, port, periph );
   137             maple_device_t dev = maple_devices[port][periph];
   138             if( dev == NULL ) {
   139                 /* no device attached */
   140                 *((uint32_t *)return_buf) = -1;
   141             } else {
   142                 int status, func, block;
   143                 out_length = 0;
   144                 switch( cmd ) {
   145                     case MAPLE_CMD_INFO:
   146                         status = MAPLE_RESP_INFO;
   147                         memcpy( return_buf+4, dev->ident, 112 );
   148                         out_length = 0x1C;
   149                         break;
   150                     case MAPLE_CMD_EXT_INFO:
   151                         status = MAPLE_RESP_EXT_INFO;
   152                         memcpy( return_buf+4, dev->ident, 192 );
   153                         out_length = 0x30;
   154                         break;
   155                     case MAPLE_CMD_RESET:
   156                         if( dev->reset == NULL )
   157                             status = MAPLE_RESP_ACK;
   158                         else status = dev->reset(dev);
   159                         break;
   160                     case MAPLE_CMD_SHUTDOWN:
   161                         if( dev->shutdown == NULL )
   162                             status = MAPLE_RESP_ACK;
   163                         else status = dev->shutdown(dev);
   164                         break;
   165                     case MAPLE_CMD_GET_COND:
   166                         func = GETWORD(12);
   167                         if( dev->get_condition == NULL )
   168                             status = MAPLE_ERR_CMD_UNKNOWN;
   169                         else status = dev->get_condition(dev, func,
   170                                                          return_buf+8,
   171                                                          &out_length );
   172 			out_length++;
   173                         if( status == 0 ) {
   174                             status = MAPLE_RESP_DATA;
   175                             PUTWORD(4,func);
   176                         }
   177                         break;
   178                     case MAPLE_CMD_SET_COND:
   179                         func = GETWORD(12);
   180                         if( dev->set_condition == NULL )
   181                             status = MAPLE_ERR_CMD_UNKNOWN;
   182                         else status = dev->set_condition(dev, func,
   183                                                          buf+16,
   184                                                          length);
   185                         if( status == 0 )
   186                             status = MAPLE_RESP_ACK;
   187                         break;
   188                     case MAPLE_CMD_READ_BLOCK:
   189                         func = GETWORD(12);
   190                         block = GETWORD(16);
   191                         if( dev->read_block == NULL )
   192                             status = MAPLE_ERR_CMD_UNKNOWN;
   193                         else status = dev->read_block(dev, func, block,
   194                                                       return_buf+12,
   195                                                       &out_length );
   196                         if( status == 0 ) {
   197                             status = MAPLE_RESP_DATA;
   198                             PUTWORD(4,func);
   199                             PUTWORD(8,block);
   200                         }
   201                         break;
   202                     case MAPLE_CMD_WRITE_BLOCK:
   203                         func = GETWORD(12);
   204                         block = GETWORD(16);
   205                         if( dev->write_block == NULL )
   206                             status = MAPLE_ERR_CMD_UNKNOWN;
   207                         else {
   208                             status = dev->write_block(dev, func, block, 
   209                                                       buf+20, length);
   210                             if( status == 0 )
   211                                 status = MAPLE_RESP_ACK;
   212                         }
   213                         break;
   214                     default:
   215                         status = MAPLE_ERR_CMD_UNKNOWN;
   216                 }
   217                 return_buf[0] = status;
   218                 return_buf[1] = send_addr;
   219                 return_buf[2] = recv_addr;
   220                 if( periph == 0 )
   221                     return_buf[2] |= maple_periph_mask[port];
   222                 return_buf[3] = out_length;
   223             }
   224             buf += 12 + (length<<2);
   225         }
   226         asic_event( EVENT_MAPLE_DMA );
   227     }
   228 }
   230 void maple_attach_device( maple_device_t dev, unsigned int port,
   231                           unsigned int periph ) {
   232     assert( port < 4 );
   233     assert( periph < 6 );
   235     if( maple_devices[port][periph] != NULL ) {
   236         /* Detach existing peripheral first */
   237         maple_detach_device( port, periph );
   238     }
   240     maple_devices[port][periph] = dev;
   241     if( periph != 0 )
   242         maple_periph_mask[port] |= (1<<(periph-1));
   243     else maple_periph_mask[port] |= 0x20;
   244     if( dev->attach != NULL ) {
   245         dev->attach( dev );
   246     }
   247 }
   249 void maple_detach_device( unsigned int port, unsigned int periph ) {
   250     assert( port < 4 );
   251     assert( periph < 6 );
   253     maple_device_t dev = maple_devices[port][periph];
   254     if( dev == NULL ) /* already detached */
   255         return;
   256     maple_devices[port][periph] = NULL;
   257     if( dev->detach != NULL ) {
   258         dev->detach(dev);
   259     }
   260     if( periph == 0 ) {
   261         /* If we detach the main peripheral, we also have to detach all the
   262          * subperipherals, or the system could get quite confused
   263          */
   264         int i;
   265         maple_periph_mask[port] = 0;
   266         for( i=1; i<6; i++ ) {
   267             maple_detach_device(port,i);
   268         }
   269     } else {
   270         maple_periph_mask[port] &= (~(1<<(periph-1)));
   271     }
   273 }
   275 void maple_detach_all() {
   276     int i, j;
   277     for( i=0; i<4; i++ ) {
   278 	for( j=0; j<6; j++ ) {
   279 	    if( maple_devices[i][j] != NULL ) {
   280 		maple_device_t dev = maple_devices[i][j];
   281 		if( dev->detach != NULL )
   282 		    dev->detach(dev);
   283 		if( dev->destroy != NULL )
   284 		    dev->destroy(dev);
   285 	    }
   286 	}
   287 	maple_periph_mask[i] = 0;
   288     }
   289 }
   291 void maple_reattach_all() {
   292     int i, j;
   293     for( i=0; i<4; i++ ) {
   294 	for( j=0; j<6; j++ ) {
   295 	    if( maple_devices[i][j] != NULL ) {
   296 		maple_device_t dev = maple_devices[i][j];
   297 		if( dev->attach != NULL )
   298 		    dev->attach(dev);
   299 	    }
   300 	}
   301     }
   302 }
.