小霸王学习机的真实手柄,实测CPU 占用 80%

接线图:

nes 红白机模拟器 第4篇 linux 手柄驱动支持-LMLPHP

nes 红白机模拟器 第4篇 linux 手柄驱动支持-LMLPHP

手柄读时序:

nes 红白机模拟器 第4篇 linux 手柄驱动支持-LMLPHP

joypad.c 驱动: 普通的字符设备驱动。

 #include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/device.h> /**
*手柄接线定义
*VCC 3.3 来自 串口
*GND 来自 串口
*CLK 摄像头接口 1P IICSDA GPE15
*LATCH 摄像头接口 2P IICSCL GPE14
*DAT0 摄像头接口 5P CAMCLK GPJ11
*/ #define GPE_BASE 0x56000040
#define GPJ_BASE 0x560000d0 //定义一个结构体用来保存 GPIO 信息
typedef struct {
unsigned int con;
unsigned int dat;
unsigned int up; }T_GPIO_REG, *PT_GPIO_REG; //禁止编译器优化
static volatile PT_GPIO_REG pt_gpe_reg;
static volatile PT_GPIO_REG pt_gpj_reg; static struct class *joypad_drv_class; static ssize_t joypad_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
//利用 sszie_t 返回 手柄键值
//buf 是有符号无法保存 8 bit
int i;
ssize_t val = ;
pt_gpe_reg->dat |= <<;
udelay();
pt_gpe_reg->dat &= ~(<<);
for(i=; i<; i++)
{
udelay();
if(! (pt_gpj_reg->dat & <<))
{
val |= <<i;
} pt_gpe_reg->dat |= <<;
udelay();
pt_gpe_reg->dat &= ~(<<);
}
//最后输出低电平
pt_gpe_reg->dat &= ~(<< | <<);
return val;
} static struct file_operations joypad_drv_fops = {
.owner = THIS_MODULE,
.read = joypad_drv_read,
}; int major;
//注册驱动程序
int joypad_drv_init(void)
{
major = register_chrdev(, "joypad_drv", &joypad_drv_fops); //自动创建 dev 节点
joypad_drv_class = class_create(THIS_MODULE, "joypad_drv");
device_create(joypad_drv_class, NULL, MKDEV(major, ), NULL, "joypad"); //ioremap 地址映射
pt_gpe_reg = ioremap(GPE_BASE, sizeof(T_GPIO_REG));
pt_gpj_reg = ioremap(GPJ_BASE, sizeof(T_GPIO_REG)); //配置GPIO
//GPE 14 15 配置为输出引脚
pt_gpe_reg->con &= ~(<<(*));
pt_gpe_reg->con &= ~(<<(*));
pt_gpe_reg->con |= <<(*);
pt_gpe_reg->con |= <<(*); //默认输出低电平
pt_gpe_reg->dat &= ~(<< | <<); //GPJ 11 配置为输入引脚 禁用内部上拉
pt_gpj_reg->con &= ~(<<(*));
pt_gpj_reg->up |= <<;
return ;
} //卸载驱动程序
void joypad_drv_exit(void)
{
//取消 地址映射
iounmap(pt_gpe_reg);
iounmap(pt_gpj_reg); unregister_chrdev(major, "joypad_drv");
device_destroy(joypad_drv_class, MKDEV(major, ));
class_destroy(joypad_drv_class);
} module_init(joypad_drv_init);
module_exit(joypad_drv_exit);
MODULE_LICENSE("GPL");

InfoNES  InfoNES_System_Linux.cpp:

 /*===================================================================*/
