3rdParty: add mupen64plus-input-raphnetraw

This commit is contained in:
Rosalie Wanders
2023-07-19 11:00:22 +02:00
parent 06164d41b1
commit 6d1da7514c
30 changed files with 3714 additions and 0 deletions
@@ -0,0 +1,5 @@
*.dll
*.so
*.o
*.swp
/projects/unix/_obj*/
+12
View File
@@ -0,0 +1,12 @@
; DO NOT EDIT (unless you know what you are doing)
;
; This subdirectory is a git "subrepo", and this file is maintained by the
; git-subrepo command. See https://github.com/ingydotnet/git-subrepo#readme
;
[subrepo]
remote = git@github.com:/raphnet/mupen64plus-input-raphnetraw.git
branch = master
commit = 86112413e98a8648edb11d199673cc24d5799af8
parent = 06164d41b10707838444095da63841248d6f28f6
method = merge
cmdver = 0.4.6
+340
View File
@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
+26
View File
@@ -0,0 +1,26 @@
Mupen64Plus-Input-raphnetraw INSTALL
-----------------------------
This text file was written to explain the installation process of the
Mupen64Plus-Input-raphnetraw module.
If this module is part of a Mupen64Plus source code bundle, the user should run
the "m64p_install.sh" script in the root of the unzipped bundle to install all
of the included modules in the bundle.
If this module is a standalone source code release, you should build the library
from source code and install it via the makefile, like this:
$ cd projects/unix
$ make all
$ sudo make install
If you want to build the Mupen64Plus-Input-raphnetraw module for installation in a
home folder for a single user, you may build it like this (replacing
<my-folder> with your desired local installation path):
$ cd projects/unix
$ make all
$ make install LIBDIR=<my-folder>
+377
View File
@@ -0,0 +1,377 @@
Mupen64Plus-input-raphnetraw LICENSE
-----------------------------
Mupen64Plus-input-raphnetraw is licensed under the GNU General Public License version 2.
The author of Mupen64Plus-input-raphnetraw is:
* Raphaël Assénat (raphnet)
Mupen64Plus-input-raphnetraw is based on Mupen64Plus-input-sdl, its authors being:
* Richard Goedeken (Richard42)
* Sven Eckelmann (ecsv)
* John Chadwick (NMN)
* James Hood (Ebenblues)
* Scott Gorman (okaygo)
* Scott Knauert (Tillin9)
* Jesse Dean (DarkJezter)
* Louai Al-Khanji (slougi)
* Bob Forder (orbitaldecay)
* Jason Espinosa (hasone)
* Bobby Smiles (bsmiles32)
* conchurnavid
* Fayvel
* HyperHacker
* Nebuleon
* s-verma
* and others.
Mupen64Plus is based on GPL-licensed source code from Mupen64 v0.5, originally written by:
* Hacktarux
* Dave2001
* Zilmar
* Gregor Anich (Blight)
* Juha Luotio (JttL)
* and others.
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
+159
View File
@@ -0,0 +1,159 @@
# Input plugin with direct N64 controller access for raphnet adapters
This mupen64plus plugin uses the direct controller access feature offered by my N64 to USB
adapters (versions 3 and up) to let the emulated game communicate with the controllers directly.
* Perfect accuracy: The controller works exactly as it would on a N64 system, without any calibration or tweaking.
* Rumble Pak and Controller Pak (mempak) support (and potentially other accesories too [not confirmed])
* Support for other peripherals that connect to controller ports (eg: N64 mouse) [not confirmed]
* Low latency
## Project homepage
* English: [Direct N64 controller access plugin mupen64plus](http://raphnet.net/programmation/mupen64plus-input-raphnetraw/index_en.php)
* French: [Plugin d'accès direct aux manettes N64 pour mupen64plus](http://raphnet.net/programmation/mupen64plus-input-raphnetraw/index.php)
## License
This project is licensed under the terms of the GNU General Public License, version 2.
Source code is available on the project homepage and on GitHub.
## How to use the plugin
Regardless of your operating system, you will need to install the plugin file(s)
in a directory mupen64plus will search for plugins (eg: Along the other plugin files).
Then, you must tell mupen64plus to use it. eg:
```
mupen64plus --input mupen64plus-input-raphnetraw
```
Where to obtain the plugin files is described below.
### Linux
Please compile it from sources (howto below). This will generate mupen64plus-input-raphnetraw.so
for your architecture.
### Windows (32 and 64 bit)
You may use the releases distributed by raphnet in a zip file. The file contents will look
like this:
```
mupen64plus-input-raphnetraw-windows-0.9/
mupen64plus-input-raphnetraw-windows-0.9/README.md
mupen64plus-input-raphnetraw-windows-0.9/dist_win64/
mupen64plus-input-raphnetraw-windows-0.9/dist_win64/libhidapi-0.dll
mupen64plus-input-raphnetraw-windows-0.9/dist_win64/mupen64plus-input-raphnetraw.dll
mupen64plus-input-raphnetraw-windows-0.9/dist_win32/
mupen64plus-input-raphnetraw-windows-0.9/dist_win32/libhidapi-0.dll
mupen64plus-input-raphnetraw-windows-0.9/dist_win32/mupen64plus-input-raphnetraw.dll
```
If you use a 64-bit version of mupen64plus, copy the files from the `dist_win64` directory. For
the 32-bit version, copy the files from the `dist_win32` directory.
## Compiling the Linux / Unix version
### Prerequesites
A Linux system such as Debian with the following packages installed: (non-exhaustive list)
* gcc
* make
* libhidapi-hidraw0
* libhidapi-dev
### Environment
#### Directory layout
The input-raphnetraw plugin requires a checkout of mupen64plus-core (for the plugin api headers).
* ...somedir/mupen64plus-input-raphnetraw
* ...somedir/mupen64plus-core
#### Compilation
```sh
$ cd .../somedir/
$ cd mupen64plus-input-raphnetraw/projects/unix
$ make all
# then, assuming all went well:
$ cp mupen64plus-input-raphnetraw.so /your/mupen64plus-plugin-directory
# or, if you passed an appropriate PREFIX to make, you can just:
$ make install
```
## Win32/64 cross-compilation under Linux
### System requirements
A Linux system such as Debian with the following packages installed: (non-exhaustive list)
* mingw-w64
* autotools-dev
* autoconf
* automake
* libtool
* git
* make
### Environment
#### Directory layout
The input-raphnetraw plugin requires a checkout of mupen64plus-core (for the plugin api headers) in the
parent directory. Also, each version (32 or 64 bit) requires a matching hidapi build.
* ...somedir/mupen64plus-input-raphnetraw
* ...somedir/mupen64plus-core
* ...somedir/hidapi
* ...somedir/hidapi64
#### preparing the hidapi build
The buildwin32.sh and buildwin64.sh scripts assume the following:
* For the 32-bit build an hidapi configured and compiled with --host i686-w64-mingw32 is required here: ../../../hidapi
* For the 64-bit build an hidapi configured and compiled with --host x86_64-w64-mingw32 is required here: ../../../hidapi64
hidapi can be obtained like this:
```sh
$ cd ...somedir
$ git clone https://github.com/signal11/hidapi.git
$ git clone hidapi hidapi64
```
And then to compile the win32 version:
```sh
cd ...somedir/hidapi
./bootstrap
./configure --host i686-w64-mingw32
make
```
And the win64 version:
```sh
cd ...somedir/hidapi64
./bootstrap
./configure --host x86_64-w64-mingw32
make
```
#### Compilation
This would cross-compile the 32 and 64-bit windows versions.
```bash
$ cd .../somedir/
$ cd mupen64plus-input-raphnetraw/projects/unix
# 32-bit version
$./buildwin32.sh
$ ./buildwin64.sh
```
+43
View File
@@ -0,0 +1,43 @@
# Raphnet raw Input plugin for Mupen64Plus
--------------------------------
## v1.1.0 - July 16, 2019
* Update to input plugin API 2.1.0
## v1.0.2 - November 6, 2018
* Add support for the 3.6.x adapter firmware
## v1.0.1 - November 22, 2017
* Add support for the upcoming 3.5.x adapter firmware
(2-player adapters won't work properly otherwise)
## v1.0.0 - January 15, 2017
* Support for multiple adapters
## v0.9.4 - December 3, 2016
* Improved structure and separation for easier maintenance of the code shared between the Project 64 and mupen64plus versions of this plugin.
* Support for the upcoming 3.4.x adapter firmware (will provide even lower latency/overhead)
## v0.9.3 - November 26, 2016
* Only handle channels supported by the adapter. This increases performance (reduces lag) by
preventing meaningless attempts to communicate with controllers connected to non-existing
ports on the adapter. It also fixes issues where games would see more than one controller was present.
## v0.9.2 - November 24, 2016
* Protect against invalid commands received from emulator. This fixes some games that failed to start.
## v0.9.1 - November 23, 2016
* Polling is now disabled only while a ROM is open.
## v0.9.0 - November 20, 2016
* Initial release
@@ -0,0 +1,312 @@
#/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
# * Mupen64plus-input-raphnetraw - Makefile *
# * Copyright (C) 2016 Raphael Assenat *
# * *
# * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU General Public License as published by *
# * the Free Software Foundation; either version 2 of the License, or *
# * (at your option) any later version. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU General Public License for more details. *
# * *
# * You should have received a copy of the GNU General Public License *
# * along with this program; if not, write to the *
# * Free Software Foundation, Inc., *
# * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# Makefile for raphnetraw Input plugin in Mupen64plus
# detect operating system
UNAME ?= $(shell uname -s)
OS := NONE
ifeq ("$(UNAME)","Linux")
OS = LINUX
SO_EXTENSION = so
SHARED = -shared
endif
ifeq ("$(UNAME)","linux")
OS = LINUX
SO_EXTENSION = so
SHARED = -shared
endif
ifneq ("$(filter GNU hurd,$(UNAME))","")
OS = LINUX
SO_EXTENSION = so
SHARED = -shared
endif
ifeq ("$(UNAME)","Darwin")
OS = OSX
SO_EXTENSION = dylib
SHARED = -bundle
endif
ifeq ("$(UNAME)","FreeBSD")
OS = FREEBSD
SO_EXTENSION = so
SHARED = -shared
endif
ifeq ("$(UNAME)","OpenBSD")
OS = FREEBSD
SO_EXTENSION = so
SHARED = -shared
endif
ifneq ("$(filter GNU/kFreeBSD kfreebsd,$(UNAME))","")
OS = LINUX
SO_EXTENSION = so
SHARED = -shared
endif
ifeq ("$(patsubst MINGW%,MINGW,$(UNAME))","MINGW")
OS = MINGW
SO_EXTENSION = dll
SHARED = -shared
PIC = 0
endif
ifeq ("$(OS)","NONE")
$(error OS type "$(UNAME)" not supported. Please file bug report at 'http://code.google.com/p/mupen64plus/issues')
endif
# detect system architecture, only if it matters for build flags
HOST_CPU ?= $(shell uname -m)
CPU := OTHER
ifneq ("$(filter x86_64 amd64,$(HOST_CPU))","")
CPU := X86
ifeq ("$(BITS)", "32")
ARCH_DETECTED := 64BITS_32
PIC ?= 0
else
ARCH_DETECTED := 64BITS
PIC ?= 1
endif
endif
ifneq ("$(filter pentium i%86,$(HOST_CPU))","")
CPU := X86
ARCH_DETECTED := 32BITS
PIC ?= 0
endif
ifeq ("$(CPU)","OTHER")
PIC ?= 1
endif
# base CFLAGS, LDLIBS, and LDFLAGS
OPTFLAGS ?= -O3 -flto
WARNFLAGS ?= -Wall
CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -ffast-math -fno-strict-aliasing -fvisibility=hidden -I../../src -D_GNU_SOURCE=1
LDFLAGS += $(SHARED)
LDLIBS += -lm
# Since we are building a shared library, we must compile with -fPIC on some architectures
# On 32-bit x86 systems we do not want to use -fPIC because we don't have to and it has a big performance penalty on this arch
ifeq ($(PIC), 1)
CFLAGS += -fPIC
else
CFLAGS += -fno-PIC
endif
# tweak flags for 32-bit build on 64-bit system
ifeq ($(ARCH_DETECTED), 64BITS_32)
CFLAGS += -m32
LDFLAGS += -Wl,-m,elf_i386
endif
# set special flags per-system
ifeq ($(OS), FREEBSD)
ifeq ($(ARCH_DETECTED), 64BITS_32)
$(error Do not use the BITS=32 option with FreeBSD, use -m32 and -m elf_i386)
endif
endif
ifeq ($(OS), LINUX)
LDLIBS += -ldl
endif
ifeq ($(OS), OSX)
#xcode-select has been around since XCode 3.0, i.e. OS X 10.5
OSX_SDK_ROOT = $(shell xcode-select -print-path)/Platforms/MacOSX.platform/Developer/SDKs
OSX_SDK_PATH = $(OSX_SDK_ROOT)/$(shell ls $(OSX_SDK_ROOT) | tail -1)
ifeq ($(CPU), X86)
ifeq ($(ARCH_DETECTED), 64BITS)
CFLAGS += -arch x86_64 -mmacosx-version-min=10.5 -isysroot $(OSX_SDK_PATH)
LDLIBS += -ldl
else
CFLAGS += -mmmx -msse -fomit-frame-pointer -arch i686 -mmacosx-version-min=10.5 -isysroot $(OSX_SDK_PATH)
LDLIBS += -ldl -read_only_relocs suppress
endif
endif
endif
ifeq ($(OS), LINUX)
HIDAPI_NAME=hidapi-hidraw
else
HIDAPI_NAME=hidapi
endif
# test for presence of HIDLIB
ifeq ($(origin HID_CFLAGS) $(origin HID_LDLIBS), undefined undefined)
HIDAPI_CONFIG = $(CROSS_COMPILE)pkg-config $(HIDAPI_NAME)
ifeq ($(shell which $(HIDAPI_CONFIG) 2>/dev/null),)
HIDAPI_CONFIG = $(CROSS_COMPILE)pkg-config $(HIDAPI_NAME)
ifeq ($(shell which $(HIDAPI_CONFIG) 2>/dev/null),)
$(error No HIDAPI development libraries found!)
else
$(warning Using HIDAPI libraries)
endif
endif
HID_CFLAGS += $(shell $(HIDAPI_CONFIG) --cflags)
HID_LDLIBS += $(shell $(HIDAPI_CONFIG) --libs)
endif
CFLAGS += $(HID_CFLAGS)
LDLIBS += $(HID_LDLIBS)
# set mupen64plus core API header path
ifneq ("$(APIDIR)","")
CFLAGS += "-I$(APIDIR)"
else
TRYDIR = ../../../mupen64plus-core/src/api
ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","")
CFLAGS += -I$(TRYDIR)
else
TRYDIR = /usr/local/include/mupen64plus
ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","")
CFLAGS += -I$(TRYDIR)
else
TRYDIR = /usr/include/mupen64plus
ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","")
CFLAGS += -I$(TRYDIR)
else
$(error Mupen64Plus API header files not found! Use makefile parameter APIDIR to force a location.)
endif
endif
endif
endif
# reduced compile output when running make without V=1
ifneq ($(findstring $(MAKEFLAGS),s),s)
ifndef V
Q_CC = @echo ' CC '$@;
Q_LD = @echo ' LD '$@;
endif
endif
# set base program pointers and flags
CC = $(CROSS_COMPILE)gcc
CXX = $(CROSS_COMPILE)g++
RM ?= rm -f
INSTALL ?= install
MKDIR ?= mkdir -p
COMPILE.c = $(Q_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
LINK.o = $(Q_LD)$(CC) $(CFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# set special flags for given Makefile parameters
ifeq ($(DEBUG),1)
CFLAGS += -g
INSTALL_STRIP_FLAG ?=
else
ifneq ($(OS),OSX)
INSTALL_STRIP_FLAG ?= -s
endif
endif
ifeq ($(PLUGINDBG), 1)
CFLAGS += -D_DEBUG
endif
ifeq ($(PORTS_1_AND_4), 1)
CFLAGS += -DPORTS_1_AND_4
endif
# set installation options
ifeq ($(PREFIX),)
PREFIX := /usr/local
endif
ifeq ($(SHAREDIR),)
SHAREDIR := $(PREFIX)/share/mupen64plus
endif
ifeq ($(LIBDIR),)
LIBDIR := $(PREFIX)/lib
endif
ifeq ($(PLUGINDIR),)
PLUGINDIR := $(LIBDIR)/mupen64plus
endif
SRCDIR = ../../src
OBJDIR = _obj$(POSTFIX)
# list of source files to compile
SOURCE = \
$(SRCDIR)/plugin_front.c \
$(SRCDIR)/plugin_back.c \
$(SRCDIR)/gcn64lib.c \
$(SRCDIR)/gcn64.c \
$(SRCDIR)/hexdump.c
ifeq ($(OS),MINGW)
SOURCE += $(SRCDIR)/osal_dynamiclib_win32.c
else
SOURCE += $(SRCDIR)/osal_dynamiclib_unix.c
endif
# generate a list of object files build, make a temporary directory for them
OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(filter %.c, $(SOURCE)))
OBJDIRS = $(dir $(OBJECTS))
$(shell $(MKDIR) $(OBJDIRS))
# build targets
TARGET = mupen64plus-input-raphnetraw$(POSTFIX).$(SO_EXTENSION)
targets:
@echo "Mupen64Plus-input-raphnetraw makefile. "
@echo " Targets:"
@echo " all == Build Mupen64Plus raphnetraw input plugin"
@echo " clean == remove object files"
@echo " rebuild == clean and re-build all"
@echo " install == Install Mupen64Plus raphnetraw input plugin"
@echo " uninstall == Uninstall Mupen64Plus raphnetraw input plugin"
@echo " Options:"
@echo " BITS=32 == build 32-bit binaries on 64-bit machine"
@echo " APIDIR=path == path to find Mupen64Plus Core headers"
@echo " OPTFLAGS=flag == compiler optimization (default: -O3 -flto)"
@echo " WARNFLAGS=flag == compiler warning levels (default: -Wall)"
@echo " PIC=(1|0) == Force enable/disable of position independent code"
@echo " POSTFIX=name == String added to the name of the the build (default: '')"
@echo " Install Options:"
@echo " PREFIX=path == install/uninstall prefix (default: /usr/local)"
@echo " SHAREDIR=path == path to install shared data files (default: PREFIX/share/mupen64plus)"
@echo " LIBDIR=path == library prefix (default: PREFIX/lib)"
@echo " PLUGINDIR=path == path to install plugin libraries (default: LIBDIR/mupen64plus)"
@echo " DESTDIR=path == path to prepend to all installation paths (only for packagers)"
@echo " Debugging Options:"
@echo " DEBUG=1 == add debugging symbols"
@echo " PLUGINDBG=1 == print extra debugging information while running"
@echo " V=1 == show verbose compiler output"
@echo " Build Options, tweaks:"
@echo " PORTS_1_AND_4 == N64 port 4 -> Adapter port 2"
all: $(TARGET)
install: $(TARGET)
$(INSTALL) -d "$(DESTDIR)$(PLUGINDIR)"
$(INSTALL) -m 0644 $(INSTALL_STRIP_FLAG) $(TARGET) "$(DESTDIR)$(PLUGINDIR)"
$(INSTALL) -d "$(DESTDIR)$(SHAREDIR)"
uninstall:
$(RM) "$(DESTDIR)$(PLUGINDIR)/$(TARGET)"
$(RM) "$(DESTDIR)$(SHAREDIR)/InputAutoCfg.ini"
clean:
$(RM) -r $(OBJDIR) $(TARGET)
rebuild: clean all
# build dependency files
CFLAGS += -MD -MP
-include $(OBJECTS:.o=.d)
# standard build rules
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(COMPILE.c) -o $@ $<
$(TARGET): $(OBJECTS)
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
.PHONY: all clean install uninstall targets
@@ -0,0 +1,24 @@
#!/bin/bash
HIDHOME=../../../hidapi
UNAME=MINGW32
DESTDIR=./dist_win32
HID_CFLAGS="-I $HIDHOME/hidapi"
HID_LDLIBS="-L $HIDHOME/windows/.libs/ -lhidapi"
TARGETS=all
MAKEFILE=Makefile
make -f $MAKEFILE clean
if [ $? -ne 0 ]; then
exit 1
fi
make -f $MAKEFILE CROSS_COMPILE=i686-w64-mingw32- UNAME=$UNAME HID_CFLAGS="$HID_CFLAGS" HID_LDLIBS="$HID_LDLIBS" $TARGETS V=1
if [ $? -ne 0 ]; then
exit 1
fi
mkdir -p $DESTDIR
cp mupen64plus-input-raphnetraw.dll $DESTDIR -v
cp $HIDHOME/windows/.libs/*.dll $DESTDIR -v
@@ -0,0 +1,24 @@
#!/bin/bash
HIDHOME=../../../hidapi64
UNAME=MINGW64
DESTDIR=./dist_win64
HID_CFLAGS="-I $HIDHOME/hidapi"
HID_LDLIBS="-L $HIDHOME/windows/.libs/ -lhidapi"
TARGETS=all
MAKEFILE=Makefile
make -f $MAKEFILE clean
if [ $? -ne 0 ]; then
exit 1
fi
make -f $MAKEFILE CROSS_COMPILE=x86_64-w64-mingw32- UNAME=$UNAME HID_CFLAGS="$HID_CFLAGS" HID_LDLIBS="$HID_LDLIBS" $TARGETS V=1
if [ $? -ne 0 ]; then
exit 1
fi
mkdir -p $DESTDIR
cp mupen64plus-input-raphnetraw.dll $DESTDIR -v
cp $HIDHOME/windows/.libs/*.dll $DESTDIR -v
+38
View File
@@ -0,0 +1,38 @@
#!/bin/bash
PREFIX=mupen64plus-input-raphnetraw
HEXFILE=$PREFIX.hex
echo "Release script for $PREFIX"
if [ $# -ne 2 ]; then
echo "Syntax: ./release.sh version releasedir"
echo
echo "ex: './release 1.0' will produce $PREFIX-1.0.tar.gz in releasedir out of git HEAD,"
echo "and place it in the release directory."
echo
echo "It will also create a tag named v1.0"
exit
fi
VERSION=$1
RELEASEDIR=$2
DIRNAME=$PREFIX-$VERSION
FILENAME=$PREFIX-$VERSION.tar.gz
TAG=v$VERSION
echo "Version: $VERSION"
echo "Filename: $FILENAME"
echo "Release directory: $RELEASEDIR"
echo "--------"
echo "Ready? Press ENTER to go ahead (or CTRL+C to cancel)"
read
if [ -f $RELEASEDIR/$FILENAME ]; then
echo "Release file already exists!"
exit 1
fi
git tag $TAG -f
git archive --format=tar --prefix=$DIRNAME/ HEAD | gzip > $RELEASEDIR/$FILENAME
+62
View File
@@ -0,0 +1,62 @@
#!/bin/bash
PROJECT=mupen64plus-input-raphnetraw-windows
if [ $# -ne 2 ]; then
echo "Syntax: ./release.sh version releasedir"
echo
exit
fi
VERSION=$1
RELEASEDIR=$2
DIRNAME=$PROJECT-$VERSION
FILENAME=$PROJECT-$VERSION.zip
if [ -d $RELEASEDIR/$DIRNAME ]; then
echo "$RELEASEDIR/$DIRNAME already exists";
exit 1
fi
mkdir -p $RELEASEDIR/$DIRNAME
if [ $? -ne 0 ]; then
echo "Could not mkdir"
exit 1
fi
cd projects/unix
if [ $? -ne 0 ]; then
echo "Could not chdir"
exit 1
fi
./buildwin32.sh
if [ $? -ne 0 ]; then
echo "Win32 build failed"
exit 1
fi
./buildwin64.sh
if [ $? -ne 0 ]; then
echo "Win64 build failed"
exit 1
fi
cd .. # exit unix
cd .. # exit projects
cp projects/unix/dist_win32 -rv $RELEASEDIR/$DIRNAME
cp projects/unix/dist_win64 -rv $RELEASEDIR/$DIRNAME
cp README.md -rv $RELEASEDIR/$DIRNAME
cp README.md -rv $RELEASEDIR/$DIRNAME/readme.txt
cp RELEASE -rv $RELEASEDIR/$DIRNAME/releases.txt
cd $RELEASEDIR
zip -r $FILENAME $DIRNAME
echo
echo
echo
echo -------------------------------------
ls -lh $FILENAME
echo Done
+371
View File
@@ -0,0 +1,371 @@
/* gc_n64_usb : Gamecube or N64 controller to USB adapter firmware
Copyright (C) 2007-2017 Raphael Assenat <raph@raphnet.net>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "gcn64.h"
#include "gcn64_priv.h"
#include "gcn64lib.h"
#include "requests.h"
#include "hidapi.h"
static int dusbr_verbose = 0;
#define IS_VERBOSE() (dusbr_verbose)
struct supported_adapter {
uint16_t vid, pid;
int if_number;
struct gcn64_adapter_caps caps;
};
static struct supported_adapter supported_adapters[] = {
/* vid, pid, if_no, { n_raw, bio_support } */
{ OUR_VENDOR_ID, 0x0017, 1, { 1, 0 } }, // GC/N64 USB v3.0, 3.1.0, 3.1.1
{ OUR_VENDOR_ID, 0x001D, 1, { 1, 0 } }, // GC/N64 USB v3.2.0 ... v3.3.x
{ OUR_VENDOR_ID, 0x0020, 1, { 1, 0 } }, // GCN64->USB v3.2.1 (N64 mode)
{ OUR_VENDOR_ID, 0x0021, 1, { 1, 0 } }, // GCN64->USB v3.2.1 (GC mode)
{ OUR_VENDOR_ID, 0x0022, 1, { 2, 0 } }, // GCN64->USB v3.3.x (2x GC/N64 mode)
{ OUR_VENDOR_ID, 0x0030, 1, { 2, 0 } }, // GCN64->USB v3.3.0 (2x N64-only mode)
{ OUR_VENDOR_ID, 0x0031, 1, { 2, 0 } }, // GCN64->USB v3.3.0 (2x GC-only mode)
{ OUR_VENDOR_ID, 0x0032, 1, { 1, 1 } }, // GC/N64 USB v3.4.x (GC/N64 mode)
{ OUR_VENDOR_ID, 0x0033, 1, { 1, 1 } }, // GC/N64 USB v3.4.x (N64 mode)
{ OUR_VENDOR_ID, 0x0034, 1, { 1, 1 } }, // GC/N64 USB v3.4.x (GC mode)
{ OUR_VENDOR_ID, 0x0035, 1, { 2, 1 } }, // GC/N64 USB v3.4.x (2x GC/N64 mode)
{ OUR_VENDOR_ID, 0x0036, 1, { 2, 1 } }, // GC/N64 USB v3.4.x (2x N64-only mode)
{ OUR_VENDOR_ID, 0x0037, 1, { 2, 1 } }, // GC/N64 USB v3.4.x (2x GC-only mode)
// GC/N64 USB v3.5.x flavours
{ OUR_VENDOR_ID, 0x0038, 1, { 1, 1 } }, // (GC/N64 mode)
{ OUR_VENDOR_ID, 0x0039, 1, { 1, 1 } }, // (N64 mode)
{ OUR_VENDOR_ID, 0x003A, 1, { 1, 1 } }, // (GC mode)
{ OUR_VENDOR_ID, 0x003B, 2, { 2, 1 } }, // (2x GC/N64 mode)
{ OUR_VENDOR_ID, 0x003C, 2, { 2, 1 } }, // (2x N64-only mode)
{ OUR_VENDOR_ID, 0x003D, 2, { 2, 1 } }, // (2x GC-only mode)
// GC/N64 USB v3.6.x flavours
{ OUR_VENDOR_ID, 0x0060, 1, { 1, 1 } }, // (GC/N64 mode)
{ OUR_VENDOR_ID, 0x0061, 1, { 1, 1 } }, // (N64 mode)
{ OUR_VENDOR_ID, 0x0063, 2, { 2, 1 } }, // (2x GC/N64 mode)
{ OUR_VENDOR_ID, 0x0064, 2, { 2, 1 } }, // (2x N64-only mode)
{ OUR_VENDOR_ID, 0x0067, 1, { 1, 1 } }, // (GC/N64 in GC keyboard mode)
{ }, // terminator
};
int gcn64_init(int verbose)
{
dusbr_verbose = verbose;
hid_init();
return 0;
}
void gcn64_shutdown(void)
{
hid_exit();
}
static char isProductIdHandled(unsigned short pid, int interface_number, struct gcn64_adapter_caps *caps)
{
int i;
for (i=0; supported_adapters[i].vid; i++) {
if (pid == supported_adapters[i].pid) {
if (interface_number == supported_adapters[i].if_number) {
if (caps) {
memcpy(caps, &supported_adapters[i].caps, sizeof (struct gcn64_adapter_caps));
}
return 1;
}
}
}
return 0;
}
struct gcn64_list_ctx *gcn64_allocListCtx(void)
{
struct gcn64_list_ctx *ctx;
ctx = calloc(1, sizeof(struct gcn64_list_ctx));
return ctx;
}
void gcn64_freeListCtx(struct gcn64_list_ctx *ctx)
{
if (ctx) {
if (ctx->devs) {
hid_free_enumeration(ctx->devs);
}
free(ctx);
}
}
int gcn64_countDevices(void)
{
struct gcn64_list_ctx *ctx;
struct gcn64_info inf;
int count = 0;
ctx = gcn64_allocListCtx();
while (gcn64_listDevices(&inf, ctx)) {
count++;
}
gcn64_freeListCtx(ctx);
return count;
}
/**
* \brief List instances of our rgbleds device on the USB busses.
* \param info Pointer to gcn64_info structure to store data
* \param dst Destination buffer for device serial number/id.
* \param dstbuf_size Destination buffer size.
*/
struct gcn64_info *gcn64_listDevices(struct gcn64_info *info, struct gcn64_list_ctx *ctx)
{
struct gcn64_adapter_caps caps;
memset(info, 0, sizeof(struct gcn64_info));
if (!ctx) {
fprintf(stderr, "gcn64_listDevices: Passed null context\n");
return NULL;
}
if (ctx->devs)
goto jumpin;
if (IS_VERBOSE()) {
printf("Start listing\n");
}
ctx->devs = hid_enumerate(OUR_VENDOR_ID, 0x0000);
if (!ctx->devs) {
printf("Hid enumerate returned NULL\n");
return NULL;
}
for (ctx->cur_dev = ctx->devs; ctx->cur_dev; ctx->cur_dev = ctx->cur_dev->next)
{
if (IS_VERBOSE()) {
printf("Considering 0x%04x:0x%04x\n", ctx->cur_dev->vendor_id, ctx->cur_dev->product_id);
}
if (isProductIdHandled(ctx->cur_dev->product_id, ctx->cur_dev->interface_number, &caps))
{
info->usb_vid = ctx->cur_dev->vendor_id;
info->usb_pid = ctx->cur_dev->product_id;
wcsncpy(info->str_prodname, ctx->cur_dev->product_string, PRODNAME_MAXCHARS-1);
wcsncpy(info->str_serial, ctx->cur_dev->serial_number, SERIAL_MAXCHARS-1);
strncpy(info->str_path, ctx->cur_dev->path, PATH_MAXCHARS-1);
memcpy(&info->caps, &caps, sizeof(info->caps));
return info;
}
jumpin:
// prevent 'error: label at end of compound statement'
continue;
}
return NULL;
}
gcn64_hdl_t gcn64_openDevice(struct gcn64_info *dev)
{
hid_device *hdev;
gcn64_hdl_t hdl;
if (!dev)
return NULL;
if (IS_VERBOSE()) {
printf("Opening device path: '%s'\n", dev->str_path);
}
hdev = hid_open_path(dev->str_path);
if (!hdev) {
return NULL;
}
hdl = malloc(sizeof(struct _gcn64_hdl_t));
if (!hdl) {
perror("malloc");
hid_close(hdev);
return NULL;
}
hdl->hdev = hdev;
hdl->report_size = 63;
memcpy(&hdl->caps, &dev->caps, sizeof(hdl->caps));
if (!dev->caps.bio_support) {
printf("Pre-3.4 version detected. Setting report size to 40 bytes\n");
hdl->report_size = 40;
}
return hdl;
}
gcn64_hdl_t gcn64_openBy(struct gcn64_info *dev, unsigned char flags)
{
struct gcn64_list_ctx *ctx;
struct gcn64_info inf;
gcn64_hdl_t h;
if (IS_VERBOSE())
printf("gcn64_openBy, flags=0x%02x\n", flags);
ctx = gcn64_allocListCtx();
if (!ctx)
return NULL;
while (gcn64_listDevices(&inf, ctx)) {
if (IS_VERBOSE())
printf("Considering '%s'\n", inf.str_path);
if (flags & GCN64_FLG_OPEN_BY_SERIAL) {
if (wcscmp(inf.str_serial, dev->str_serial))
continue;
}
if (flags & GCN64_FLG_OPEN_BY_PATH) {
if (strcmp(inf.str_path, dev->str_path))
continue;
}
if (flags & GCN64_FLG_OPEN_BY_VID) {
if (inf.usb_vid != dev->usb_vid)
continue;
}
if (flags & GCN64_FLG_OPEN_BY_PID) {
if (inf.usb_pid != dev->usb_pid)
continue;
}
if (IS_VERBOSE())
printf("Found device. opening...\n");
h = gcn64_openDevice(&inf);
gcn64_freeListCtx(ctx);
return h;
}
gcn64_freeListCtx(ctx);
return NULL;
}
void gcn64_closeDevice(gcn64_hdl_t hdl)
{
hid_device *hdev = hdl->hdev;
if (hdev) {
hid_close(hdev);
}
free(hdl);
}
int gcn64_send_cmd(gcn64_hdl_t hdl, const unsigned char *cmd, int cmdlen)
{
hid_device *hdev = hdl->hdev;
unsigned char buffer[hdl->report_size+1];
int n;
if (cmdlen > (sizeof(buffer)-1)) {
fprintf(stderr, "Error: Command too long\n");
return -1;
}
memset(buffer, 0, sizeof(buffer));
buffer[0] = 0x00; // report ID set to 0 (device has only one)
memcpy(buffer + 1, cmd, cmdlen);
n = hid_send_feature_report(hdev, buffer, sizeof(buffer));
if (n < 0) {
fprintf(stderr, "Could not send feature report (%ls)\n", hid_error(hdev));
return -1;
}
return 0;
}
int gcn64_poll_result(gcn64_hdl_t hdl, unsigned char *cmd, int cmd_maxlen)
{
hid_device *hdev = hdl->hdev;
unsigned char buffer[hdl->report_size+1];
int res_len;
int n;
memset(buffer, 0, sizeof(buffer));
buffer[0] = 0x00; // report ID set to 0 (device has only one)
n = hid_get_feature_report(hdev, buffer, sizeof(buffer));
if (n < 0) {
fprintf(stderr, "Could not send feature report (%ls)\n", hid_error(hdev));
return -1;
}
if (n==0) {
return 0;
}
res_len = n-1;
if (res_len>0) {
int copy_len;
copy_len = res_len;
if (copy_len > cmd_maxlen) {
copy_len = cmd_maxlen;
}
if (cmd) {
memcpy(cmd, buffer+1, copy_len);
}
}
return res_len;
}
int gcn64_exchange(gcn64_hdl_t hdl, unsigned char *outcmd, int outlen, unsigned char *result, int result_max)
{
int n;
n = gcn64_send_cmd(hdl, outcmd, outlen);
if (n<0) {
fprintf(stderr, "Error sending command\n");
return -1;
}
/* Answer to the command comes later. For now, this is polled, but in
* the future an interrupt-in transfer could be used. */
do {
n = gcn64_poll_result(hdl, result, result_max);
if (n < 0) {
fprintf(stderr, "Error\r\n");
break;
}
if (n==0) {
// printf("."); fflush(stdout);
}
} while (n==0);
return n;
}
@@ -0,0 +1,59 @@
#ifndef _gcn64_h__
#define _gcn64_h__
#include <wchar.h>
#define OUR_VENDOR_ID 0x289b
#define PRODNAME_MAXCHARS 256
#define SERIAL_MAXCHARS 256
#define PATH_MAXCHARS 256
struct gcn64_adapter_caps {
int n_raw_channels;
int bio_support;
};
struct gcn64_info {
wchar_t str_prodname[PRODNAME_MAXCHARS];
wchar_t str_serial[SERIAL_MAXCHARS];
char str_path[PATH_MAXCHARS];
int usb_vid, usb_pid;
int access; // True unless direct access to read serial/prodname failed due to permissions.
struct gcn64_adapter_caps caps;
};
struct gcn64_list_ctx;
typedef struct _gcn64_hdl_t *gcn64_hdl_t; // Cast from hid_device
int gcn64_init(int verbose);
void gcn64_shutdown(void);
struct gcn64_list_ctx *gcn64_allocListCtx(void);
void gcn64_freeListCtx(struct gcn64_list_ctx *ctx);
struct gcn64_info *gcn64_listDevices(struct gcn64_info *info, struct gcn64_list_ctx *ctx);
int gcn64_countDevices(void);
gcn64_hdl_t gcn64_openDevice(struct gcn64_info *dev);
#define GCN64_FLG_OPEN_BY_SERIAL 1 /** Serial must match */
#define GCN64_FLG_OPEN_BY_PATH 2 /** Path must match */
#define GCN64_FLG_OPEN_BY_VID 4 /** USB VID must match */
#define GCN64_FLG_OPEN_BY_PID 8 /** USB PID MUST match */
/**
* \brief Open a device matching a serial number
* \param dev The device structure
* \param flags Flags
* \return A handle to the opened device, or NULL if not found
**/
gcn64_hdl_t gcn64_openBy(struct gcn64_info *dev, unsigned char flags);
void gcn64_closeDevice(gcn64_hdl_t hdl);
int gcn64_send_cmd(gcn64_hdl_t hdl, const unsigned char *cmd, int len);
int gcn64_poll_result(gcn64_hdl_t hdl, unsigned char *cmd, int cmdlen);
int gcn64_exchange(gcn64_hdl_t hdl, unsigned char *outcmd, int outlen, unsigned char *result, int result_max);
#endif // _gcn64_h__
@@ -0,0 +1,17 @@
#ifndef _gcn64_priv_h__
#define _gcn64_priv_h__
#include "hidapi.h"
#include "gcn64.h"
struct gcn64_list_ctx {
struct hid_device_info *devs, *cur_dev;
};
typedef struct _gcn64_hdl_t {
hid_device *hdev;
int report_size;
struct gcn64_adapter_caps caps;
} *gcn64_hdl_t;
#endif
@@ -0,0 +1,166 @@
#ifndef _gcn64_protocol_h__
#define _gcn64_protocol_h__
#define CONTROLLER_IS_ABSENT 0
#define CONTROLLER_IS_N64 1
#define CONTROLLER_IS_GC 2
#define CONTROLLER_IS_GC_KEYBOARD 3
#define CONTROLLER_IS_UNKNOWN 4
/* Return many unknown bits, but two are about the expansion port. */
#define N64_GET_CAPABILITIES 0x00
#define N64_RESET 0xFF
#define N64_CAPS_REPLY_LENGTH 3
#define OFFSET_EXT_REMOVED 22
#define OFFSET_EXT_PRESENT 23
/* Returns button states and axis values */
#define N64_GET_STATUS 0x01
#define N64_GET_STATUS_REPLY_LENGTH 4
/* Read from the expansion bus. */
#define N64_EXPANSION_READ 0x02
/* Write to the expansion bus. */
#define N64_EXPANSION_WRITE 0x03
/* Return information about controller. */
#define GC_GETID 0x00
#define GC_GETID_REPLY_LENGTH 3
/* 3-byte get status command. Returns axis and buttons. Also
* controls motor. */
#define GC_GETSTATUS1 0x40
#define GC_GETSTATUS2 0x03
#define GC_GETSTATUS3(rumbling) ((rumbling) ? 0x01 : 0x00)
#define GC_GETSTATUS_REPLY_LENGTH 8
/* 3-byte poll keyboard command.
* Source: http://hitmen.c02.at/files/yagcd/yagcd/chap9.html#sec9.3.3
* */
#define GC_POLL_KB1 0x54
#define GC_POLL_KB2 0x00
#define GC_POLL_KB3 0x00
/* Gamecube keycodes are from table 9.3.2:
* http://hitmen.c02.at/files/yagcd/yagcd/chap9.html#sec9.3.2
*
* But the table appears to have been built using a PC keyboard
* converted (Tototek).
*
* I was working with an ASCII keyboard so I made a few adjustments
* to reflect the /real/ key functions. For instance:
*
* LWIN, RWIN and MENU are in fact the Henkan, muhenkan and katakana/hiragana keys.
* They are equivalemnt to the HID keys International 4, International 5 and International 2.
* The - key (code 0x3F) is also HID international 1.
* The PrntScrn key (code 0x36) is in fact the Yen key (International 3).
* The bracket/brace [{ and }] keys are at different places on this Japanese keyboard,
* but following standard PC practice, some keycodes are named after the US usage. Hence,
* the aforementioned keys are the 2 keys right of P, even if they are not labeled.
*/
#define GC_KEY_RESERVED 0x00 // No key
#define GC_KEY_HOME 0x06
#define GC_KEY_END 0x07
#define GC_KEY_PGUP 0x08
#define GC_KEY_PGDN 0x09
#define GC_KEY_SCROLL_LOCK 0x0A
#define GC_KEY_A 0x10
#define GC_KEY_B 0x11
#define GC_KEY_C 0x12
#define GC_KEY_D 0x13
#define GC_KEY_E 0x14
#define GC_KEY_F 0x15
#define GC_KEY_G 0x16
#define GC_KEY_H 0x17
#define GC_KEY_I 0x18
#define GC_KEY_J 0x19
#define GC_KEY_K 0x1A
#define GC_KEY_L 0x1B
#define GC_KEY_M 0x1C
#define GC_KEY_N 0x1D
#define GC_KEY_O 0x1E
#define GC_KEY_P 0x1F
#define GC_KEY_Q 0x20
#define GC_KEY_R 0x21
#define GC_KEY_S 0x22
#define GC_KEY_T 0x23
#define GC_KEY_U 0x24
#define GC_KEY_V 0x25
#define GC_KEY_W 0x26
#define GC_KEY_X 0x27
#define GC_KEY_Y 0x28
#define GC_KEY_Z 0x29
#define GC_KEY_1 0x2A
#define GC_KEY_2 0x2B
#define GC_KEY_3 0x2C
#define GC_KEY_4 0x2D
#define GC_KEY_5 0x2E
#define GC_KEY_6 0x2F
#define GC_KEY_7 0x30
#define GC_KEY_8 0x31
#define GC_KEY_9 0x32
#define GC_KEY_0 0x33
#define GC_KEY_DASH_UNDERSCORE 0x34 // Key next to 0
#define GC_KEY_PLUS_EQUAL 0x35
#define GC_KEY_YEN 0x36 // Yen on ascii keyboard. HID International 3.
#define GC_KEY_OPEN_BRKT_BRACE 0x37 // 1st key right of P
#define GC_KEY_CLOSE_BRKT_BRACE 0x38 // 2nd key right of P
#define GC_KEY_SEMI_COLON_COLON 0x39 // ;:
#define GC_KEY_QUOTES 0x3A // '"
// The 3rd key after 'L'. HID Keyboard non-us # and ~
#define GC_KEY_BRACKET_MU 0x3B
#define GC_KEY_COMMA_ST 0x3C // ,<
#define GC_KEY_PERIOD_GT 0x3D // .>
#define GC_KEY_SLASH_QUESTION 0x3E // /?
// (The extra key before right-shift on japanese keyboards.
// HID code International 1 [HID usage tables Footnote 15-20]).
#define GC_KEY_INTERNATIONAL1 0x3F
#define GC_KEY_F1 0x40
#define GC_KEY_F2 0x41
#define GC_KEY_F3 0x42
#define GC_KEY_F4 0x43
#define GC_KEY_F5 0x44
#define GC_KEY_F6 0x45
#define GC_KEY_F7 0x46
#define GC_KEY_F8 0x47
#define GC_KEY_F9 0x48
#define GC_KEY_F10 0x49
#define GC_KEY_F11 0x4A
#define GC_KEY_F12 0x4B
#define GC_KEY_ESC 0x4C
#define GC_KEY_INSERT 0x4D
#define GC_KEY_DELETE 0x4E
// (Hankaku/zenkaku/kanji button). Also known as `~
#define GC_KEY_HANKAKU 0x4F
#define GC_KEY_BACKSPACE 0x50
#define GC_KEY_TAB 0x51
#define GC_KEY_CAPS_LOCK 0x53
#define GC_KEY_LEFT_SHIFT 0x54
#define GC_KEY_RIGHT_SHIFT 0x55
#define GC_KEY_LEFT_CTRL 0x56
#define GC_KEY_LEFT_ALT 0x57
#define GC_KEY_MUHENKAN 0x58 // HID international 5
#define GC_KEY_SPACE 0x59
#define GC_KEY_HENKAN 0x5A // HID international 4
#define GC_KEY_KANA 0x5B // HID international 2
#define GC_KEY_LEFT 0x5C
#define GC_KEY_DOWN 0x5D
#define GC_KEY_UP 0x5E
#define GC_KEY_RIGHT 0x5F
#define GC_KEY_ENTER 0x61
void gcn64protocol_hwinit(void);
int gcn64_detectController(void);
unsigned char gcn64_transaction(const unsigned char *tx, int tx_len, unsigned char *rx, unsigned char rx_max);
#endif // _gcn64_protocol_h__
@@ -0,0 +1,444 @@
/* gc_n64_usb : Gamecube or N64 controller to USB adapter firmware
Copyright (C) 2007-2015 Raphael Assenat <raph@raphnet.net>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdio.h>
#include "gcn64lib.h"
#include "gcn64_priv.h"
#include "requests.h"
#include "gcn64_protocol.h"
#include "hexdump.h"
int gcn64lib_getConfig(gcn64_hdl_t hdl, unsigned char param, unsigned char *rx, unsigned char rx_max)
{
unsigned char cmd[2];
int n;
if (!hdl) {
return -1;
}
cmd[0] = RQ_GCN64_GET_CONFIG_PARAM;
cmd[1] = param;
n = gcn64_exchange(hdl, cmd, 2, rx, rx_max);
if (n<2)
return n;
n -= 2;
// Drop the leading CMD and PARAM
if (n) {
memmove(rx, rx+2, n);
}
return n;
}
int gcn64lib_setConfig(gcn64_hdl_t hdl, unsigned char param, unsigned char *data, unsigned char len)
{
unsigned char cmd[2 + len];
int n;
if (!hdl) {
return -1;
}
cmd[0] = RQ_GCN64_SET_CONFIG_PARAM;
cmd[1] = param;
memcpy(cmd + 2, data, len);
n = gcn64_exchange(hdl, cmd, 2 + len, cmd, sizeof(cmd));
if (n<0)
return n;
return 0;
}
int gcn64lib_suspendPolling(gcn64_hdl_t hdl, unsigned char suspend)
{
unsigned char cmd[2];
int n;
if (!hdl) {
return -1;
}
cmd[0] = RQ_GCN64_SUSPEND_POLLING;
cmd[1] = suspend;
n = gcn64_exchange(hdl, cmd, 2, cmd, sizeof(cmd));
if (n<0)
return n;
return 0;
}
int gcn64lib_getVersion(gcn64_hdl_t hdl, char *dst, int dstmax)
{
unsigned char cmd[32];
int n;
if (!hdl) {
return -1;
}
if (dstmax <= 0)
return -1;
cmd[0] = RQ_GCN64_GET_VERSION;
n = gcn64_exchange(hdl, cmd, 1, cmd, sizeof(cmd));
if (n<0)
return n;
dst[0] = 0;
if (n > 1) {
strncpy(dst, (char*)cmd+1, n);
}
dst[dstmax-1] = 0;
return 0;
}
int gcn64lib_getControllerType(gcn64_hdl_t hdl, int chn)
{
unsigned char cmd[32];
int n;
if (!hdl) {
return -1;
}
cmd[0] = RQ_GCN64_GET_CONTROLLER_TYPE;
cmd[1] = chn;
n = gcn64_exchange(hdl, cmd, 2, cmd, sizeof(cmd));
if (n<0)
return n;
if (n<3)
return -1;
return cmd[2];
}
const char *gcn64lib_controllerName(int type)
{
switch(type) {
case CTL_TYPE_NONE: return "No controller";
case CTL_TYPE_N64: return "N64 Controller";
case CTL_TYPE_GC: return "GC Controller";
case CTL_TYPE_GCKB: return "GC Keyboard";
default:
return "Unknown";
}
}
int gcn64lib_getSignature(gcn64_hdl_t hdl, char *dst, int dstmax)
{
unsigned char cmd[40];
int n;
if (!hdl) {
return -1;
}
if (dstmax <= 0)
return -1;
cmd[0] = RQ_GCN64_GET_SIGNATURE;
n = gcn64_exchange(hdl, cmd, 1, cmd, sizeof(cmd));
if (n<0)
return n;
dst[0] = 0;
if (n > 1) {
strncpy(dst, (char*)cmd+1, n);
}
dst[dstmax-1] = 0;
return 0;
}
int gcn64lib_forceVibration(gcn64_hdl_t hdl, unsigned char channel, unsigned char vibrate)
{
unsigned char cmd[3];
int n;
if (!hdl) {
return -1;
}
cmd[0] = RQ_GCN64_SET_VIBRATION;
cmd[1] = channel;
cmd[2] = vibrate;
n = gcn64_exchange(hdl, cmd, 3, cmd, sizeof(cmd));
if (n<0)
return n;
return 0;
}
int gcn64lib_rawSiCommand(gcn64_hdl_t hdl, unsigned char channel, unsigned char *tx, unsigned char tx_len, unsigned char *rx, unsigned char max_rx)
{
unsigned char cmd[3 + tx_len];
unsigned char rep[3 + 64];
int cmdlen, rx_len, n;
if (!hdl) {
return -1;
}
if (!tx) {
return -1;
}
cmd[0] = RQ_GCN64_RAW_SI_COMMAND;
cmd[1] = channel;
cmd[2] = tx_len;
memcpy(cmd+3, tx, tx_len);
cmdlen = 3 + tx_len;
n = gcn64_exchange(hdl, cmd, cmdlen, rep, sizeof(rep));
if (n<0)
return n;
rx_len = rep[2];
if (rx) {
memcpy(rx, rep + 3, rx_len);
}
return rx_len;
}
int gcn64lib_16bit_scan(gcn64_hdl_t hdl, unsigned short min, unsigned short max)
{
int id, n;
unsigned char buf[64];
if (!hdl) {
return -1;
}
for (id = min; id<=max; id++) {
buf[0] = id >> 8;
buf[1] = id & 0xff;
n = gcn64lib_rawSiCommand(hdl, 0, buf, 2, buf, sizeof(buf));
if (n > 0) {
printf("CMD 0x%04x answer: ", id);
printHexBuf(buf, n);
}
}
return 0;
}
int gcn64lib_8bit_scan(gcn64_hdl_t hdl, unsigned char min, unsigned char max)
{
int id, n;
unsigned char buf[64];
if (!hdl) {
return -1;
}
for (id = min; id<=max; id++) {
buf[0] = id;
n = gcn64lib_rawSiCommand(hdl, 0, buf, 1, buf, sizeof(buf));
if (n > 0) {
printf("CMD 0x%02x answer: ", id);
printHexBuf(buf, n);
}
}
return 0;
}
int gcn64lib_bootloader(gcn64_hdl_t hdl)
{
unsigned char cmd[4];
int cmdlen;
if (!hdl) {
return -1;
}
cmd[0] = RQ_GCN64_JUMP_TO_BOOTLOADER;
cmdlen = 1;
gcn64_exchange(hdl, cmd, cmdlen, cmd, sizeof(cmd));
return 0;
}
int gcn64lib_n64_expansionWrite(gcn64_hdl_t hdl, unsigned short addr, unsigned char *data, int len)
{
unsigned char cmd[3 + len];
int cmdlen;
int n;
if (!hdl) {
return -1;
}
cmd[0] = N64_EXPANSION_WRITE;
cmd[1] = addr>>8; // Address high byte
cmd[2] = addr&0xff; // Address low byte
memcpy(cmd + 3, data, len);
cmdlen = 3 + len;
n = gcn64lib_rawSiCommand(hdl, 0, cmd, cmdlen, cmd, sizeof(cmd));
if (n != 1) {
printf("expansion write returned != 1 (%d)\n", n);
return -1;
}
return cmd[0];
}
int gcn64lib_n64_expansionRead(gcn64_hdl_t hdl, unsigned short addr, unsigned char *dst, int max_len)
{
unsigned char cmd[3];
int n;
if (!hdl) {
return -1;
}
cmd[0] = N64_EXPANSION_READ;
cmd[1] = addr>>8; // Address high byte
cmd[2] = addr&0xff; // Address low byte
n = gcn64lib_rawSiCommand(hdl, 0, cmd, 3, dst, max_len);
if (n < 0)
return n;
return n;
}
static int gcn64lib_blockIO_compat(gcn64_hdl_t hdl, struct blockio_op *iops, int n_iops)
{
int i;
int res;
for (i=0; i<n_iops; i++) {
res = gcn64lib_rawSiCommand(hdl, iops[i].chn, iops[i].tx_data, iops[i].tx_len, iops[i].rx_data, iops[i].rx_len);
if (res <= 0) {
// Timeout
iops[i].rx_len &= BIO_RXTX_MASK;
iops[i].rx_len |= BIO_RX_LEN_TIMEDOUT;
} else if (res != iops[i].rx_len) {
// Less bytes than expected
iops[i].rx_len &= BIO_RXTX_MASK;
iops[i].rx_len |= BIO_RX_LEN_TIMEDOUT;
} else {
// Read n bytes as expected.
}
}
return 0;
}
int gcn64lib_blockIO(gcn64_hdl_t hdl, struct blockio_op *iops, int n_iops)
{
unsigned char iobuf[63];
int p, i, n;
if (!hdl)
return -1;
if (!hdl->caps.bio_support) {
return gcn64lib_blockIO_compat(hdl, iops, n_iops);
}
else {
// Request format:
//
// RQ_GCN64_BLOCK_IO
// chn, n_tx, n_rx, tx[]
// ...
//
// The adapter stops processing the buffer when the
// buffer ends or when a channel set to 0xff is encountered.
//
memset(iobuf, 0xff, sizeof(iobuf));
iobuf[0] = RQ_GCN64_BLOCK_IO;
for (p=1, i=0; i<n_iops; i++) {
if (p + 3 + iops[i].tx_len > sizeof(iobuf)) {
fprintf(stderr, "io blocks do not fit in buffer\n");
return -1;
}
iobuf[p] = iops[i].chn;
p++;
iobuf[p] = iops[i].tx_len & BIO_RXTX_MASK;
p++;
iobuf[p] = iops[i].rx_len & BIO_RXTX_MASK;
p++;
memcpy(iobuf + p, iops[i].tx_data, iops[i].tx_len);
p += iops[i].tx_len;
}
#ifdef DEBUG_BLOCKIO
fputs("blockIO request: ", stdout);
printHexBuf(iobuf, sizeof(iobuf));
#endif
n = gcn64_exchange(hdl, iobuf, sizeof(iobuf), iobuf, sizeof(iobuf));
if (n < 0) {
return n;
}
if (n != sizeof(iobuf)) {
fprintf(stderr, "Unexpected iobuf reply size\n");
return -1;
}
#ifdef DEBUG_BLOCKIO
fputs("blockIO answer.: ", stdout);
printHexBuf(iobuf, sizeof(iobuf));
printf("\n");
#endif
// Answer format:
//
// RQ_GCN64_BLOCK_IO
// n_rx, rx[n_rx]
// ...
//
// n_rx will have bits set according to the result. See BIO_RX*. rx will always
// occupy the number of bytes set in the request, regardless of the result.
//
if (iobuf[0] != RQ_GCN64_BLOCK_IO) {
fprintf(stderr, "Invalid iobuf reply\n");
return -1;
}
for (p=1,i=0; i<n_iops; i++) {
if (p >= sizeof(iobuf)) {
fprintf(stderr, "blockIO: adapter reports too much received data\n");
break;
}
iops[i].rx_len = iobuf[p];
p++;
if (p + (iops[i].rx_len & BIO_RXTX_MASK) >= sizeof(iobuf)) {
fprintf(stderr, "blockIO: adapter reports too much received data\n");
break;
}
memcpy(iops[i].rx_data, iobuf + p, iops[i].rx_len & BIO_RXTX_MASK);
p += iops[i].rx_len & BIO_RXTX_MASK;
}
}
return 0;
}
@@ -0,0 +1,42 @@
#ifndef _gcn64_lib_h__
#define _gcn64_lib_h__
#include "gcn64.h"
#define CTL_TYPE_NONE 0
#define CTL_TYPE_N64 1
#define CTL_TYPE_GC 2
#define CTL_TYPE_GCKB 3
int gcn64lib_suspendPolling(gcn64_hdl_t hdl, unsigned char suspend);
int gcn64lib_setConfig(gcn64_hdl_t hdl, unsigned char param, unsigned char *data, unsigned char len);
int gcn64lib_getConfig(gcn64_hdl_t hdl, unsigned char param, unsigned char *rx, unsigned char rx_max);
int gcn64lib_rawSiCommand(gcn64_hdl_t hdl, unsigned char channel, unsigned char *tx, unsigned char tx_len, unsigned char *rx, unsigned char max_rx);
int gcn64lib_getVersion(gcn64_hdl_t hdl, char *dst, int dstmax);
int gcn64lib_getSignature(gcn64_hdl_t hdl, char *dst, int dstmax);
int gcn64lib_forceVibration(gcn64_hdl_t hdl, unsigned char channel, unsigned char vibrate);
int gcn64lib_getControllerType(gcn64_hdl_t hdl, int chn);
const char *gcn64lib_controllerName(int type);
int gcn64lib_bootloader(gcn64_hdl_t hdl);
int gcn64lib_n64_expansionWrite(gcn64_hdl_t hdl, unsigned short addr, unsigned char *data, int len);
int gcn64lib_n64_expansionRead(gcn64_hdl_t hdl, unsigned short addr, unsigned char *dst, int max_len);
int gcn64lib_8bit_scan(gcn64_hdl_t hdl, unsigned char min, unsigned char max);
int gcn64lib_16bit_scan(gcn64_hdl_t hdl, unsigned short min, unsigned short max);
#define BIO_RXTX_MASK 0x3F
#define BIO_RX_LEN_TIMEDOUT 0x80
#define BIO_RX_LEN_PARTIAL 0x40
struct blockio_op {
unsigned char chn;
unsigned char tx_len;
unsigned char *tx_data;
unsigned char rx_len; // expected/max bytes
unsigned char *rx_data;
};
int gcn64lib_blockIO(gcn64_hdl_t hdl, struct blockio_op *iops, int n_iops);
#endif // _gcn64_lib_h__
@@ -0,0 +1,29 @@
/* gc_n64_usb : Gamecube or N64 controller to USB adapter firmware
Copyright (C) 2007-2015 Raphael Assenat <raph@raphnet.net>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
void printHexBuf(unsigned char *buf, int n)
{
int i;
for (i=0; i<n; i++) {
printf("%02x ", buf[i]);
}
printf("\n");
}
@@ -0,0 +1,3 @@
void printHexBuf(unsigned char *buf, int n);
@@ -0,0 +1,30 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-core - osal/dynamiclib.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2009 Richard Goedeken *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#if !defined(OSAL_DYNAMICLIB_H)
#define OSAL_DYNAMICLIB_H
#include "m64p_types.h"
void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName);
#endif /* #define OSAL_DYNAMICLIB_H */
@@ -0,0 +1,37 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-core - osal/dynamiclib_unix.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2009 Richard Goedeken *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include "m64p_types.h"
#include "osal_dynamiclib.h"
void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName)
{
if (pccProcedureName == NULL)
return NULL;
return dlsym(LibHandle, pccProcedureName);
}
@@ -0,0 +1,74 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-ui-console - osal_dynamiclib_win32.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2009 Richard Goedeken *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "m64p_types.h"
#include "osal_dynamiclib.h"
m64p_error osal_dynlib_open(m64p_dynlib_handle *pLibHandle, const char *pccLibraryPath)
{
if (pLibHandle == NULL || pccLibraryPath == NULL)
return M64ERR_INPUT_ASSERT;
*pLibHandle = LoadLibrary(pccLibraryPath);
if (*pLibHandle == NULL)
{
char *pchErrMsg;
DWORD dwErr = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL);
fprintf(stderr, "LoadLibrary('%s') error: %s\n", pccLibraryPath, pchErrMsg);
LocalFree(pchErrMsg);
return M64ERR_INPUT_NOT_FOUND;
}
return M64ERR_SUCCESS;
}
void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName)
{
if (pccProcedureName == NULL)
return NULL;
return GetProcAddress(LibHandle, pccProcedureName);
}
m64p_error osal_dynlib_close(m64p_dynlib_handle LibHandle)
{
int rval = FreeLibrary(LibHandle);
if (rval == 0)
{
char *pchErrMsg;
DWORD dwErr = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL);
fprintf(stderr, "FreeLibrary() error: %s\n", pchErrMsg);
LocalFree(pchErrMsg);
return M64ERR_INTERNAL;
}
return M64ERR_SUCCESS;
}
@@ -0,0 +1,45 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - osal_preproc.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* this header file is for system-dependent #defines, #includes, and typedefs */
#if !defined(OSAL_PREPROC_H)
#define OSAL_PREPROC_H
#if defined(WIN32)
#define strcasestr strstr
#define strcasecmp _stricmp
#endif // WIN32
#if defined(WIN32) && !defined(__MINGW32__)
// macros
#define osal_inline __inline
#else /* Not WIN32 */
// macros
#define osal_inline inline
#endif
#endif // OSAL_PREPROC_H
@@ -0,0 +1,475 @@
/* mupen64plus-input-raphnetraw
*
* Copyright (C) 2016-2017 Raphael Assenat
*
* An input plugin that lets the game under emulation communicate with
* the controllers directly using the direct controller communication
* feature of raphnet V3 adapters[1].
*
* [1] http://www.raphnet.net/electronique/gcn64_usb_adapter_gen3/index_en.php
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
* plugin_back.c : Plugin back code (in contrast to the "front" emulator interface
*
* Revision history:
* 28 Nov 2016 : Initial version
* 1 Dec 2016 : Switch to block IO api
*
*/
#include <stdio.h>
#include <string.h>
#include "plugin_back.h"
#include "gcn64.h"
#include "gcn64lib.h"
#include "version.h"
#include "hexdump.h"
#undef ENABLE_TIMING
#ifdef ENABLE_TIMING
#include <sys/time.h>
#if defined(__MINGW32__) || defined(__MINGW64__)
#error Timing not supported under Windows
#endif
#endif
#undef TIME_RAW_IO
#undef TIME_COMMAND_TO_READ
#undef TRACE_BLOCK_IO
// Filter
#define EXTENSION_RW_ONLY 0
#define MAX_ADAPTERS 4
#define MAX_CHANNELS 4
static void nodebug(int l, const char *m, ...) { }
static pb_debugFunc DebugMessage = nodebug;
#define MAX_OPS 64
struct adapter {
gcn64_hdl_t handle;
struct gcn64_info inf;
struct blockio_op biops[MAX_OPS];
int n_ops;
};
static int g_n_adapters = 0;
struct adapter g_adapters[MAX_ADAPTERS] = { };
struct rawChannel {
struct adapter *adapter;
int chn;
};
/* Multiple adapters are supported, some are single player, others
* two-player. As they are discovered during scan, their
* channels (corresponding to physical controller ports) are added
* to this table. Then, when plugin_front() calls functions in this
* files with a specified channel, the channel is the index in this
* table.
*/
static struct rawChannel g_channels[MAX_CHANNELS] = { };
static int g_n_channels = 0;
int pb_init(pb_debugFunc debugFn)
{
DebugMessage = debugFn;
gcn64_init(1);
return 0;
}
static void pb_freeAllAdapters(void)
{
int i;
for (i=0; i<g_n_adapters; i++) {
if (g_adapters[i].handle) {
/* RomClosed() should have done this, but just
in case it is not always called, do this again here. */
gcn64lib_suspendPolling(g_adapters[i].handle, 0);
gcn64_closeDevice(g_adapters[i].handle);
}
}
g_n_channels = 0;
g_n_adapters = 0;
memset(g_adapters, 0, sizeof(g_adapters));
memset(g_channels, 0, sizeof(g_channels));
}
int pb_shutdown(void)
{
pb_freeAllAdapters();
gcn64_shutdown();
return 0;
}
/**
* \return The number of channels available.
*/
int pb_scanControllers(void)
{
struct gcn64_list_ctx * lctx;
int i, j;
struct adapter *adap;
lctx = gcn64_allocListCtx();
if (!lctx) {
DebugMessage(PB_MSG_ERROR, "Could not allocate gcn64 list context");
return 0;
}
/* This may be called many times in the plugin's lifetime. For instance, each
* time a new game is selected from the PJ64 menu. Freeing previously found
* adapters here and creating a new list makes it possible to disconnect/replace
* USB adapters without having to restart PJ64. */
pb_freeAllAdapters();
/* Pass 1: Fill g_adapters[] with the adapters present on the system. */
g_n_adapters = 0;
adap = &g_adapters[g_n_adapters];
while (gcn64_listDevices(&adap->inf, lctx)) {
adap->handle = gcn64_openDevice(&adap->inf);
if (!adap->handle) {
DebugMessage(PB_MSG_ERROR, "Could not open gcn64 device serial '%ls'. Skipping it.", adap->inf.str_serial);
continue;
}
DebugMessage(PB_MSG_INFO, "Found USB device 0x%04x:0x%04x serial '%ls' name '%ls'",
adap->inf.usb_vid, adap->inf.usb_pid, adap->inf.str_serial, adap->inf.str_prodname);
DebugMessage(PB_MSG_INFO, "Adapter supports %d raw channel(s)", adap->inf.caps.n_raw_channels);
g_n_adapters++;
if (g_n_adapters >= MAX_ADAPTERS)
break;
adap = &g_adapters[g_n_adapters];
}
gcn64_freeListCtx(lctx);
/* Pass 2: Fill the g_channel[] array with the available raw channels.
* For instance, if there are adapters A, B and C (where A and C are single-player
* and B is dual-player), we get this:
*
* [0] = Adapter A, raw channel 0
* [1] = Adapter B, raw channel 0
* [2] = Adapter B, raw channel 1
* [3] = Adapter C, raw channel 0
*
* */
for (i=0; i<g_n_adapters; i++) {
struct adapter *adap = &g_adapters[i];
if (adap->inf.caps.n_raw_channels <= 0)
continue;
for (j=0; j<adap->inf.caps.n_raw_channels; j++) {
if (g_n_channels >= MAX_CHANNELS) {
return g_n_channels;
}
g_channels[g_n_channels].adapter = adap;
g_channels[g_n_channels].chn = j;
DebugMessage(PB_MSG_INFO, "Channel %d: Adapter '%ls' raw channel %d", g_n_channels, adap->inf.str_serial, j);
g_n_channels++;
}
}
return g_n_channels;
}
int pb_romOpen(void)
{
int i;
for (i=0; i<MAX_ADAPTERS; i++) {
if (g_adapters[i].handle) {
gcn64lib_suspendPolling(g_adapters[i].handle, 1);
}
}
return 0;
}
int pb_romClosed(void)
{
int i;
for (i=0; i<MAX_ADAPTERS; i++) {
if (g_adapters[i].handle) {
gcn64lib_suspendPolling(g_adapters[i].handle, 0);
}
}
return 0;
}
static void timing(int start, const char *label)
{
#ifdef ENABLE_TIMING
static struct timeval tv_start;
static int started = 0;
struct timeval tv_now;
if (start) {
gettimeofday(&tv_start, NULL);
started = 1;
return;
}
if (started) {
gettimeofday(&tv_now, NULL);
printf("%s: %ld us\n", label, (tv_now.tv_sec - tv_start.tv_sec) * 1000000 + (tv_now.tv_usec - tv_start.tv_usec) );
started = 0;
}
#endif
}
#ifdef _DEBUG
static void debug_raw_commands_in(unsigned char *command, int channel_id)
{
int tx_len = command[0];
int rx_len = command[1] & 0x3F;
int i;
printf("chn %d: tx[%d] = {", channel_id, tx_len);
for (i=0; i<tx_len; i++) {
printf("0x%02x ", command[2+i]);
}
printf("}, expecting %d byte%c\n", rx_len, rx_len > 1 ? 's':' ');
}
static void debug_raw_commands_out(unsigned char *command, int channel_id)
{
int result = command[1];
int i;
printf("chn %d: result: 0x%02x : ", channel_id, result);
if (0 == (command[1] & 0xC0)) {
for (i=0; i<result; i++) {
printf("0x%02x ", command[2+i]);
}
} else {
printf("error\n");
}
printf("\n");
}
#endif
int pb_controllerCommand(int Control, unsigned char *Command)
{
// I thought of sending requests to the adapter from here, reading
// the results later in readController.
//
// But unlike what I expected, controllerCommand is NOT always called
// before readController... Will investigate later.
#ifdef TIME_COMMAND_TO_READ
timing(1, NULL);
#endif
return 0;
}
static int pb_performIo(void)
{
struct adapter *adap;
struct blockio_op *biops;
int j, i, res;
int op_was_extio[MAX_OPS] = { };
for (j=0; j<g_n_channels; j++)
{
adap = &g_adapters[j];
biops = adap->biops;
/* Skip adapters that do not have IO operations queued. */
if (adap->n_ops <= 0)
continue;
#ifdef TRACE_BLOCK_IO
for (i=0; i<adap->n_ops; i++) {
if (EXTENSION_RW_ONLY && (biops[i].tx_data[0] < 0x02))
continue;
op_was_extio[i] = 1;
printf("Before blockIO: op %d, chn: %d, : tx: 0x%02x, rx: 0x%02x, data: ", i, biops[i].chn,
biops[i].tx_len, biops[i].rx_len);
printHexBuf(biops[i].tx_data, biops[i].tx_len);
}
#endif
#ifdef TIME_RAW_IO
timing(1, NULL);
#endif
res = gcn64lib_blockIO(adap->handle, biops, adap->n_ops);
#ifdef TIME_RAW_IO
timing(0, "blockIO");
#endif
if (res == 0) {
// biops rx_data pointed into PIFram so data is there. But we need
// to patch the RX length parameters (the two most significant bits
// are error bits such as timeout..)
for (i=0; i<adap->n_ops; i++) {
// in PIFram, the read length is one byte before the tx data. A rare
// occasion to use a negative array index ;)
biops[i].tx_data[-1] = biops[i].rx_len;
#ifdef TRACE_BLOCK_IO
if (EXTENSION_RW_ONLY && (!op_was_extio[i])) // Read
continue;
printf("After blockIO: op %d, chn: %d, : tx: 0x%02x, rx: 0x%02x, data: ", i, biops[i].chn,
biops[i].tx_len, biops[i].rx_len);
if (biops[i].rx_len & BIO_RX_LEN_TIMEDOUT) {
printf("Timeout\n");
} else if (biops[i].rx_len & BIO_RX_LEN_PARTIAL) {
printf("Incomplete\n");
} else {
printHexBuf(biops[i].rx_data, biops[i].rx_len);
}
#endif
}
} else {
// For debugging
//exit(1);
}
adap->n_ops = 0;
}
return 0;
}
static int pb_commandIsValid(int Control, unsigned char *Command)
{
if (Control < 0 || Control >= g_n_channels) {
DebugMessage(PB_MSG_WARNING, "pb_readController called with Control=%d", Control);
return 0;
}
if (!Command) {
DebugMessage(PB_MSG_WARNING, "pb_readController called with NULL Command pointer");
return 0;
}
// When a CIC challenge took place in update_pif_write(), the pif ram
// contains a bunch 0xFF followed by 0x00 at offsets 46 and 47. Offset
// 48 onwards contains the challenge answer.
//
// Then when update_pif_read() is called, the 0xFF bytes are be skipped
// up to the two 0x00 bytes that increase the channel to 2. Then the
// challenge answer is (incorrectly) processed as if it were commands
// for the third controller.
//
// This cause issues with the raphnetraw plugin since it modifies pif ram
// to store the result or command error flags. This corrupts the reponse
// and leads to challenge failure.
//
// As I know of no controller commands above 0x03, the filter below guards
// against this condition...
//
if (Control == 2 && Command[2] > 0x03) {
DebugMessage(PB_MSG_WARNING, "Invalid controller command");
return 0;
}
// When Mario Kart 64 uses a controller pak, such PIF ram content
// occurs:
//
// ff 03 21 02 01 f7 ff ff
// ff ff ff ff ff ff ff ff
// ff ff ff ff ff ff ff ff
// ff ff ff ff ff ff ff ff
// ff ff ff ff ff ff ff 21
// fe 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00
// 00 00 00 00 00 00 00 00
//
// It results in this:
// - Transmission of 3 bytes with a 33 bytes return on channel 0,
// - Transmission of 33 bytes with 254 bytes in return on channel 1!?
//
// Obviously the second transaction is an error. The 0xFE (254) that follows
// is where processing should actually stop. This happens to be an invalid length detectable
// by looking at the two most significant bits..
//
if (Command[0] == 0xFE && Command[1] == 0x00) {
DebugMessage(PB_MSG_WARNING, "Ignoring invalid io operation (T: 0x%02x, R: 0x%02x)",
Command[0], Command[1]);
return 0;
}
return 1;
}
int pb_readController(int Control, unsigned char *Command)
{
struct rawChannel *channel;
struct adapter *adap;
struct blockio_op *biops;
// Called with -1 at the end of PIF ram.
if (Control == -1) {
return pb_performIo();
}
/* Check for out of bounds Control parameter, for
* NULL Command and filter various invalid conditions. */
if (!pb_commandIsValid(Control, Command)) {
return 0;
}
/* Add the IO operation to the block io list of
* the adapter serving this channel. */
channel = &g_channels[Control];
adap = channel->adapter;
if (adap->n_ops >= MAX_OPS) {
DebugMessage(PB_MSG_ERROR, "Too many io ops");
} else {
biops = adap->biops;
biops[adap->n_ops].chn = channel->chn; // Control;
biops[adap->n_ops].tx_len = Command[0] & BIO_RXTX_MASK;
biops[adap->n_ops].rx_len = Command[1] & BIO_RXTX_MASK;
biops[adap->n_ops].tx_data = Command + 2;
biops[adap->n_ops].rx_data = Command + 2 + biops[adap->n_ops].tx_len;
if (biops[adap->n_ops].tx_len == 0 || biops[adap->n_ops].rx_len == 0) {
DebugMessage(PB_MSG_WARNING, "TX or RX was zero");
return 0;
}
adap->n_ops++;
}
return 0;
}
@@ -0,0 +1,22 @@
#ifndef _plugin_back_h__
#define _plugin_back_h__
/* Those match mupen64plus levels */
#define PB_MSG_ERROR 1
#define PB_MSG_WARNING 2
#define PB_MSG_INFO 3
#define PB_MSG_STATUS 4
#define PB_MSG_VERBOSE 5
typedef void (*pb_debugFunc)(int level, const char *message, ...);
int pb_init(pb_debugFunc debugFn);
int pb_shutdown(void);
int pb_scanControllers(void);
int pb_readController(int Control, unsigned char *Command);
int pb_controllerCommand(int Control, unsigned char *Command);
int pb_romOpen(void);
int pb_romClosed(void);
#endif // _plugin_back_h__
@@ -0,0 +1,331 @@
/* mupen64plus-input-raphnetraw
*
* Copyright (C) 2016 Raphael Assenat
*
* An input plugin that lets the game under emulation communicate with
* the controllers directly using the direct controller communication
* feature of raphnet V3 adapters[1].
*
* [1] http://www.raphnet.net/electronique/gcn64_usb_adapter_gen3/index_en.php
*
* Based on the Mupen64plus-input-sdl plugin (original banner below)
*/
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-input-sdl - plugin.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2008-2011 Richard Goedeken *
* Copyright (C) 2008 Tillin9 *
* Copyright (C) 2002 Blight *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define M64P_PLUGIN_PROTOTYPES 1
#include "config.h"
#include "m64p_common.h"
#include "m64p_config.h"
#include "m64p_plugin.h"
#include "m64p_types.h"
#include "osal_dynamiclib.h"
#include "plugin_front.h"
#include "plugin_back.h"
#include "version.h"
#ifdef __linux__
#endif /* __linux__ */
#include <errno.h>
#define MAX_CONTROLLERS 4
#ifdef PORTS_1_AND_4
static int emu2adap_portmap[MAX_CONTROLLERS] = { 0, 2, 3, 1 };
#undef PLUGIN_NAME
#define PLUGIN_NAME "raphnetraw ports 1 and 4"
#else
static int emu2adap_portmap[MAX_CONTROLLERS] = { 0, 1, 2, 3 };
#endif
#define EMU_2_ADAP_PORT(a) ((a) == -1 ? -1 : emu2adap_portmap[a])
#if 0
/* definitions of pointers to Core config functions */
ptr_ConfigOpenSection ConfigOpenSection = NULL;
ptr_ConfigDeleteSection ConfigDeleteSection = NULL;
ptr_ConfigSaveSection ConfigSaveSection = NULL;
ptr_ConfigListParameters ConfigListParameters = NULL;
ptr_ConfigSaveFile ConfigSaveFile = NULL;
ptr_ConfigSetParameter ConfigSetParameter = NULL;
ptr_ConfigGetParameter ConfigGetParameter = NULL;
ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL;
ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL;
ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL;
ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL;
ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL;
ptr_ConfigGetParamInt ConfigGetParamInt = NULL;
ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL;
ptr_ConfigGetParamBool ConfigGetParamBool = NULL;
ptr_ConfigGetParamString ConfigGetParamString = NULL;
ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL;
ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL;
ptr_ConfigGetUserDataPath ConfigGetUserDataPath = NULL;
ptr_ConfigGetUserCachePath ConfigGetUserCachePath = NULL;
#endif
/* static data definitions */
static void (*l_DebugCallback)(void *, int, const char *) = NULL;
static void *l_DebugCallContext = NULL;
static int l_PluginInit = 0;
/* Global functions */
static void DebugMessage(int level, const char *message, ...)
{
char msgbuf[1024];
va_list args;
if (!l_DebugCallback) {
printf("No debug callback!\n");
return;
}
va_start(args, message);
vsnprintf(msgbuf, sizeof(msgbuf), message, args);
(*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
va_end(args);
}
/* Mupen64Plus plugin functions */
EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
void (*DebugCallback)(void *, int, const char *))
{
ptr_CoreGetAPIVersions CoreAPIVersionFunc;
int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
if (l_PluginInit) {
return M64ERR_ALREADY_INIT;
}
l_DebugCallback = DebugCallback;
l_DebugCallContext = Context;
/* attach and call the CoreGetAPIVersions function, check Config API version for compatibility */
CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");
if (CoreAPIVersionFunc == NULL)
{
DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");
return M64ERR_INCOMPATIBLE;
}
(*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000) || ConfigAPIVersion < CONFIG_API_VERSION)
{
DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",
VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION));
return M64ERR_INCOMPATIBLE;
}
#if 0
/* Get the core config function pointers from the library handle */
ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection");
ConfigDeleteSection = (ptr_ConfigDeleteSection) osal_dynlib_getproc(CoreLibHandle, "ConfigDeleteSection");
ConfigSaveFile = (ptr_ConfigSaveFile) osal_dynlib_getproc(CoreLibHandle, "ConfigSaveFile");
ConfigSaveSection = (ptr_ConfigSaveSection) osal_dynlib_getproc(CoreLibHandle, "ConfigSaveSection");
ConfigListParameters = (ptr_ConfigListParameters) osal_dynlib_getproc(CoreLibHandle, "ConfigListParameters");
ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter");
ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter");
ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt");
ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat");
ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool");
ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString");
ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt");
ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat");
ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool");
ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString");
ConfigGetSharedDataFilepath = (ptr_ConfigGetSharedDataFilepath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetSharedDataFilepath");
ConfigGetUserConfigPath = (ptr_ConfigGetUserConfigPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserConfigPath");
ConfigGetUserDataPath = (ptr_ConfigGetUserDataPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserDataPath");
ConfigGetUserCachePath = (ptr_ConfigGetUserCachePath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserCachePath");
if (!ConfigOpenSection || !ConfigDeleteSection || !ConfigSaveFile || !ConfigSaveSection || !ConfigSetParameter || !ConfigGetParameter ||
!ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString ||
!ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString ||
!ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath)
{
DebugMessage(M64MSG_ERROR, "Couldn't connect to Core configuration functions");
return M64ERR_INCOMPATIBLE;
}
#endif
pb_init(DebugMessage);
l_PluginInit = 1;
return M64ERR_SUCCESS;
}
EXPORT m64p_error CALL PluginShutdown(void)
{
if (!l_PluginInit) {
return M64ERR_NOT_INIT;
}
/* reset some local variables */
l_DebugCallback = NULL;
l_DebugCallContext = NULL;
pb_shutdown();
l_PluginInit = 0;
return M64ERR_SUCCESS;
}
EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
{
/* set version info */
if (PluginType != NULL)
*PluginType = M64PLUGIN_INPUT;
if (PluginVersion != NULL)
*PluginVersion = PLUGIN_VERSION;
if (APIVersion != NULL)
*APIVersion = INPUT_PLUGIN_API_VERSION;
if (PluginNamePtr != NULL)
*PluginNamePtr = PLUGIN_NAME;
if (Capabilities != NULL)
{
*Capabilities = 0;
}
return M64ERR_SUCCESS;
}
/******************************************************************
Function: InitiateControllers
Purpose: This function initialises how each of the controllers
should be handled.
input: - The handle to the main window.
- A controller structure that needs to be filled for
the emulator to know how to handle each controller.
output: none
*******************************************************************/
EXPORT void CALL InitiateControllers(CONTROL_INFO ControlInfo)
{
int i, n_controllers, adap_port;
n_controllers = pb_scanControllers();
if (n_controllers <= 0) {
DebugMessage(PB_MSG_ERROR, "No adapters detected\n");
return;
}
for (i=0; i<MAX_CONTROLLERS; i++) {
adap_port = EMU_2_ADAP_PORT(i);
if (adap_port < n_controllers) {
ControlInfo.Controls[i].RawData = 1;
/* Setting this is currently required or we
* won't be called at all.
*
* Look at pif.c update_pif_write() to see why.
*/
ControlInfo.Controls[i].Present = 1;
}
}
DebugMessage(PB_MSG_INFO, "%s version %i.%i.%i %s(compiled "__DATE__" "__TIME__") initialized.", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION),
#ifdef _DEBUG
"DEBUG "
#else
""
#endif
);
}
/******************************************************************
Function: ReadController
Purpose: To process the raw data in the pif ram that is about to
be read.
input: - Controller Number (0 to 3) and -1 signalling end of
processing the pif ram.
- Pointer of data to be processed.
output: none
note: This function is only needed if the DLL is allowing raw
data.
*******************************************************************/
EXPORT void CALL ReadController(int Control, unsigned char *Command)
{
pb_readController(EMU_2_ADAP_PORT(Control), Command);
}
EXPORT void CALL ControllerCommand(int Control, unsigned char *Command)
{
pb_controllerCommand(EMU_2_ADAP_PORT(Control), Command);
}
EXPORT void CALL GetKeys( int Control, BUTTONS *Keys )
{
}
EXPORT void CALL RomClosed(void)
{
pb_romClosed();
}
EXPORT int CALL RomOpen(void)
{
pb_romOpen();
return 1;
}
/******************************************************************
Function: SDL_KeyDown
Purpose: To pass the SDL_KeyDown message from the emulator to the
plugin.
input: keymod and keysym of the SDL_KEYDOWN message.
output: none
*******************************************************************/
EXPORT void CALL SDL_KeyDown(int keymod, int keysym)
{
}
/******************************************************************
Function: SDL_KeyUp
Purpose: To pass the SDL_KeyUp message from the emulator to the
plugin.
input: keymod and keysym of the SDL_KEYUP message.
output: none
*******************************************************************/
EXPORT void CALL SDL_KeyUp(int keymod, int keysym)
{
}
@@ -0,0 +1,71 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-input-sdl - plugin.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2008-2009 Richard Goedeken *
* Copyright (C) 2008 Tillin9 *
* Copyright (C) 2002 Blight *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef __PLUGIN_H__
#define __PLUGIN_H__
#include <string.h>
#define M64P_PLUGIN_PROTOTYPES 1
#include "m64p_config.h"
#include "m64p_plugin.h"
#define DEVICE_NO_JOYSTICK (-1)
// Some stuff from n-rage plugin
#define RD_GETSTATUS 0x00 // get status
#define RD_READKEYS 0x01 // read button values
#define RD_READPAK 0x02 // read from controllerpack
#define RD_WRITEPAK 0x03 // write to controllerpack
#define RD_RESETCONTROLLER 0xff // reset controller
#define RD_READEEPROM 0x04 // read eeprom
#define RD_WRITEEPROM 0x05 // write eeprom
#define PAK_IO_RUMBLE 0xC000 // the address where rumble-commands are sent to
/* declarations of pointers to Core config functions */
extern ptr_ConfigListSections ConfigListSections;
extern ptr_ConfigOpenSection ConfigOpenSection;
extern ptr_ConfigDeleteSection ConfigDeleteSection;
extern ptr_ConfigListParameters ConfigListParameters;
extern ptr_ConfigSaveFile ConfigSaveFile;
extern ptr_ConfigSaveSection ConfigSaveSection;
extern ptr_ConfigSetParameter ConfigSetParameter;
extern ptr_ConfigGetParameter ConfigGetParameter;
extern ptr_ConfigGetParameterHelp ConfigGetParameterHelp;
extern ptr_ConfigSetDefaultInt ConfigSetDefaultInt;
extern ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat;
extern ptr_ConfigSetDefaultBool ConfigSetDefaultBool;
extern ptr_ConfigSetDefaultString ConfigSetDefaultString;
extern ptr_ConfigGetParamInt ConfigGetParamInt;
extern ptr_ConfigGetParamFloat ConfigGetParamFloat;
extern ptr_ConfigGetParamBool ConfigGetParamBool;
extern ptr_ConfigGetParamString ConfigGetParamString;
extern ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath;
extern ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath;
extern ptr_ConfigGetUserDataPath ConfigGetUserDataPath;
extern ptr_ConfigGetUserCachePath ConfigGetUserCachePath;
#endif // __PLUGIN_H__
@@ -0,0 +1,38 @@
#ifndef _gcn64_requests_h__
#define _gcn64_requests_h__
/* Commands */
#define RQ_GCN64_SET_CONFIG_PARAM 0x01
#define RQ_GCN64_GET_CONFIG_PARAM 0x02
#define RQ_GCN64_SUSPEND_POLLING 0x03
#define RQ_GCN64_GET_VERSION 0x04
#define RQ_GCN64_GET_SIGNATURE 0x05
#define RQ_GCN64_GET_CONTROLLER_TYPE 0x06
#define RQ_GCN64_SET_VIBRATION 0x07
#define RQ_GCN64_RAW_SI_COMMAND 0x80
#define RQ_GCN64_BLOCK_IO 0x81
#define RQ_GCN64_JUMP_TO_BOOTLOADER 0xFF
/* Configuration parameters and constants */
#define CFG_PARAM_MODE 0x00
/* Values for mode */
#define CFG_MODE_STANDARD 0x00
#define CFG_MODE_N64_ONLY 0x01
#define CFG_MODE_GC_ONLY 0x02
#define CFG_PARAM_SERIAL 0x01
#define CFG_PARAM_POLL_INTERVAL0 0x10
#define CFG_PARAM_POLL_INTERVAL1 0x11
#define CFG_PARAM_POLL_INTERVAL2 0x12
#define CFG_PARAM_POLL_INTERVAL3 0x13
#define CFG_PARAM_N64_SQUARE 0x20 // Not implemented
#define CFG_PARAM_GC_MAIN_SQUARE 0x21 // Not implemented
#define CFG_PARAM_GC_CSTICK_SQUARE 0x22 // Not implemented
#define CFG_PARAM_FULL_SLIDERS 0x23
#define CFG_PARAM_INVERT_TRIG 0x24
#endif
@@ -0,0 +1,38 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-input-sdl - version.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2009-2012 Richard Goedeken *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This header file is for versioning information
*
*/
#if !defined(VERSION_H)
#define VERSION_H
#define PLUGIN_NAME "Mupen64Plus raphnetraw Input Plugin"
#define PLUGIN_VERSION 0x010100
//#define INPUT_PLUGIN_API_VERSION 0x020000
#define INPUT_PLUGIN_API_VERSION 0x020100
#define CONFIG_API_VERSION 0x020100
#define VERSION_PRINTF_SPLIT(x) (((x) >> 16) & 0xffff), (((x) >> 8) & 0xff), ((x) & 0xff)
#endif /* #define VERSION_H */