Search
lxdream.org :: lxdream/src/maple/vmu.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/maple/vmu.c
changeset 1034:7044e01148f0
next1035:e3093fd7d1da
author nkeynes
date Wed Jun 24 02:41:12 2009 +0000 (13 years ago)
permissions -rw-r--r--
last change Add initial VMU support
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/maple/vmu.c Wed Jun 24 02:41:12 2009 +0000
1.3 @@ -0,0 +1,241 @@
1.4 +/**
1.5 + * $Id: vmu.c 858 2008-09-02 03:34:00Z nkeynes $
1.6 + *
1.7 + * Implementation of the SEGA VMU device
1.8 + * Part No. HKT-7000
1.9 + *
1.10 + * The standard VMU implements 3 functions - Clock, LCD, and memory card,
1.11 + * in addition to having it's own little CPU, buttons, etc. The CPU isn't
1.12 + * implemented just yet.
1.13 + *
1.14 + * Copyright (c) 2009 Nathan Keynes.
1.15 + *
1.16 + * This program is free software; you can redistribute it and/or modify
1.17 + * it under the terms of the GNU General Public License as published by
1.18 + * the Free Software Foundation; either version 2 of the License, or
1.19 + * (at your option) any later version.
1.20 + *
1.21 + * This program is distributed in the hope that it will be useful,
1.22 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.23 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.24 + * GNU General Public License for more details.
1.25 + */
1.26 +
1.27 +#include <assert.h>
1.28 +#include <stdlib.h>
1.29 +#include <stdio.h>
1.30 +#include <string.h>
1.31 +#include <errno.h>
1.32 +#include <sys/mman.h>
1.33 +#include <fcntl.h>
1.34 +#include "display.h"
1.35 +#include "maple/maple.h"
1.36 +#include "vmu/vmuvol.h"
1.37 +#include "vmu/vmulist.h"
1.38 +
1.39 +#define VMU_LCD_SIZE (48*4)
1.40 +#define VMU_BLOCK_COUNT 256
1.41 +#define VMU_BLOCK_SIZE 512
1.42 +#define VMU_PHASE_SIZE 128
1.43 +#define VMU_CONFIG_ENTRIES 1
1.44 +
1.45 +#define VMU_IDENT { 0x00, 0x00, 0x00, 0x0E, 0x7E, 0x7E, 0x3F, 0x40, 0x00, 0x05, 0x10, 0x00, \
1.46 + 0x00, 0x0F, 0x41, 0x00, 0xFF, 0x00, 0x56, 0x69, 0x73, 0x75, 0x61, 0x6C, 0x20, 0x4D, 0x65, 0x6D, \
1.47 + 0x6F, 0x72, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, \
1.48 + 0x20, 0x20, 0x20, 0x20, 0x50, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x42, 0x79, 0x20, \
1.49 + 0x6F, 0x72, 0x20, 0x55, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x4C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, \
1.50 + 0x20, 0x46, 0x72, 0x6F, 0x6D, 0x20, 0x53, 0x45, 0x47, 0x41, 0x20, 0x45, 0x4E, 0x54, 0x45, 0x52, \
1.51 + 0x50, 0x52, 0x49, 0x53, 0x45, 0x53, 0x2C, 0x4C, 0x54, 0x44, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, \
1.52 + 0x7C, 0x00, 0x82, 0x00 }
1.53 +#define VMU_VERSION { 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x31, 0x2E, 0x30, 0x30, \
1.54 + 0x35, 0x2C, 0x31, 0x39, 0x39, 0x39, 0x2F, 0x30, 0x34, 0x2F, 0x31, 0x35, 0x2C, 0x33, 0x31, 0x35, \
1.55 + 0x2D, 0x36, 0x32, 0x30, 0x38, 0x2D, 0x30, 0x33, 0x2C, 0x53, 0x45, 0x47, 0x41, 0x20, 0x56, 0x69, \
1.56 + 0x73, 0x75, 0x61, 0x6C, 0x20, 0x4D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x20, 0x53, 0x79, 0x73, 0x74, \
1.57 + 0x65, 0x6D, 0x20, 0x42, 0x49, 0x4F, 0x53, 0x20, 0x50, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x65, 0x64, \
1.58 + 0x20, 0x62, 0x79, 0x20 }
1.59 +
1.60 +static void vmu_destroy( maple_device_t dev );
1.61 +static maple_device_t vmu_clone( maple_device_t dev );
1.62 +static maple_device_t vmu_new();
1.63 +static lxdream_config_entry_t vmu_get_config( maple_device_t dev );
1.64 +static void vmu_set_config_value( maple_device_t dev, unsigned int key, const gchar *value );
1.65 +static int vmu_get_condition( maple_device_t dev, int function, unsigned char *outbuf,
1.66 + unsigned int *outlen );
1.67 +static int vmu_get_meminfo( maple_device_t dev, int function, unsigned int pt,
1.68 + unsigned char *outbuf, unsigned int *outlen );
1.69 +static void vmu_attach(struct maple_device *dev);
1.70 +static void vmu_detach(struct maple_device *dev);
1.71 +static int vmu_read_block(struct maple_device *dev, int function, unsigned int pt,
1.72 + uint32_t block, unsigned int phase,
1.73 + unsigned char *outbuf, unsigned int *buflen);
1.74 +static int vmu_write_block(struct maple_device *dev, int function, unsigned int pt,
1.75 + uint32_t block, unsigned int phase,
1.76 + unsigned char *inbuf, unsigned int buflen);
1.77 +
1.78 +typedef struct vmu_device {
1.79 + struct maple_device dev;
1.80 + vmu_volume_t vol;
1.81 + char lcd_bitmap[VMU_LCD_SIZE]; /* 48x32 bitmap */
1.82 + struct lxdream_config_entry config[VMU_CONFIG_ENTRIES+1];
1.83 +} *vmu_device_t;
1.84 +
1.85 +struct maple_device_class vmu_class = { "Sega VMU", MAPLE_GRAB_DONTCARE, vmu_new };
1.86 +
1.87 +static struct vmu_device base_vmu = {
1.88 + { MAPLE_DEVICE_TAG, &vmu_class,
1.89 + VMU_IDENT, VMU_VERSION,
1.90 + vmu_get_config, vmu_set_config_value,
1.91 + vmu_attach, vmu_detach, vmu_destroy,
1.92 + vmu_clone, NULL, NULL, vmu_get_condition, NULL,
1.93 + vmu_get_meminfo, vmu_read_block, vmu_write_block, NULL, NULL },
1.94 + NULL, {0},
1.95 + {{ "volume", N_("Volume"), CONFIG_TYPE_FILE },
1.96 + { NULL, CONFIG_TYPE_NONE }} };
1.97 +
1.98 +static maple_device_t vmu_new( )
1.99 +{
1.100 + vmu_device_t dev = malloc( sizeof(struct vmu_device) );
1.101 + memcpy( dev, &base_vmu, sizeof(base_vmu) );
1.102 + return MAPLE_DEVICE(dev);
1.103 +}
1.104 +
1.105 +static maple_device_t vmu_clone( maple_device_t srcdevice )
1.106 +{
1.107 + vmu_device_t src = (vmu_device_t)srcdevice;
1.108 + vmu_device_t dev = (vmu_device_t)vmu_new();
1.109 + lxdream_copy_config_list( dev->config, src->config );
1.110 + return MAPLE_DEVICE(dev);
1.111 +}
1.112 +
1.113 +static lxdream_config_entry_t vmu_get_config( maple_device_t mdev )
1.114 +{
1.115 + vmu_device_t dev = (vmu_device_t)mdev;
1.116 + return dev->config;
1.117 +}
1.118 +
1.119 +static void vmu_set_config_value( maple_device_t dev, unsigned int key, const gchar *value )
1.120 +{
1.121 + vmu_device_t vmu = (vmu_device_t)dev;
1.122 + assert( key < VMU_CONFIG_ENTRIES );
1.123 +
1.124 + if( value == vmu->config[key].value ||
1.125 + value != NULL && vmu->config[key].value != NULL && strcmp(vmu->config[key].value, value) == 0 ) {
1.126 + return; /* Unchanged */
1.127 + }
1.128 +
1.129 + if( vmu->vol != NULL ) {
1.130 + vmulist_detach_vmu(vmu->vol);
1.131 + }
1.132 + lxdream_set_config_value( &vmu->config[key], value );
1.133 + vmu->vol = vmulist_get_vmu_by_filename( value );
1.134 + if( vmu->vol != NULL ) {
1.135 + vmulist_attach_vmu(vmu->vol, "MAPLE");
1.136 + }
1.137 +}
1.138 +
1.139 +void vmu_attach(struct maple_device *dev)
1.140 +{
1.141 + vmu_device_t vmu = (vmu_device_t)dev;
1.142 + if( vmu->config[0].value != NULL ) {
1.143 + vmu->vol = vmulist_get_vmu_by_filename(vmu->config[0].value);
1.144 + if( vmu->vol != NULL ) {
1.145 + vmulist_attach_vmu(vmu->vol, "MAPLE");
1.146 + }
1.147 + }
1.148 +}
1.149 +
1.150 +static void vmu_detach(struct maple_device *dev)
1.151 +{
1.152 + vmu_device_t vmu = (vmu_device_t)dev;
1.153 + if( vmu->vol != NULL ) {
1.154 + vmulist_detach_vmu(vmu->vol);
1.155 + vmu->vol = NULL;
1.156 + }
1.157 +}
1.158 +
1.159 +static void vmu_destroy( maple_device_t dev )
1.160 +{
1.161 + vmu_device_t vmu = (vmu_device_t)dev;
1.162 + free( dev );
1.163 +}
1.164 +
1.165 +static int vmu_get_condition(struct maple_device *dev, int function,
1.166 + unsigned char *outbuf, unsigned int *buflen)
1.167 +{
1.168 +}
1.169 +static int vmu_set_condition(struct maple_device *dev, int function,
1.170 + unsigned char *inbuf, unsigned int buflen)
1.171 +{
1.172 + return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
1.173 +}
1.174 +
1.175 +static int vmu_get_meminfo(struct maple_device *dev, int function, unsigned int pt,
1.176 + unsigned char *outbuf, unsigned int *buflen)
1.177 +{
1.178 + struct vmu_device *vmu = (struct vmu_device *)dev;
1.179 + switch(function) {
1.180 + case MAPLE_FUNC_MEMORY:
1.181 + if( vmu->vol != NULL ) {
1.182 + const struct vmu_volume_metadata *md = vmu_volume_get_metadata( vmu->vol, pt );
1.183 + memcpy( outbuf, md, sizeof(struct vmu_volume_metadata) );
1.184 + *buflen = sizeof(struct vmu_volume_metadata);
1.185 + return 0;
1.186 + } // Else fallthrough
1.187 + case MAPLE_FUNC_LCD:
1.188 + case MAPLE_FUNC_CLOCK:
1.189 + return MAPLE_ERR_NO_RESPONSE;
1.190 + default:
1.191 + return MAPLE_ERR_FUNC_UNSUP;
1.192 + }
1.193 +
1.194 +}
1.195 +static int vmu_read_block(struct maple_device *dev, int function, unsigned int pt,
1.196 + uint32_t block, unsigned int phase,
1.197 + unsigned char *outbuf, unsigned int *buflen)
1.198 +{
1.199 + struct vmu_device *vmu = (struct vmu_device *)dev;
1.200 + switch( function ) {
1.201 + case MAPLE_FUNC_LCD:
1.202 + if( pt == 0 && block == 0 ) {
1.203 + *buflen = VMU_LCD_SIZE/4;
1.204 + memcpy( outbuf, vmu->lcd_bitmap, VMU_LCD_SIZE/4 );
1.205 + }
1.206 + return 0;
1.207 + break;
1.208 + case MAPLE_FUNC_MEMORY:
1.209 + if( vmu->vol != NULL ) {
1.210 + vmu_volume_read_block( vmu->vol, pt, block, outbuf );
1.211 + return 0;
1.212 + }
1.213 + // Else fallthrough for now
1.214 + case MAPLE_FUNC_CLOCK:
1.215 + return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
1.216 + default:
1.217 + return MAPLE_ERR_FUNC_UNSUP;
1.218 + }
1.219 +}
1.220 +
1.221 +static int vmu_write_block(struct maple_device *dev, int function, unsigned int pt,
1.222 + uint32_t block, unsigned int phase,
1.223 + unsigned char *inbuf, unsigned int buflen)
1.224 +{
1.225 + struct vmu_device *vmu = (struct vmu_device *)dev;
1.226 + switch( function ) {
1.227 + case MAPLE_FUNC_LCD:
1.228 + if( pt == 0 && block == 0 && buflen == (VMU_LCD_SIZE/4) ) {
1.229 + memcpy( vmu->lcd_bitmap, inbuf, VMU_LCD_SIZE );
1.230 + }
1.231 + return 0;
1.232 + break;
1.233 + case MAPLE_FUNC_MEMORY:
1.234 + if( vmu->vol != NULL && buflen == (VMU_PHASE_SIZE/4) ) {
1.235 + vmu_volume_write_phase( vmu->vol, pt, block, phase, inbuf );
1.236 + return 0;
1.237 + }
1.238 + // Else fallthrough for now
1.239 + case MAPLE_FUNC_CLOCK:
1.240 + return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
1.241 + default:
1.242 + return MAPLE_ERR_FUNC_UNSUP;
1.243 + }
1.244 +}
.