/* */
/* InfoNES_System_Linux.cpp : Linux specific File */
/* */
/* 2001/05/18 InfoNES Project ( Sound is based on DarcNES ) */
/* */
/*===================================================================*/ /*-------------------------------------------------------------------*/
/* Include files */
/*-------------------------------------------------------------------*/ #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h> #include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/soundcard.h> #include "../InfoNES.h"
#include "../InfoNES_System.h"
#include "../InfoNES_pAPU.h" //bool define
#define TRUE 1
#define FALSE 0 /* lcd 操作相关 头文件 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <termios.h> #include <fcntl.h> #define JOYPAD_DEV "/dev/joypad"
static int joypad_fd; static int fb_fd;
static unsigned char *fb_mem;
static int px_width;
static int line_width;
static int screen_width;
static struct fb_var_screeninfo var; static int init_joypad()
{
joypad_fd = open(JOYPAD_DEV, O_RDONLY);
if(- == joypad_fd)
{
printf("joypad dev not found \r\n");
return -;
}
return ;
} static int lcd_fb_display_px(WORD color, int x, int y)
{
unsigned char *pen8;
unsigned short *pen16; pen8 = (unsigned char *)(fb_mem + y*line_width + x*px_width);
pen16 = (unsigned short *)pen8;
*pen16 = color; return ;
} static int lcd_fb_init()
{
//如果使用 mmap 打开方式 必须是 读定方式
fb_fd = open("/dev/fb0", O_RDWR);
if(- == fb_fd)
{
printf("cat't open /dev/fb0 \n");
return -;
}
//获取屏幕参数
if(- == ioctl(fb_fd, FBIOGET_VSCREENINFO, &var))
{
close(fb_fd);
printf("cat't ioctl /dev/fb0 \n");
return -;
} //计算参数
px_width = var.bits_per_pixel / ;
line_width = var.xres * px_width;
screen_width = var.yres * line_width; fb_mem = (unsigned char *)mmap(NULL, screen_width, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, );
if(fb_mem == (void *)-)
{
close(fb_fd);
printf("cat't mmap /dev/fb0 \n");
return -;
}
//清屏
memset(fb_mem, , screen_width);
return ;
} /*-------------------------------------------------------------------*/
/* ROM image file information */
/*-------------------------------------------------------------------*/ char szRomName[];
char szSaveName[];
int nSRAM_SaveFlag; /*-------------------------------------------------------------------*/
/* Constants ( Linux specific ) */
/*-------------------------------------------------------------------*/ #define VBOX_SIZE 7
#define SOUND_DEVICE "/dev/dsp"
#define VERSION "InfoNES v0.91J" /*-------------------------------------------------------------------*/
/* Global Variables ( Linux specific ) */
/*-------------------------------------------------------------------*/ /* Emulation thread */
pthread_t emulation_tid;
int bThread; /* Pad state */
DWORD dwKeyPad1;
DWORD dwKeyPad2;
DWORD dwKeySystem; /* For Sound Emulation */
BYTE final_wave[];
int waveptr;
int wavflag;
int sound_fd; /*-------------------------------------------------------------------*/
/* Function prototypes ( Linux specific ) */
/*-------------------------------------------------------------------*/ void *emulation_thread( void *args ); void start_application( char *filename ); int LoadSRAM(); int SaveSRAM(); /* Palette data */
WORD NesPalette[] =
{
0x39ce, 0x1071, 0x0015, 0x2013, 0x440e, 0x5402, 0x5000, 0x3c20,
0x20a0, 0x0100, 0x0140, 0x00e2, 0x0ceb, 0x0000, 0x0000, 0x0000,
0x5ef7, 0x01dd, 0x10fd, 0x401e, 0x5c17, 0x700b, 0x6ca0, 0x6521,
0x45c0, 0x0240, 0x02a0, 0x0247, 0x0211, 0x0000, 0x0000, 0x0000,
0x7fff, 0x1eff, 0x2e5f, 0x223f, 0x79ff, 0x7dd6, 0x7dcc, 0x7e67,
0x7ae7, 0x4342, 0x2769, 0x2ff3, 0x03bb, 0x0000, 0x0000, 0x0000,
0x7fff, 0x579f, 0x635f, 0x6b3f, 0x7f1f, 0x7f1b, 0x7ef6, 0x7f75,
0x7f94, 0x73f4, 0x57d7, 0x5bf9, 0x4ffe, 0x0000, 0x0000, 0x0000
}; /*===================================================================*/
/* */
/* main() : Application main */
/* */
/*===================================================================*/ /* Application main */
int main( int argc, char **argv )
{
char cmd; /*-------------------------------------------------------------------*/
/* Pad Control */
/*-------------------------------------------------------------------*/ /* Initialize a pad state */
dwKeyPad1 = ;
dwKeyPad2 = ;
dwKeySystem = ; /*-------------------------------------------------------------------*/
/* Load Cassette & Create Thread */
/*-------------------------------------------------------------------*/ /* Initialize thread state */
bThread = FALSE; /* If a rom name specified, start it */
if ( argc == )
{
start_application( argv[] );
} lcd_fb_init();
init_joypad(); //主循环中处理输入事件
while()
{
dwKeyPad1 = read(joypad_fd, , );
}
return();
} /*===================================================================*/
/* */
/* emulation_thread() : Thread Hooking Routine */
/* */
/*===================================================================*/ void *emulation_thread( void *args )
{
InfoNES_Main();
} /*===================================================================*/
/* */
/* start_application() : Start NES Hardware */
/* */
/*===================================================================*/
void start_application( char *filename )
{
/* Set a ROM image name */
strcpy( szRomName, filename ); /* Load cassette */
if ( InfoNES_Load( szRomName ) == )
{
/* Load SRAM */
LoadSRAM(); /* Create Emulation Thread */
bThread = TRUE;
pthread_create( &emulation_tid, NULL, emulation_thread, NULL );
}
} /*===================================================================*/
/* */
/* LoadSRAM() : Load a SRAM */
/* */
/*===================================================================*/
int LoadSRAM()
{
/*
* Load a SRAM
*
* Return values
* 0 : Normally
* -1 : SRAM data couldn't be read
*/ FILE *fp;
unsigned char pSrcBuf[SRAM_SIZE];
unsigned char chData;
unsigned char chTag;
int nRunLen;
int nDecoded;
int nDecLen;
int nIdx; /* It doesn't need to save it */
nSRAM_SaveFlag = ; /* It is finished if the ROM doesn't have SRAM */
if ( !ROM_SRAM )
return(); /* There is necessity to save it */
nSRAM_SaveFlag = ; /* The preparation of the SRAM file name */
strcpy( szSaveName, szRomName );
strcpy( strrchr( szSaveName, '.' ) + , "srm" ); /*-------------------------------------------------------------------*/
/* Read a SRAM data */
/*-------------------------------------------------------------------*/ /* Open SRAM file */
fp = fopen( szSaveName, "rb" );
if ( fp == NULL )
return(-); /* Read SRAM data */
fread( pSrcBuf, SRAM_SIZE, , fp ); /* Close SRAM file */
fclose( fp ); /*-------------------------------------------------------------------*/
/* Extract a SRAM data */
/*-------------------------------------------------------------------*/ nDecoded = ;
nDecLen = ; chTag = pSrcBuf[nDecoded++]; while ( nDecLen < )
{
chData = pSrcBuf[nDecoded++]; if ( chData == chTag )
{
chData = pSrcBuf[nDecoded++];
nRunLen = pSrcBuf[nDecoded++];
for ( nIdx = ; nIdx < nRunLen + ; ++nIdx )
{
SRAM[nDecLen++] = chData;
}
}else {
SRAM[nDecLen++] = chData;
}
} /* Successful */
return();
} /*===================================================================*/
/* */
/* SaveSRAM() : Save a SRAM */
/* */
/*===================================================================*/
int SaveSRAM()
{
/*
* Save a SRAM
*
* Return values
* 0 : Normally
* -1 : SRAM data couldn't be written
*/ FILE *fp;
int nUsedTable[];
unsigned char chData;
unsigned char chPrevData;
unsigned char chTag;
int nIdx;
int nEncoded;
int nEncLen;
int nRunLen;
unsigned char pDstBuf[SRAM_SIZE]; if ( !nSRAM_SaveFlag )
return(); /* It doesn't need to save it */ /*-------------------------------------------------------------------*/
/* Compress a SRAM data */
/*-------------------------------------------------------------------*/ memset( nUsedTable, , sizeof nUsedTable ); for ( nIdx = ; nIdx < SRAM_SIZE; ++nIdx )
{
++nUsedTable[SRAM[nIdx++]];
}
for ( nIdx = , chTag = ; nIdx < ; ++nIdx )
{
if ( nUsedTable[nIdx] < nUsedTable[chTag] )
chTag = nIdx;
} nEncoded = ;
nEncLen = ;
nRunLen = ; pDstBuf[nEncLen++] = chTag; chPrevData = SRAM[nEncoded++]; while ( nEncoded < SRAM_SIZE && nEncLen < SRAM_SIZE - )
{
chData = SRAM[nEncoded++]; if ( chPrevData == chData && nRunLen < )
++nRunLen;
else{
if ( nRunLen >= || chPrevData == chTag )
{
pDstBuf[nEncLen++] = chTag;
pDstBuf[nEncLen++] = chPrevData;
pDstBuf[nEncLen++] = nRunLen - ;
}else {
for ( nIdx = ; nIdx < nRunLen; ++nIdx )
pDstBuf[nEncLen++] = chPrevData;
} chPrevData = chData;
nRunLen = ;
}
}
if ( nRunLen >= || chPrevData == chTag )
{
pDstBuf[nEncLen++] = chTag;
pDstBuf[nEncLen++] = chPrevData;
pDstBuf[nEncLen++] = nRunLen - ;
}else {
for ( nIdx = ; nIdx < nRunLen; ++nIdx )
pDstBuf[nEncLen++] = chPrevData;
} /*-------------------------------------------------------------------*/
/* Write a SRAM data */
/*-------------------------------------------------------------------*/ /* Open SRAM file */
fp = fopen( szSaveName, "wb" );
if ( fp == NULL )
return(-); /* Write SRAM data */
fwrite( pDstBuf, nEncLen, , fp ); /* Close SRAM file */
fclose( fp ); /* Successful */
return();
} /*===================================================================*/
/* */
/* InfoNES_Menu() : Menu screen */
/* */
/*===================================================================*/
int InfoNES_Menu()
{
/*
* Menu screen
*
* Return values
* 0 : Normally
* -1 : Exit InfoNES
*/ /* If terminated */
if ( bThread == FALSE )
{
return(-);
} /* Nothing to do here */
return();
} /*===================================================================*/
/* */
/* InfoNES_ReadRom() : Read ROM image file */
/* */
/*===================================================================*/
int InfoNES_ReadRom( const char *pszFileName )
{
/*
* Read ROM image file
*
* Parameters
* const char *pszFileName (Read)
*
* Return values
* 0 : Normally
* -1 : Error
*/ FILE *fp; /* Open ROM file */
fp = fopen( pszFileName, "rb" );
if ( fp == NULL )
return(-); /* Read ROM Header */
fread( &NesHeader, sizeof NesHeader, , fp );
if ( memcmp( NesHeader.byID, "NES\x1a", ) != )
{
/* not .nes file */
fclose( fp );
return(-);
} /* Clear SRAM */
memset( SRAM, , SRAM_SIZE ); /* If trainer presents Read Triner at 0x7000-0x71ff */
if ( NesHeader.byInfo1 & )
{
fread( &SRAM[0x1000], , , fp );
} /* Allocate Memory for ROM Image */
ROM = (BYTE *) malloc( NesHeader.byRomSize * 0x4000 ); /* Read ROM Image */
fread( ROM, 0x4000, NesHeader.byRomSize, fp ); if ( NesHeader.byVRomSize > )
{
/* Allocate Memory for VROM Image */
VROM = (BYTE *) malloc( NesHeader.byVRomSize * 0x2000 ); /* Read VROM Image */
fread( VROM, 0x2000, NesHeader.byVRomSize, fp );
} /* File close */
fclose( fp ); /* Successful */
return();
} /*===================================================================*/
/* */
/* InfoNES_ReleaseRom() : Release a memory for ROM */
/* */
/*===================================================================*/
void InfoNES_ReleaseRom()
{
/*
* Release a memory for ROM
*
*/ if ( ROM )
{
free( ROM );
ROM = NULL;
} if ( VROM )
{
free( VROM );
VROM = NULL;
}
} /*===================================================================*/
/* */
/* InfoNES_MemoryCopy() : memcpy */
/* */
/*===================================================================*/
void *InfoNES_MemoryCopy( void *dest, const void *src, int count )
{
/*
* memcpy
*
* Parameters
* void *dest (Write)
* Points to the starting address of the copied block's destination
*
* const void *src (Read)
* Points to the starting address of the block of memory to copy
*
* int count (Read)
* Specifies the size, in bytes, of the block of memory to copy
*
* Return values
* Pointer of destination
*/ memcpy( dest, src, count );
return(dest);
} /*===================================================================*/
/* */
/* InfoNES_MemorySet() : memset */
/* */
/*===================================================================*/
void *InfoNES_MemorySet( void *dest, int c, int count )
{
/*
* memset
*
* Parameters
* void *dest (Write)
* Points to the starting address of the block of memory to fill
*
* int c (Read)
* Specifies the byte value with which to fill the memory block
*
* int count (Read)
* Specifies the size, in bytes, of the block of memory to fill
*
* Return values
* Pointer of destination
*/ memset( dest, c, count );
return(dest);
} /*===================================================================*/
/* */
/* InfoNES_LoadFrame() : */
/* Transfer the contents of work frame on the screen */
/* */
/*===================================================================*/
void InfoNES_LoadFrame()
{
int x,y;
WORD wColor;
for (y = ; y < NES_DISP_HEIGHT; y++ )
{
for (x = ; x < NES_DISP_WIDTH; x++ )
{
wColor = WorkFrame[y * NES_DISP_WIDTH + x ];
lcd_fb_display_px(wColor, x, y);
}
}
} /*===================================================================*/
/* */
/* InfoNES_PadState() : Get a joypad state */
/* */
/*===================================================================*/
void InfoNES_PadState( DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem )
{
/*
* Get a joypad state
*
* Parameters
* DWORD *pdwPad1 (Write)
* Joypad 1 State
*
* DWORD *pdwPad2 (Write)
* Joypad 2 State
*
* DWORD *pdwSystem (Write)
* Input for InfoNES
*
*/ /* Transfer joypad state */
*pdwPad1 = dwKeyPad1;
*pdwPad2 = dwKeyPad2;
*pdwSystem = dwKeySystem; dwKeyPad1 = ;
} /*===================================================================*/
/* */
/* InfoNES_SoundInit() : Sound Emulation Initialize */
/* */
/*===================================================================*/
void InfoNES_SoundInit( void )
{
sound_fd = ;
} /*===================================================================*/
/* */
/* InfoNES_SoundOpen() : Sound Open */
/* */
/*===================================================================*/
int InfoNES_SoundOpen( int samples_per_sync, int sample_rate )
{
return ;
} /*===================================================================*/
/* */
/* InfoNES_SoundClose() : Sound Close */
/* */
/*===================================================================*/
void InfoNES_SoundClose( void )
{
if ( sound_fd )
{
close( sound_fd );
}
} /*===================================================================*/
/* */
/* InfoNES_SoundOutput() : Sound Output 5 Waves */
/* */
/*===================================================================*/
void InfoNES_SoundOutput( int samples, BYTE *wave1, BYTE *wave2, BYTE *wave3, BYTE *wave4, BYTE *wave5 )
{ } /*===================================================================*/
/* */
/* InfoNES_Wait() : Wait Emulation if required */
/* */
/*===================================================================*/
void InfoNES_Wait()
{
} /*===================================================================*/
/* */
/* InfoNES_MessageBox() : Print System Message */
/* */
/*===================================================================*/
void InfoNES_MessageBox( char *pszMsg, ... )
{
printf( "MessageBox: %s \n", pszMsg );
} /*
* End of InfoNES_System_Linux.cpp
*/
05-11 10:58