| 1 | /* |
| 2 | GP2X minimal library v0.A by rlyeh, 2005. emulnation.info@rlyeh (swap it!) |
| 3 | |
| 4 | + GP2X 920t/940t CPUs library with a FIFO message system. |
| 5 | + GP2X video library with double buffering. |
| 6 | + GP2X sound library with double buffering. |
| 7 | + GP2X blitter library. |
| 8 | + GP2X timer library. |
| 9 | + GP2X joystick library. |
| 10 | |
| 11 | Thanks to Squidge, Robster, snaff, Reesy and NK, for the help & previous work! :-) |
| 12 | |
| 13 | |
| 14 | License |
| 15 | ======= |
| 16 | |
| 17 | Free for non-commercial projects (it would be nice receiving a mail from you). |
| 18 | Other cases, ask me first. |
| 19 | |
| 20 | GamePark Holdings is not allowed to use this library and/or use parts from it. |
| 21 | |
| 22 | |
| 23 | Known projects using the library or parts from it |
| 24 | ================================================= |
| 25 | |
| 26 | REminiscence-0.1.8 (rlyeh) |
| 27 | Atari800 GP2X pre-release 3 (foft) |
| 28 | XUMP (kedo) |
| 29 | MAME2X (Franxis) |
| 30 | DrMD for GP2X (Reesy) |
| 31 | |
| 32 | |
| 33 | What's new |
| 34 | ========== |
| 35 | |
| 36 | 0.A: 940t disabled all time unless required |
| 37 | sound is paused by default now, use gp2x_sound_pause() to unlock it |
| 38 | |
| 39 | fixed functions: |
| 40 | - gp2x_sound_play() ; increased the number of sampling buffers |
| 41 | - gp2x_timer_read() ; it should work again. broken at some point before |
| 42 | - gp2x_dualcore_launch_program_from_disk() ; it missed the code uploading call |
| 43 | |
| 44 | added functions: |
| 45 | - gp2x_sound_pause() |
| 46 | - gp2x_timer_delay() |
| 47 | - gp2x_dualcore_pause() |
| 48 | |
| 49 | 0.9: initial FIFO message system for dual cpu cores. |
| 50 | initial 48 Mb support. |
| 51 | initial quadruple buffering in 8bbp mode. |
| 52 | |
| 53 | added functions: |
| 54 | - gp2x_dualcore_exec() ; initial FIFO message system for dual cpu cores. |
| 55 | - gp2x_dualcore_sync() ; initial FIFO message system for dual cpu cores. |
| 56 | |
| 57 | improved functions: |
| 58 | - gp2x_video_flip() ; initial quadruple buffering in 8bbp mode. |
| 59 | |
| 60 | 0.8: initial dual cores cpu support. |
| 61 | very basic blit functions by popular demand ;-) |
| 62 | vsync & hsync waiting code (thanks Reesy) |
| 63 | |
| 64 | added functions: |
| 65 | - gp2x_launch_program() ; initial dual cores cpu support. |
| 66 | - gp2x_launch_program_from_disk() ; initial dual cores cpu support. |
| 67 | - gp2x_launch_subprogram() ; initial dual cores cpu support. |
| 68 | - gp2x_blitter_rect15() ; very basic blit function by popular demand ;-) |
| 69 | - gp2x_blitter_rect8() ; very basic blit function by popular demand ;-) |
| 70 | - gp2x_video_hsync() ; hsync waiting code (thanks Reesy) |
| 71 | - gp2x_video_vsync() ; vsync waiting code (thanks Reesy) |
| 72 | |
| 73 | fixed functions: |
| 74 | - gp2x_video_color8() ; bugfixed a stupid typo (thanks Franxis for the bug report) |
| 75 | |
| 76 | 0.7: added functions: |
| 77 | - gp2x_sound_volume() |
| 78 | |
| 79 | fixed functions: |
| 80 | - gp2x_deinit() ; fixed menu launch code when exiting. |
| 81 | |
| 82 | improved functions: |
| 83 | - gp2x_timer_read() ; rewritten timer. it should be more accurate now. |
| 84 | - gp2x_init() ; faster init code. |
| 85 | |
| 86 | 0.6: added functions: |
| 87 | - gp2x_timer_read() |
| 88 | - gp2x_sound_pause() |
| 89 | |
| 90 | fixed functions: |
| 91 | - gp2x_video_setpalette() ; palette handling was incorrect. fixed. |
| 92 | |
| 93 | 0.5: improved functions: |
| 94 | - gp2x_init() ; better and cleaner initalizing code. |
| 95 | - gp2x_init() ; sound patched for real stereo output (by using NK's solution) |
| 96 | |
| 97 | 0.4: lots of cleanups. |
| 98 | sound is threaded and double buffered now. |
| 99 | 8 bpp video support. |
| 100 | |
| 101 | fixed functions: |
| 102 | - gp2x_deinit() ; better and cleaner exiting code. |
| 103 | |
| 104 | 0.3: shorter library. |
| 105 | |
| 106 | fixed functions: |
| 107 | - gp2x_joystick_read() ; improved joystick diagonal detection. |
| 108 | |
| 109 | 0.2: better code layout. |
| 110 | public release. |
| 111 | |
| 112 | 0.1: beta release. |
| 113 | */ |
| 114 | |
| 115 | #include "minimal.h" |
| 116 | #include "squidgehack.h" |
| 117 | #include "asmutils.h" |
| 118 | |
| 119 | unsigned char *gp2x_screen8 ,*gp2x_upperRAM; |
| 120 | unsigned long gp2x_dev[8]={0,0,0,0,0,0,0,0}, gp2x_physvram[8], *gp2x_memregl, gp2x_volume, gp2x_ticks_per_second; |
| 121 | volatile unsigned long gp2x_sound_pausei=1, gp2x_ticks=0, gp2x_sound=0, *gp2x_dualcore_ram=0; |
| 122 | unsigned short *gp2x_memregs, *gp2x_screen15, *gp2x_logvram15[4], gp2x_sound_buffer[4+((44100/25)*2)*8]; //25 Hz gives our biggest supported sampling buffer |
| 123 | volatile unsigned short gp2x_palette[512]; |
| 124 | |
| 125 | extern void gp2x_sound_frame(void *blah, void *buff, int samples); |
| 126 | |
| 127 | // hack |
| 128 | static int scaling_enabled = 0; |
| 129 | |
| 130 | void gp2x_video_flip(void) |
| 131 | { |
| 132 | unsigned long address=gp2x_physvram[gp2x_physvram[7]]; |
| 133 | if (scaling_enabled) address += 32; |
| 134 | |
| 135 | // since we are using the mmu hack, we must flush the cache first |
| 136 | // (the params are most likely wrong, but they seem to work somehow) |
| 137 | flushcache(address, address + 320*240, 0); |
| 138 | |
| 139 | if(++gp2x_physvram[7]==4) gp2x_physvram[7]=0; |
| 140 | gp2x_screen15=gp2x_logvram15[gp2x_physvram[7]]; |
| 141 | gp2x_screen8=(unsigned char *)gp2x_screen15; |
| 142 | |
| 143 | gp2x_memregs[0x290E>>1]=(unsigned short)(address & 0xFFFF); |
| 144 | gp2x_memregs[0x2910>>1]=(unsigned short)(address >> 16); |
| 145 | gp2x_memregs[0x2912>>1]=(unsigned short)(address & 0xFFFF); |
| 146 | gp2x_memregs[0x2914>>1]=(unsigned short)(address >> 16); |
| 147 | } |
| 148 | |
| 149 | void gp2x_video_flip_single(void) |
| 150 | { |
| 151 | unsigned long address=gp2x_physvram[0]; |
| 152 | |
| 153 | gp2x_screen15=gp2x_logvram15[0]; |
| 154 | gp2x_screen8=(unsigned char *)gp2x_screen15; |
| 155 | |
| 156 | gp2x_memregs[0x290E>>1]=(unsigned short)(address & 0xFFFF); |
| 157 | gp2x_memregs[0x2910>>1]=(unsigned short)(address >> 16); |
| 158 | gp2x_memregs[0x2912>>1]=(unsigned short)(address & 0xFFFF); |
| 159 | gp2x_memregs[0x2914>>1]=(unsigned short)(address >> 16); |
| 160 | } |
| 161 | |
| 162 | |
| 163 | void gp2x_video_setgamma(unsigned short gamma) /*0..255*/ |
| 164 | { |
| 165 | int i=256*3; |
| 166 | gp2x_memregs[0x295C>>1]=0; |
| 167 | while(i--) gp2x_memregs[0x295E>>1]=gamma; |
| 168 | } |
| 169 | |
| 170 | void gp2x_video_setpalette(void) |
| 171 | { |
| 172 | unsigned short *g=(unsigned short *)gp2x_palette; int i=512; |
| 173 | gp2x_memregs[0x2958>>1]=0; |
| 174 | while(i--) gp2x_memregs[0x295A>>1]=*g++; |
| 175 | } |
| 176 | |
| 177 | void gp2x_blitter_rect15(gp2x_rect *r) |
| 178 | { |
| 179 | int x, y; unsigned short *data=r->data15, *offset=&gp2x_screen15[r->x+r->y*320]; |
| 180 | |
| 181 | y=r->h; if(r->solid) |
| 182 | while(y--) { x=r->w; while(x--) *offset++=*data++; offset+=320-x; } |
| 183 | else |
| 184 | while(y--) { x=r->w; while(x--) { if(*data) *offset=*data; offset++, data++; } |
| 185 | offset+=320-x; } |
| 186 | } |
| 187 | |
| 188 | void gp2x_blitter_rect8(gp2x_rect *r) |
| 189 | { |
| 190 | int x, y; unsigned char *data=r->data8, *offset=&gp2x_screen8[r->x+r->y*320]; |
| 191 | |
| 192 | y=r->h; if(r->solid) |
| 193 | while(y--) { x=r->w; while(x--) *offset++=*data++; offset+=320-x; } |
| 194 | else |
| 195 | while(y--) { x=r->w; while(x--) { if(*data) *offset=*data; offset++, data++; } |
| 196 | offset+=320-x; } |
| 197 | } |
| 198 | |
| 199 | unsigned long gp2x_joystick_read(void) |
| 200 | { |
| 201 | unsigned long value=(gp2x_memregs[0x1198>>1] & 0x00FF); |
| 202 | |
| 203 | if(value==0xFD) value=0xFA; |
| 204 | if(value==0xF7) value=0xEB; |
| 205 | if(value==0xDF) value=0xAF; |
| 206 | if(value==0x7F) value=0xBE; |
| 207 | |
| 208 | return ~((gp2x_memregs[0x1184>>1] & 0xFF00) | value | (gp2x_memregs[0x1186>>1] << 16)); |
| 209 | } |
| 210 | |
| 211 | void gp2x_sound_volume(int l, int r) |
| 212 | { |
| 213 | l=(((l*0x50)/100)<<8)|((r*0x50)/100); //0x5A, 0x60 |
| 214 | ioctl(gp2x_dev[4], SOUND_MIXER_WRITE_PCM, &l); //SOUND_MIXER_WRITE_VOLUME |
| 215 | } |
| 216 | |
| 217 | void gp2x_timer_delay(unsigned long ticks) |
| 218 | { |
| 219 | unsigned long target=gp2x_memregl[0x0A00>>2]+ticks*gp2x_ticks_per_second; |
| 220 | while(gp2x_memregl[0x0A00>>2]<target); |
| 221 | } |
| 222 | |
| 223 | unsigned long gp2x_timer_read(void) |
| 224 | { |
| 225 | return gp2x_memregl[0x0A00>>2]/gp2x_ticks_per_second; |
| 226 | } |
| 227 | |
| 228 | unsigned long gp2x_timer_read_ms(void) |
| 229 | { |
| 230 | return gp2x_memregl[0x0A00>>2]; |
| 231 | } |
| 232 | |
| 233 | |
| 234 | void gp2x_sound_pause(int yes) { gp2x_sound_pausei=yes; } |
| 235 | |
| 236 | #if 0 |
| 237 | static void *gp2x_sound_play(void *blah) |
| 238 | { |
| 239 | int flip=0, flyp=gp2x_sound_buffer[1]; |
| 240 | struct timespec ts; ts.tv_sec=0, ts.tv_nsec=gp2x_sound_buffer[2]; |
| 241 | |
| 242 | while(!gp2x_sound) |
| 243 | { |
| 244 | nanosleep(&ts, NULL); |
| 245 | |
| 246 | |
| 247 | if(!gp2x_sound_pausei) |
| 248 | { |
| 249 | // [1] is sound buffer size at 22050, 16, stereo, it is 1468 (367*4) |
| 250 | // [0] number of bytes?, at 22050,16,stereo, it is 367 |
| 251 | // first half of buffer |
| 252 | |
| 253 | // first one is 368 |
| 254 | |
| 255 | |
| 256 | gp2x_sound_frame(blah, (void *)(&gp2x_sound_buffer[4+flip]), gp2x_sound_buffer[0]); |
| 257 | // write out to second half of buffer |
| 258 | write(gp2x_dev[3], (void *)(&gp2x_sound_buffer[4+flyp]), gp2x_sound_buffer[1]); |
| 259 | |
| 260 | flip+=gp2x_sound_buffer[1]; |
| 261 | if(flip==gp2x_sound_buffer[1]*8) flip=0; |
| 262 | flyp+=gp2x_sound_buffer[1]; |
| 263 | if(flyp==gp2x_sound_buffer[1]*8) flyp=0; |
| 264 | } |
| 265 | } |
| 266 | return NULL; |
| 267 | } |
| 268 | #endif |
| 269 | |
| 270 | #if 0 |
| 271 | static void gp2x_initqueue(gp2x_queue *q, unsigned long queue_items, unsigned long *position920t, unsigned long *position940t) |
| 272 | { |
| 273 | q->head = q->tail = q->items = 0; |
| 274 | q->max_items = queue_items; |
| 275 | if(position920t) q->place920t=position920t; else q->place920t=(unsigned long *)malloc(sizeof(unsigned long) * queue_items); |
| 276 | if(position940t) q->place940t=position940t; |
| 277 | memset(q->place920t, 0, sizeof(unsigned long) * queue_items); |
| 278 | } |
| 279 | |
| 280 | static void gp2x_enqueue(gp2x_queue *q, unsigned long data) |
| 281 | { |
| 282 | while(q->items==q->max_items); /*waiting for tail to decrease...*/ |
| 283 | q->place920t[q->head = (q->head < q->max_items ? q->head+1 : 0)] = data; |
| 284 | q->items++; |
| 285 | } |
| 286 | |
| 287 | /* UNUSED |
| 288 | static unsigned long gp2x_dequeue(gp2x_queue *q) |
| 289 | { |
| 290 | while(!q->items); //waiting for head to increase... |
| 291 | q->items--; |
| 292 | return q->place920t[q->tail = (q->tail < q->max_items ? q->tail+1 : 0)]; |
| 293 | } */ |
| 294 | #endif |
| 295 | |
| 296 | void gp2x_dualcore_pause(int yes) { if(yes) gp2x_memregs[0x0904>>1] &= 0xFFFE; else gp2x_memregs[0x0904>>1] |= 1; } |
| 297 | static void gp2x_940t_reset(int yes) { gp2x_memregs[0x3B48>>1] = ((yes&1) << 7) | (0x03); } |
| 298 | static void gp2x_940t_pause(int yes) { gp2x_dualcore_pause(yes); } |
| 299 | |
| 300 | static void gp2x_dualcore_registers(int save) |
| 301 | { |
| 302 | static unsigned short regs[8]; |
| 303 | |
| 304 | if(save) |
| 305 | { |
| 306 | regs[0]=gp2x_memregs[0x0904>>1]; regs[1]=gp2x_memregs[0x0912>>1]; |
| 307 | regs[2]=gp2x_memregs[0x091c>>1]; regs[3]=gp2x_memregs[0x3b40>>1]; |
| 308 | regs[4]=gp2x_memregs[0x3b42>>1]; regs[5]=gp2x_memregs[0x3b48>>1]; |
| 309 | regs[6]=gp2x_memregs[0x3b44>>1]; regs[7]=gp2x_memregs[0x3b46>>1]; |
| 310 | |
| 311 | gp2x_940t_reset(1); |
| 312 | gp2x_940t_pause(1); |
| 313 | } |
| 314 | else |
| 315 | { |
| 316 | gp2x_memregs[0x0904>>1]=regs[0]; gp2x_memregs[0x0912>>1]=regs[1]; |
| 317 | gp2x_memregs[0x091c>>1]=regs[2]; gp2x_memregs[0x3b40>>1]=regs[3]; |
| 318 | gp2x_memregs[0x3b42>>1]=regs[4]; gp2x_memregs[0x3b48>>1]=regs[5]; |
| 319 | gp2x_memregs[0x3b44>>1]=regs[6]; gp2x_memregs[0x3b46>>1]=regs[7]; |
| 320 | } |
| 321 | } |
| 322 | |
| 323 | #if 0 |
| 324 | void gp2x_dualcore_sync(void) |
| 325 | { |
| 326 | gp2x_queue *q=(gp2x_queue *)gp2x_1stcore_data_ptr(GP2X_QUEUE_ARRAY_PTR); |
| 327 | while(q->items); |
| 328 | } |
| 329 | |
| 330 | void gp2x_dualcore_exec(unsigned long command) { gp2x_enqueue((gp2x_queue *)gp2x_1stcore_data_ptr(GP2X_QUEUE_ARRAY_PTR),command); } |
| 331 | |
| 332 | void gp2x_dualcore_launch_program(unsigned long *area, unsigned long size) |
| 333 | { |
| 334 | unsigned long i=0, *arm940t_ram=(unsigned long *)gp2x_dualcore_ram; |
| 335 | |
| 336 | gp2x_940t_reset(1); |
| 337 | |
| 338 | gp2x_memregs[0x3B40>>1] = 0; //disable interrupts |
| 339 | gp2x_memregs[0x3B42>>1] = 0; |
| 340 | gp2x_memregs[0x3B44>>1] = 0xffff; |
| 341 | gp2x_memregs[0x3B46>>1] = 0xffff; |
| 342 | |
| 343 | gp2x_940t_pause(0); |
| 344 | |
| 345 | while(i < size) *arm940t_ram++=area[i++]; |
| 346 | |
| 347 | gp2x_initqueue((gp2x_queue *)gp2x_1stcore_data_ptr(GP2X_QUEUE_ARRAY_PTR), GP2X_QUEUE_MAX_ITEMS, (unsigned long *)gp2x_1stcore_data_ptr(GP2X_QUEUE_DATA_PTR), (unsigned long *)gp2x_2ndcore_data_ptr(GP2X_QUEUE_DATA_PTR)); |
| 348 | |
| 349 | gp2x_940t_reset(0); |
| 350 | } |
| 351 | |
| 352 | void gp2x_dualcore_launch_program_from_disk(const char *file, unsigned long offset, unsigned long size) |
| 353 | { |
| 354 | FILE *in; void *data; |
| 355 | |
| 356 | if((in=fopen(file, "rb"))==NULL) return; |
| 357 | if((data=malloc(size))==NULL) { fclose(in); return; } |
| 358 | fseek(in, 0L, offset); |
| 359 | fread(data, 1, size, in); |
| 360 | gp2x_dualcore_launch_program((unsigned long *)data, size); |
| 361 | free(data); |
| 362 | fclose(in); |
| 363 | } |
| 364 | #endif |
| 365 | |
| 366 | void gp2x_init(int ticks_per_second, int bpp, int rate, int bits, int stereo, int Hz) |
| 367 | { |
| 368 | struct fb_fix_screeninfo fixed_info; |
| 369 | static int first=1; |
| 370 | |
| 371 | // GP2X_DO_SOUND |
| 372 | int gp2x_do_sound=1; |
| 373 | int frag=0; |
| 374 | int channels=1; |
| 375 | int stereoLocal=0; |
| 376 | int ret; |
| 377 | |
| 378 | gp2x_ticks_per_second=7372800/ticks_per_second; |
| 379 | |
| 380 | if(!gp2x_dev[0]) gp2x_dev[0] = open("/dev/fb0", O_RDWR); |
| 381 | if(!gp2x_dev[1]) gp2x_dev[1] = open("/dev/fb1", O_RDWR); |
| 382 | if(!gp2x_dev[2]) gp2x_dev[2] = open("/dev/mem", O_RDWR); |
| 383 | |
| 384 | ioctl(gp2x_dev[gp2x_physvram[7]=0], FBIOGET_FSCREENINFO, &fixed_info); |
| 385 | gp2x_physvram[2]=gp2x_physvram[0]=fixed_info.smem_start; |
| 386 | gp2x_screen15=gp2x_logvram15[2]=gp2x_logvram15[0]= |
| 387 | (unsigned short *)mmap(0, 0x20000*2, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], gp2x_physvram[0]); |
| 388 | gp2x_screen8=(unsigned char *)gp2x_screen15; |
| 389 | printf("/dev/fb0 is @ %08lx / %p\n", gp2x_physvram[0], gp2x_screen15); |
| 390 | |
| 391 | ioctl(gp2x_dev[1], FBIOGET_FSCREENINFO, &fixed_info); |
| 392 | gp2x_physvram[3]=gp2x_physvram[1]=fixed_info.smem_start; |
| 393 | gp2x_logvram15[3]=gp2x_logvram15[1]= |
| 394 | (unsigned short *)mmap(0, 0x20000*2, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], gp2x_physvram[1]); |
| 395 | printf("/dev/fb1 is @ %08lx / %p\n", gp2x_physvram[1], gp2x_logvram15[1]); |
| 396 | |
| 397 | // apply the MMU hack |
| 398 | ret = mmuhack(); |
| 399 | printf("squidge hack code finished and returned %s\n", ret ? "ok" : "fail"); |
| 400 | |
| 401 | // don't run sound right now |
| 402 | if ( gp2x_do_sound) |
| 403 | { |
| 404 | if(!gp2x_dev[3]) gp2x_dev[3] = open("/dev/dsp", O_WRONLY|O_ASYNC); |
| 405 | if(!gp2x_dev[4]) gp2x_dev[4] = open("/dev/mixer", O_RDWR); |
| 406 | } |
| 407 | |
| 408 | // gp2x_dualcore_ram=(unsigned long *)mmap(0, 0x1000000, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], 0x03000000); |
| 409 | /*gp2x_dualcore_ram=(unsigned long *)mmap(0, 0x2000000, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], 0x02000000);*/ |
| 410 | gp2x_memregl=(unsigned long *)mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], 0xc0000000); |
| 411 | gp2x_memregs=(unsigned short *)gp2x_memregl; |
| 412 | |
| 413 | if(first) { printf(MINILIB_VERSION "\n"); |
| 414 | gp2x_dualcore_registers(1); |
| 415 | gp2x_sound_volume(100,100); |
| 416 | gp2x_memregs[0x0F16>>1] = 0x830a; usleep(100000); |
| 417 | gp2x_memregs[0x0F58>>1] = 0x100c; usleep(100000); } |
| 418 | |
| 419 | gp2x_memregs[0x28DA>>1]=(((bpp+1)/8)<<9)|0xAB; /*8/15/16/24bpp...*/ |
| 420 | gp2x_memregs[0x290C>>1]=320*((bpp+1)/8); /*line width in bytes*/ |
| 421 | |
| 422 | memset(gp2x_screen15, 0, 320*240*2); gp2x_video_flip(); |
| 423 | memset(gp2x_screen15, 0, 320*240*2); gp2x_video_flip(); |
| 424 | |
| 425 | //if(bpp==8) gp2x_physvram[2]+=320*240, gp2x_physvram[3]+=320*240, |
| 426 | // gp2x_logvram15[2]+=320*240/2, gp2x_logvram15[3]+=320*240/2; |
| 427 | if(bpp==8) gp2x_physvram[2]+=0x20000, gp2x_physvram[3]+=0x20000, |
| 428 | gp2x_logvram15[2]+=0x20000/2, gp2x_logvram15[3]+=0x20000/2; |
| 429 | |
| 430 | |
| 431 | if ( gp2x_do_sound) |
| 432 | { |
| 433 | ioctl(gp2x_dev[3], SNDCTL_DSP_SPEED, &rate); |
| 434 | ioctl(gp2x_dev[3], SNDCTL_DSP_SETFMT, &bits); |
| 435 | |
| 436 | ioctl(gp2x_dev[3], SNDCTL_DSP_CHANNELS, &channels); |
| 437 | ioctl(gp2x_dev[3], SNDCTL_DSP_STEREO, &stereoLocal); |
| 438 | |
| 439 | frag = 0x40000|13; |
| 440 | ioctl(gp2x_dev[3], SNDCTL_DSP_SETFRAGMENT, &frag); |
| 441 | |
| 442 | |
| 443 | printf("minimal() do sound, rate %d, bits %d, stereo %d, frag %d\n", rate, bits, stereo, frag); |
| 444 | |
| 445 | if(first) |
| 446 | { |
| 447 | first=0; |
| 448 | } |
| 449 | } |
| 450 | } |
| 451 | |
| 452 | |
| 453 | extern int fcloseall(void); |
| 454 | void gp2x_deinit(void) |
| 455 | { |
| 456 | while((gp2x_sound++)<1000000); //wait arm920t threads to finish |
| 457 | |
| 458 | gp2x_dualcore_registers(0); |
| 459 | mmuunhack(); |
| 460 | |
| 461 | gp2x_memregs[0x28DA>>1]=0x4AB; //set video mode |
| 462 | gp2x_memregs[0x290C>>1]=640; |
| 463 | |
| 464 | { int i; for(i=0;i<8;i++) if(gp2x_dev[i]) close(gp2x_dev[i]); } //close all devices |
| 465 | |
| 466 | fcloseall(); //close all files |
| 467 | |
| 468 | } |
| 469 | |
| 470 | |
| 471 | void SetVideoScaling(int pixels,int width,int height) |
| 472 | { |
| 473 | float x, y; |
| 474 | float xscale,yscale=0; |
| 475 | |
| 476 | int bpp=(gp2x_memregs[0x28DA>>1]>>9)&0x3; /* bytes per pixel */ |
| 477 | |
| 478 | scaling_enabled = (width == 320) ? 0 : 1; |
| 479 | |
| 480 | if(gp2x_memregs[0x2800>>1]&0x100) /* TV-Out ON? */ |
| 481 | { |
| 482 | xscale=489.0; /* X-Scale with TV-Out (PAL or NTSC) */ |
| 483 | if (gp2x_memregs[0x2818>>1] == 287) /* PAL? */ |
| 484 | yscale=(pixels*274.0)/320.0; /* Y-Scale with PAL */ |
| 485 | else if (gp2x_memregs[0x2818>>1] == 239) /* NTSC? */ |
| 486 | yscale=(pixels*331.0)/320.0; /* Y-Scale with NTSC */ |
| 487 | } |
| 488 | else /* TV-Out OFF? */ |
| 489 | { |
| 490 | xscale=1024.0; /* X-Scale for LCD */ |
| 491 | yscale=pixels; /* Y-Scale for LCD */ |
| 492 | } |
| 493 | |
| 494 | x=(xscale*width)/320.0; |
| 495 | y=(yscale*bpp*height)/240.0; |
| 496 | gp2x_memregs[0x2906>>1]=(unsigned short)x; /* scale horizontal */ |
| 497 | gp2x_memregl[0x2908>>2]=(unsigned long)y; /* scale vertical */ |
| 498 | gp2x_memregs[0x290C>>1]=pixels*bpp; /* Set Video Width */ |
| 499 | } |