├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── adb2usb ├── adb2usb.ino ├── keymap.c └── keymap.h ├── cape-bone-mac.dts ├── eventmap.c ├── holly.xbm ├── macboard.brd ├── macboard.sch ├── macvideo.c ├── macvideo.p ├── start-xvfb ├── x11mac.c └── xorg.conf /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | .*.swo 3 | *.i 4 | *.o 5 | *.a 6 | *.bin 7 | pcb/*.b[^r][^d] 8 | pcb/*.p[^c][^b] 9 | rgb-test 10 | am335x/pasm/pasm 11 | .*.d 12 | *~ 13 | *~ 14 | a.out 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ######### 2 | # 3 | # The top level targets link in the two .o files for now. 4 | # 5 | TARGETS += macvideo 6 | TARGETS += x11mac 7 | TARGETS += eventmap 8 | LEDSCAPE_DIR ?= ../LEDscape 9 | 10 | eventmap.LDLIBS := \ 11 | -lX11 \ 12 | -lXtst \ 13 | 14 | all: $(TARGETS) macvideo.bin 15 | 16 | ifeq ($(shell uname -m),armv7l) 17 | # We are on the BeagleBone Black itself; 18 | # do not cross compile. 19 | export CROSS_COMPILE:= 20 | else 21 | # We are not on the BeagleBone and might be cross compiling. 22 | # If the environment does not set CROSS_COMPILE, set our 23 | # own. Install a cross compiler with something like: 24 | # 25 | # sudo apt-get install gcc-arm-linux-gnueabi 26 | # 27 | export CROSS_COMPILE?=arm-linux-gnueabi- 28 | endif 29 | 30 | CFLAGS += \ 31 | -std=c99 \ 32 | -g \ 33 | -W \ 34 | -Wall \ 35 | -D_BSD_SOURCE \ 36 | -Wp,-MMD,$(dir $@).$(notdir $@).d \ 37 | -Wp,-MT,$@ \ 38 | -I. \ 39 | -I$(LEDSCAPE_DIR) \ 40 | -O2 \ 41 | -mtune=cortex-a8 \ 42 | -march=armv7-a \ 43 | 44 | LDFLAGS += \ 45 | 46 | LDLIBS += \ 47 | -lpthread \ 48 | 49 | 50 | COMPILE.o = $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $< 51 | COMPILE.a = $(CROSS_COMPILE)gcc -c -o $@ $< 52 | COMPILE.link = $(CROSS_COMPILE)gcc $(LDFLAGS) -o $@ $^ $(LDLIBS) $($@.LDLIBS) 53 | 54 | 55 | ##### 56 | # 57 | # The TI "app_loader" is the userspace library for talking to 58 | # the PRU and mapping memory between it and the ARM. 59 | # 60 | APP_LOADER_DIR ?= $(LEDSCAPE_DIR)/am335x/app_loader 61 | APP_LOADER_LIB := $(APP_LOADER_DIR)/lib/libprussdrv.a 62 | CFLAGS += -I$(APP_LOADER_DIR)/include 63 | LDLIBS += $(APP_LOADER_LIB) 64 | 65 | ##### 66 | # 67 | # The TI PRU assembler looks like it has macros and includes, 68 | # but it really doesn't. So instead we use cpp to pre-process the 69 | # file and then strip out all of the directives that it adds. 70 | # PASM also doesn't handle multiple statements per line, so we 71 | # insert hard newline characters for every ; in the file. 72 | # 73 | PASM_DIR ?= $(LEDSCAPE_DIR)/am335x/pasm 74 | PASM := $(PASM_DIR)/pasm 75 | 76 | %.bin: %.p $(PASM) 77 | $(CPP) \ 78 | -I$(LEDSCAPE_DIR)/ \ 79 | - \ 80 | < $< \ 81 | | perl -p -e 's/^#.*//; s/;/\n/g; s/BYTE\((\d+)\)/t\1/g' > $<.i 82 | $(PASM) -V3 -b $<.i $(basename $@) 83 | $(RM) $<.i 84 | 85 | %.o: %.c 86 | $(COMPILE.o) 87 | 88 | $(foreach O,$(TARGETS),$(eval $O: $O.o $(LEDSCAPE_DIR)/pru.o $(APP_LOADER_LIB))) 89 | 90 | $(TARGETS): 91 | $(COMPILE.link) 92 | 93 | 94 | .PHONY: clean 95 | 96 | clean: 97 | rm -rf \ 98 | *.o \ 99 | *.i \ 100 | .*.o.d \ 101 | *~ \ 102 | *.bin \ 103 | $(INCDIR_APP_LOADER)/*~ \ 104 | $(TARGETS) \ 105 | 106 | 107 | ########### 108 | # 109 | # PRU Libraries and PRU assembler are build from their own trees. 110 | # 111 | $(APP_LOADER_LIB): 112 | $(MAKE) -C $(APP_LOADER_DIR)/interface 113 | 114 | $(PASM): 115 | $(MAKE) -C $(PASM_DIR) 116 | 117 | # Compile and load the device tree file 118 | CAPE=cape-bone-mac 119 | FIRMWARE=/lib/firmware/$(CAPE)-00A0.dtbo 120 | #$(FIRMWARE): $(CAPE).dts 121 | # dtc -I dts -O dtb $< > $@ 122 | $(FIRMWARE): FORCE 123 | dtc -I dts -O dtb $(CAPE).dts > $@ 124 | 125 | FORCE: 126 | 127 | firmware: $(FIRMWARE) 128 | echo $(CAPE) > /sys/devices/bone_capemgr.9/slots 129 | 130 | # Include all of the generated dependency files 131 | -include .*.o.d 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Classic Mac CRT Interface 2 | ========================= 3 | 4 | Mac 128/Plus/SE hardware interface using the BeagleBone Black PRU. 5 | 6 | Run the virtual frame buffer: 7 | 8 | Xvfb :0 -ac -screen 0 512x384x8 -fbdir /tmp/ -retro 9 | 10 | Start the X11 to Mac CRT translation: 11 | 12 | ./x11mac /tmp/Xvfb_screen0 13 | 14 | And start the mouse/keyboard event to X11 event translation: 15 | 16 | ./eventmap /dev/input/event* 17 | 18 | Problems? hudson@trmm.net 19 | 20 | 21 | When HSYNC is low, force VIDEO high. 22 | 23 | H V 24 | 0 0 1 25 | 0 1 1 26 | 1 0 1 27 | 1 1 0 28 | 29 | !(HV) 30 | -------------------------------------------------------------------------------- /adb2usb/adb2usb.ino: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Convert Apple Desktop Bus protocol to USB. 3 | * 4 | * Pinout (female socket, front view): 5 | * 6 | * 4 3 7 | * 2 1 8 | * - 9 | * 10 | * 1: ADB Data (black), connect with 10K pullup to +5V 11 | * 2: PSW (brown) 12 | * 3: +5V (red) 13 | * 4: GND (orange) 14 | * 15 | * Useful documentation: 16 | * https://developer.apple.com/legacy/library/technotes/hw/hw_01.html 17 | */ 18 | 19 | #include "keymap.h" 20 | 21 | #define ADB_PORT PORTD 22 | #define ADB_DDR DDRD 23 | #define ADB_INPUT PIND 24 | #define ADB_PIN 4 25 | 26 | 27 | #define ADB_CMD_FLUSH 0x01 28 | #define ADB_CMD_LISTEN 0x08 29 | #define ADB_CMD_TALK 0x0C 30 | 31 | #define ADB_REG_0 0x00 32 | #define ADB_REG_1 0x01 33 | #define ADB_REG_2 0x02 34 | #define ADB_REG_3 0x03 35 | 36 | 37 | static void 38 | print_u8( 39 | uint8_t x 40 | ) 41 | { 42 | Serial.print((x >> 4) & 0xF, HEX); 43 | Serial.print((x >> 0) & 0xF, HEX); 44 | } 45 | 46 | 47 | static void led_state(int x) 48 | { 49 | if (x) 50 | PORTD |= 1 << 6; 51 | else 52 | PORTD &= ~(1 << 6); 53 | } 54 | 55 | static void led_init(void) 56 | { 57 | DDRD |= 1 << 6; 58 | } 59 | 60 | 61 | static void trigger_state(int x) 62 | { 63 | if (x) 64 | PORTD |= 1 << 3; 65 | else 66 | PORTD &= ~(1 << 3); 67 | } 68 | 69 | static void trigger_init(void) 70 | { 71 | DDRD |= 1 << 3; 72 | } 73 | 74 | static void 75 | adb_drive(int value) 76 | { 77 | if (value) 78 | { 79 | // activate pull up 80 | ADB_DDR &= ~(1 << ADB_PIN); 81 | ADB_PORT |= (1 << ADB_PIN); 82 | } else { 83 | // drive low 84 | ADB_DDR |= (1 << ADB_PIN); 85 | ADB_PORT &= ~(1 << ADB_PIN); 86 | } 87 | } 88 | 89 | 90 | static void 91 | adb_idle(void) 92 | { 93 | adb_drive(1); 94 | } 95 | 96 | 97 | 98 | static void 99 | adb_send_byte( 100 | uint8_t byte 101 | ) 102 | { 103 | // eight data bits, pulse width encoded 104 | for (int i = 0 ; i < 8 ; i++) 105 | { 106 | if (byte & 0x80) 107 | { 108 | adb_drive(0); 109 | delayMicroseconds(35); 110 | adb_drive(1); 111 | delayMicroseconds(65); 112 | } else { 113 | adb_drive(0); 114 | delayMicroseconds(65); 115 | adb_drive(1); 116 | delayMicroseconds(35); 117 | } 118 | byte <<= 1; 119 | } 120 | } 121 | 122 | 123 | static inline volatile uint8_t 124 | adb_input(void) 125 | { 126 | return (ADB_INPUT & (1 << ADB_PIN)) ? 1 : 0; 127 | } 128 | 129 | 130 | static uint8_t 131 | adb_send( 132 | uint8_t byte 133 | ) 134 | { 135 | cli(); 136 | 137 | // attention signal -- low for 800 usec 138 | adb_drive(0); 139 | delayMicroseconds(800); 140 | 141 | // sync signal -- high for 70 usec 142 | adb_drive(1); 143 | delayMicroseconds(70); 144 | 145 | adb_send_byte(byte); 146 | 147 | // stop bit -- low for 65 usec 148 | adb_drive(0); 149 | delayMicroseconds(65); 150 | 151 | // and go back into read mode 152 | adb_idle(); 153 | sei(); 154 | 155 | // if the line is still held low, SRQ has been asserted by 156 | // some device. do a quick scan to clear it. 157 | if (adb_input() == 0) 158 | { 159 | // wait for the line to come back high 160 | while (adb_input() == 0) 161 | ; 162 | return 1; 163 | } 164 | 165 | return 0; 166 | } 167 | 168 | 169 | 170 | static uint8_t 171 | adb_read_byte(void) 172 | { 173 | uint8_t byte = 0; 174 | 175 | for (uint8_t i = 0 ; i < 8 ; i++) 176 | { 177 | // wait for falling edge; need timeout/watchdog 178 | while (adb_input()) 179 | ; 180 | 181 | // wait 50 usec, sample 182 | trigger_state(0); 183 | delayMicroseconds(50); 184 | const uint8_t bit = adb_input(); 185 | byte = (byte << 1) | bit; 186 | 187 | trigger_state(1); 188 | 189 | // make sure we are back into the high-period 190 | delayMicroseconds(15); 191 | while (adb_input() == 0) 192 | ; 193 | } 194 | 195 | trigger_state(0); 196 | return byte; 197 | } 198 | 199 | 200 | static uint8_t 201 | adb_read( 202 | uint8_t * buf, 203 | uint8_t len 204 | ) 205 | { 206 | // Wait up to a few hundred usec to see if there is a start bit 207 | adb_idle(); 208 | 209 | cli(); 210 | //uint32_t end_time = micros() + 300; 211 | //while (micros() != end_time) 212 | for (int i = 0 ; i < 5000 ; i++) 213 | { 214 | const uint8_t bit = adb_input(); 215 | if (bit == 0) 216 | goto start_bit; 217 | } 218 | 219 | // no start bit seen 220 | sei(); 221 | return 0; 222 | 223 | start_bit: 224 | led_state(1); 225 | 226 | // get the start bit 227 | trigger_state(1); 228 | delayMicroseconds(70); 229 | 230 | for (uint8_t i = 0 ; i < len ; i++) 231 | buf[i] = adb_read_byte(); 232 | 233 | led_state(0); 234 | sei(); 235 | 236 | return 1; 237 | } 238 | 239 | 240 | static void 241 | adb_reset(void) 242 | { 243 | adb_drive(0); 244 | delayMicroseconds(3000); 245 | adb_drive(1); 246 | delayMicroseconds(3000); 247 | 248 | // Tell all devices to reset 249 | for (uint8_t dev = 0 ; dev < 16 ; dev++) 250 | { 251 | adb_send((dev << 4) | ADB_CMD_FLUSH); 252 | delayMicroseconds(10000); 253 | } 254 | 255 | // And attempt to clear any SRQ 256 | for (uint8_t dev = 0 ; dev < 16 ; dev++) 257 | { 258 | adb_send((dev << 4) | ADB_CMD_TALK | ADB_REG_0); 259 | delayMicroseconds(10000); 260 | } 261 | } 262 | 263 | 264 | void setup(void) 265 | { 266 | Keyboard.begin(); 267 | Mouse.begin(); 268 | 269 | led_init(); 270 | trigger_init(); 271 | 272 | // Configure the pins for pull up 273 | adb_idle(); 274 | 275 | // for now write to the serial port 276 | Serial.begin(9600); 277 | 278 | // initiate a reset cycle 279 | adb_reset(); 280 | delayMicroseconds(10000); 281 | 282 | 283 | Serial.println("scanning"); 284 | uint8_t buf[2]; 285 | for(uint8_t i = 0 ; i < 16 ; i++) 286 | { 287 | delay(1); 288 | adb_send((i << 4) | ADB_CMD_TALK | ADB_REG_3); 289 | if (adb_read(buf, 2) == 0) 290 | continue; 291 | 292 | Serial.print(i); 293 | Serial.print(' '); 294 | print_u8(buf[0]); 295 | print_u8(buf[1]); 296 | Serial.println(); 297 | } 298 | } 299 | 300 | 301 | void loop(void) 302 | { 303 | uint8_t buf[2]; 304 | 305 | // read from the keyboard 306 | adb_send(0x2C); 307 | if (adb_read(buf, 2)) 308 | { 309 | Serial.print("K:"); 310 | print_u8(buf[0]); 311 | print_u8(buf[1]); 312 | 313 | const uint8_t k0 = buf[0] & 0x7F; 314 | const uint8_t r0 = buf[0] & 0x80; 315 | 316 | Serial.print(' '); 317 | print_u8(k0); 318 | Serial.print(r0 ? '+' : '-'); 319 | 320 | const uint16_t kc0 = keymap[k0]; 321 | print_u8(kc0 >> 8); 322 | print_u8(kc0 >> 0); 323 | if (!kc0) 324 | Serial.print('?'); 325 | else 326 | if (r0) 327 | Keyboard.release(kc0); 328 | else 329 | Keyboard.press(kc0); 330 | 331 | 332 | if (buf[1] != 0xFF) 333 | { 334 | const uint8_t k1 = buf[1] & 0x7F; 335 | const uint8_t r1 = buf[1] & 0x80; 336 | const uint16_t kc1 = keymap[k1]; 337 | 338 | Serial.print(' '); 339 | Serial.print(r1 ? '+' : '-'); 340 | 341 | print_u8(kc1 >> 8); 342 | print_u8(kc1 >> 0); 343 | 344 | if (!kc1) 345 | Serial.print("?"); 346 | else 347 | if (r1) 348 | Keyboard.release(kc1); 349 | else 350 | Keyboard.press(kc1); 351 | } 352 | 353 | Serial.println(); 354 | } 355 | delayMicroseconds(3000); 356 | 357 | // Poll the mouse 358 | adb_send(0x3C); 359 | if (adb_read(buf, 2)) 360 | { 361 | uint16_t ev = (buf[0] << 8) | buf[1]; 362 | 363 | // parsing EM85000 datasheet 364 | // 15: !M main mouse button 365 | // 14-8: signed 7-bit value (positive is up) 366 | // 7: !R right mouse button 367 | // 6-0: signed 7-bit value (positive is right) 368 | uint8_t m1 = (buf[0] & 0x80) ? 0 : 1; 369 | uint8_t m2 = (buf[1] & 0x80) ? 0 : 1; 370 | int8_t dx = buf[0] & 0x7F; 371 | int8_t dy = buf[1] & 0x7F; 372 | 373 | // sign extend dx and dy 374 | dx |= (dx & 0x40) << 1; 375 | dy |= (dy & 0x40) << 1; 376 | 377 | Serial.print("M:"); 378 | print_u8(buf[0]); 379 | print_u8(buf[1]); 380 | Serial.print(' '); 381 | Serial.print(dx); 382 | Serial.print(' '); 383 | Serial.print(dy); 384 | Serial.print(' '); 385 | Serial.print(m1); 386 | Serial.print(m2); 387 | Serial.println(); 388 | 389 | Mouse.move(dy * 4, dx * 4); 390 | 391 | static uint8_t m1_held; 392 | 393 | if (m1 && !m1_held) 394 | { 395 | Mouse.press(MOUSE_LEFT); 396 | m1_held = 1; 397 | } else 398 | if (!m1 && m1_held) 399 | { 400 | Mouse.release(MOUSE_LEFT); 401 | m1_held = 0; 402 | } 403 | } 404 | 405 | delayMicroseconds(3000); 406 | } 407 | -------------------------------------------------------------------------------- /adb2usb/keymap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "keymap.h" 3 | #include 4 | 5 | 6 | const uint16_t keymap[] = { 7 | [0x35] = KEY_ESC, 8 | [0x12] = '1', 9 | [0x13] = '2', 10 | [0x14] = '3', 11 | [0x15] = '4', 12 | [0x17] = '5', 13 | [0x16] = '6', 14 | [0x1a] = '7', 15 | [0x1c] = '8', 16 | [0x19] = '9', 17 | [0x1d] = '0', 18 | [0x1b] = '-', 19 | [0x18] = '=', 20 | [0x33] = KEY_BACKSPACE, 21 | [0x47] = KEY_DELETE, 22 | [0x51] = '=', // 'np=', 23 | [0x4b] = 220, // 'np/', 24 | [0x43] = 221, // 'np*', 25 | 26 | [0x30] = KEY_TAB, 27 | [0x0c] = 'q', 28 | [0x0d] = 'w', 29 | [0x0e] = 'e', 30 | [0x0f] = 'r', 31 | [0x11] = 't', 32 | [0x10] = 'y', 33 | [0x20] = 'u', 34 | [0x22] = 'i', 35 | [0x1f] = 'o', 36 | [0x23] = 'p', 37 | [0x21] = '[', 38 | [0x1e] = ']', 39 | [0x24] = '\n', 40 | [0x59] = 231, // 'np7', 41 | [0x5b] = 232, // 'np8', 42 | [0x5c] = 233, // 'np9', 43 | [0x45] = 223, // 'np+', 44 | 45 | [0x36] = MODIFIERKEY_CTRL, 46 | [0x00] = 'a', 47 | [0x01] = 's', 48 | [0x02] = 'd', 49 | [0x03] = 'f', 50 | [0x05] = 'g', 51 | [0x04] = 'h', 52 | [0x26] = 'j', 53 | [0x28] = 'k', 54 | [0x25] = 'l', 55 | [0x29] = ';', 56 | [0x27] = '\'', 57 | [0x56] = 228, // 'np4', 58 | [0x57] = 229, // 'np5', 59 | [0x58] = 230, // 'np6', 60 | [0x4e] = 222, // 'np-', 61 | 62 | [0x38] = MODIFIERKEY_SHIFT, 63 | [0x06] = 'z', 64 | [0x07] = 'x', 65 | [0x08] = 'c', 66 | [0x09] = 'v', 67 | [0x0b] = 'b', 68 | [0x2d] = 'n', 69 | [0x2e] = 'm', 70 | [0x2b] = ',', 71 | [0x2f] = '.', 72 | [0x2c] = '/', 73 | [0x53] = 225, // 'np1', 74 | [0x54] = 226, // 'np2', 75 | [0x55] = 227, // 'np3', 76 | [0x4c] = 224, // 'np enter', 77 | 78 | [0x39] = KEY_CAPS_LOCK, 79 | [0x3a] = KEY_LEFT_ALT, 80 | [0x37] = KEY_LEFT_GUI, 81 | [0x32] = '`', 82 | [0x31] = ' ', 83 | [0x2a] = '\\', 84 | [0x3b] = KEY_LEFT_ARROW, 85 | [0x3c] = KEY_RIGHT_ARROW, 86 | [0x3d] = KEY_DOWN_ARROW, 87 | [0x3e] = KEY_UP_ARROW, 88 | [0x52] = 234, // 'np0', 89 | [0x41] = 235, // 'np.', 90 | [0x7f] = KEY_RIGHT_GUI, // 'power'! 91 | }; 92 | -------------------------------------------------------------------------------- /adb2usb/keymap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | extern const uint16_t keymap[]; 5 | -------------------------------------------------------------------------------- /cape-bone-mac.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | 3 | / { 4 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 5 | part-number = "BB-BONE-CLASSICMAC-01"; 6 | version = "00A0"; 7 | exclusive-use = "P8.45", "P8.46", "P8.43", "P8.44", "P8.41", "P8.42", "P8.39", "P8.40", "P8.37", "P8.38", "P8.36", "P8.34", "P8.35", "P8.33", "P8.31", "P8.32", "P8.27", "P8.29", "P8.28", "P8.30", "P9.14", "P9.16", "P9.15", "P9.23", "P9.27", "P9.12", "P9.42", "gpio1_18", "gpio1_19", "gpio1_16", "gpio1_17", "gpio3_19", "gpio0_7", "lcd", "tps-bl", "tscadc"; 8 | 9 | fragment@0 { 10 | target = <0xdeadbeef>; 11 | 12 | __overlay__ { 13 | pinmux_bone_lcd3_cape_lcd_pins { 14 | pinctrl-single,pins = <0xa0 0x8 0xa4 0x8 0xa8 0x8 0xac 0x8 0xb0 0x8 0xb4 0x8 0xb8 0x8 0xbc 0x8 0xc0 0x8 0xc4 0x8 0xc8 0x8 0xcc 0x8 0xd0 0x8 0xd4 0x8 0xd8 0x8 0xdc 0x8 0xe0 0x0 0xe4 0x0 0xe8 0x0 0xec 0x7>; 15 | linux,phandle = <0x3>; 16 | phandle = <0x3>; 17 | }; 18 | }; 19 | }; 20 | 21 | fragment@2 { 22 | target = <0xdeadbeef>; 23 | 24 | __overlay__ { 25 | #address-cells = <0x1>; 26 | #size-cells = <0x1>; 27 | 28 | panel { 29 | compatible = "tilcdc,panel"; 30 | pinctrl-names = "default"; 31 | pinctrl-0 = <0x3>; 32 | 33 | panel-info { 34 | ac-bias = <0xff>; 35 | ac-bias-intrpt = <0x0>; 36 | dma-burst-sz = <0x10>; 37 | bpp = <0x10>; 38 | fdd = <0x80>; 39 | tft-alt-mode = <0x0>; 40 | stn-565-mode = <0x0>; 41 | mono-8bit-mode = <0x0>; 42 | sync-edge = <0x0>; 43 | sync-ctrl = <0x1>; 44 | raster-order = <0x0>; 45 | fifo-th = <0x0>; 46 | invert-pxl-clk; 47 | }; 48 | 49 | display-timings { 50 | native-mode = <0x4>; 51 | 52 | 512x384 { 53 | hactive = <512>; 54 | vactive = <384>; 55 | hback-porch = <1>; 56 | hfront-porch = <2>; 57 | hsync-len = <150>; 58 | vback-porch = <20>; 59 | vfront-porch = <10>; 60 | vsync-len = <4>; // in frames 61 | clock-frequency = <16000000>; 62 | hsync-active = <0x0>; 63 | vsync-active = <0x0>; 64 | linux,phandle = <0x4>; 65 | phandle = <0x4>; 66 | }; 67 | }; 68 | }; 69 | 70 | fb { 71 | compatible = "ti,am33xx-tilcdc"; 72 | reg = <0x4830e000 0x1000>; 73 | interrupt-parent = <0xdeadbeef>; 74 | interrupts = <0x24>; 75 | ti,hwmods = "lcdc"; 76 | ti,power-gpio = <0xdeadbeef 0x19 0x0>; 77 | }; 78 | }; 79 | }; 80 | 81 | __symbols__ { 82 | bone_lcd3_cape_lcd_pins = "/fragment@0/__overlay__/pinmux_bone_lcd3_cape_lcd_pins"; 83 | timing0 = "/fragment@2/__overlay__/panel/display-timings/512x384"; 84 | }; 85 | 86 | __fixups__ { 87 | am33xx_pinmux = "/fragment@0:target:0"; 88 | ocp = "/fragment@2:target:0"; 89 | intc = "/fragment@2/__overlay__/fb:interrupt-parent:0"; 90 | gpio3 = "/fragment@2/__overlay__/fb:ti,power-gpio:0"; 91 | }; 92 | 93 | __local_fixups__ { 94 | fixup = "/fragment@2/__overlay__/panel:pinctrl-0:0", "/fragment@2/__overlay__/panel/display-timings:native-mode:0"; 95 | }; 96 | }; 97 | -------------------------------------------------------------------------------- /eventmap.c: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Map /dev/input/event* to XTestEvents. 3 | * 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define XK_MISCELLANY 15 | #define XK_LATIN1 16 | #include 17 | #include "util.h" 18 | 19 | 20 | static Display * dpy; 21 | 22 | // table from http://lists.freedesktop.org/pipermail/xorg/2006-May/015587.html 23 | // arrow keys are borked; need to revisit this. 24 | static const int keymap[] = { 25 | 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 26 | 22, 23, 27 | 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 28 | 38, 39, 29 | 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 30 | 54, 55, 31 | 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 32 | 70, 71, 33 | 72, 73, 74, 75, 76, 77, 76, 79, 80, 81, 82, 83, 84, 85, 34 | 86, 87, 35 | 88, 89, 90, 91, 111, 221, 94, 95, 96, 211, 128, 127, 129, 208, 36 | 131, 126, 37 | 108, 109, 112, 111, 113, 181, 97, 98, 99, 100, 102, 103, 104, 105, 38 | 106, 107, 39 | 239, 160, 174, 176, 222, 157, 123, 110, 139, 134, 209, 210, 133, 115, 40 | 116, 117, 41 | 232, 133, 134, 135, 140, 248, 191, 192, 122, 188, 245, 158, 161, 193, 42 | 223, 227, 43 | 198, 199, 200, 147, 159, 151, 178, 201, 146, 203, 166, 236, 230, 235, 44 | 234, 233, 45 | 163, 204, 253, 153, 162, 144, 164, 177, 152, 190, 208, 129, 130, 231, 46 | 209, 210, 47 | 136, 220, 143, 246, 251, 137, 138, 182, 183, 184, 93, 184, 247, 132, 48 | 170, 219, 49 | 249, 205, 207, 149, 150, 154, 155, 167, 168, 169, 171, 172, 173, 165, 50 | 175, 179, 51 | 180, 0, 185, 186, 187, 118, 119, 120, 121, 229, 194, 195, 196, 197, 52 | 148, 202, 53 | 101, 212, 237, 214, 215, 216, 217, 218, 228, 142, 213, 240, 241, 242, 54 | 243, 244, 55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 | 0, 0 57 | #if 0 58 | // this doesn't work. bummer; 59 | [KEY_RESERVED] = 0, 60 | [KEY_ESC] = XK_Escape, 61 | [KEY_1] = XK_1, 62 | [KEY_2] = XK_2, 63 | [KEY_3] = XK_3, 64 | [KEY_4] = XK_4, 65 | [KEY_5] = XK_5, 66 | [KEY_6] = XK_6, 67 | [KEY_7] = XK_7, 68 | [KEY_8] = XK_8, 69 | [KEY_9] = XK_9, 70 | [KEY_0] = XK_0, 71 | [KEY_MINUS] = XK_minus, 72 | [KEY_EQUAL] = XK_equal, 73 | [KEY_BACKSPACE] = XK_BackSpace, 74 | [KEY_TAB] = XK_Tab, 75 | [KEY_Q] = XK_Q, 76 | [KEY_W] = XK_W, 77 | [KEY_E] = XK_E, 78 | [KEY_R] = XK_R, 79 | [KEY_T] = XK_T, 80 | [KEY_Y] = XK_Y, 81 | [KEY_U] = XK_U, 82 | [KEY_I] = XK_I, 83 | [KEY_O] = XK_O, 84 | [KEY_P] = XK_P, 85 | [KEY_LEFTBRACE] = XK_braceleft, 86 | [KEY_RIGHTBRACE] = XK_braceright, 87 | [KEY_ENTER] = XK_Return, 88 | [KEY_LEFTCTRL] = XK_Control_L, 89 | [KEY_A] = XK_A, 90 | [KEY_S] = XK_S, 91 | [KEY_D] = XK_D, 92 | [KEY_F] = XK_F, 93 | [KEY_G] = XK_G, 94 | [KEY_H] = XK_H, 95 | [KEY_J] = XK_J, 96 | [KEY_K] = XK_K, 97 | [KEY_L] = XK_L, 98 | [KEY_SEMICOLON] = XK_semicolon, 99 | [KEY_APOSTROPHE] = XK_apostrophe, 100 | [KEY_GRAVE] = XK_grave, 101 | [KEY_LEFTSHIFT] = XK_Shift_L, 102 | [KEY_BACKSLASH] = XK_backslash, 103 | [KEY_Z] = XK_Z, 104 | [KEY_X] = XK_X, 105 | [KEY_C] = XK_C, 106 | [KEY_V] = XK_V, 107 | [KEY_B] = XK_B, 108 | [KEY_N] = XK_N, 109 | [KEY_M] = XK_M, 110 | [KEY_COMMA] = XK_comma, 111 | [KEY_DOT] = XK_period, 112 | [KEY_SLASH] = XK_slash, 113 | [KEY_RIGHTSHIFT] = XK_Shift_R, 114 | [KEY_KPASTERISK] = XK_KP_Multiply, 115 | [KEY_LEFTALT] = XK_Alt_L, 116 | [KEY_SPACE] = XK_space, 117 | [KEY_CAPSLOCK] = XK_Caps_Lock, 118 | [KEY_F1] = XK_F1, 119 | [KEY_F2] = XK_F2, 120 | [KEY_F3] = XK_F3, 121 | [KEY_F4] = XK_F4, 122 | [KEY_F5] = XK_F5, 123 | [KEY_F6] = XK_F6, 124 | [KEY_F7] = XK_F7, 125 | [KEY_F8] = XK_F8, 126 | [KEY_F9] = XK_F9, 127 | [KEY_F10] = XK_F10, 128 | [KEY_NUMLOCK] = XK_Num_Lock, 129 | [KEY_SCROLLLOCK] = XK_Scroll_Lock, 130 | [KEY_KP7] = XK_KP_7, 131 | [KEY_KP8] = XK_KP_8, 132 | [KEY_KP9] = XK_KP_9, 133 | [KEY_KPMINUS] = XK_KP_Subtract, 134 | [KEY_KP4] = XK_KP_4, 135 | [KEY_KP5] = XK_KP_5, 136 | [KEY_KP6] = XK_KP_6, 137 | [KEY_KPPLUS] = XK_KP_Add, 138 | [KEY_KP1] = XK_KP_1, 139 | [KEY_KP2] = XK_KP_2, 140 | [KEY_KP3] = XK_KP_3, 141 | [KEY_KP0] = XK_KP_0, 142 | [KEY_KPDOT] = XK_KP_Decimal, 143 | [KEY_ZENKAKUHANKAKU] = XK_Zenkaku_Hankaku, 144 | //[KEY_102ND] = XK_102ND, 145 | [KEY_F11] = XK_F11, 146 | [KEY_F12] = XK_F12, 147 | #if 0 148 | [KEY_RO] = XK_RO, 149 | [KEY_KATAKANA] = XK_KATAKANA, 150 | [KEY_HIRAGANA] = XK_HIRAGANA, 151 | [KEY_HENKAN] = XK_HENKAN, 152 | [KEY_KATAKANAHIRAGANA] = XK_KATAKANAHIRAGANA, 153 | [KEY_MUHENKAN] = XK_MUHENKAN, 154 | [KEY_KPJPCOMMA] = XK_KPJPCOMMA, 155 | #endif 156 | [KEY_KPENTER] = XK_KP_Enter, 157 | [KEY_RIGHTCTRL] = XK_Control_R, 158 | [KEY_KPSLASH] = XK_KP_Divide, 159 | [KEY_SYSRQ] = XK_Sys_Req, 160 | [KEY_RIGHTALT] = XK_Alt_R, 161 | [KEY_LINEFEED] = XK_Linefeed, 162 | [KEY_HOME] = XK_Home, 163 | [KEY_UP] = XK_Up, 164 | [KEY_PAGEUP] = XK_Page_Up, 165 | [KEY_LEFT] = XK_Left, 166 | [KEY_RIGHT] = XK_Right, 167 | [KEY_END] = XK_End, 168 | [KEY_DOWN] = XK_Down, 169 | [KEY_PAGEDOWN] = XK_Page_Down, 170 | [KEY_INSERT] = XK_Insert, 171 | [KEY_DELETE] = XK_Delete, 172 | //[KEY_MACRO] = XK_MACRO, 173 | //[KEY_MUTE] = XK_MUTE, 174 | //[KEY_VOLUMEDOWN] = XK_VOLUMEDOWN, 175 | //[KEY_VOLUMEUP] = XK_VOLUMEUP, 176 | //[KEY_POWER] = XK_POWER, 177 | [KEY_KPEQUAL] = XK_KP_Equal, 178 | //[KEY_KPPLUSMINUS] = XK_KPPLUSMINUS, 179 | //[KEY_PAUSE] = XK_PAUSE, 180 | //[KEY_SCALE] = XK_SCALE, 181 | //[KEY_KPCOMMA] = XK_KPCOMMA, 182 | //[KEY_HANGEUL] = XK_HANGEUL, 183 | //[KEY_HANGUEL] = XK_HANGUEL, 184 | //[KEY_HANJA] = XK_HANJA, 185 | //[KEY_YEN] = XK_YEN, 186 | [KEY_LEFTMETA] = XK_Meta_L, 187 | [KEY_RIGHTMETA] = XK_Meta_R, 188 | #if 0 189 | [KEY_COMPOSE] = XK_Compose, 190 | [KEY_STOP] = XK_Stop, 191 | [KEY_AGAIN] = XK_AGAIN, 192 | [KEY_PROPS] = XK_PROPS, 193 | [KEY_UNDO] = XK_UNDO, 194 | [KEY_FRONT] = XK_FRONT, 195 | [KEY_COPY] = XK_COPY, 196 | [KEY_OPEN] = XK_OPEN, 197 | [KEY_PASTE] = XK_PASTE, 198 | [KEY_FIND] = XK_FIND, 199 | [KEY_CUT] = XK_CUT, 200 | [KEY_HELP] = XK_HELP, 201 | [KEY_MENU] = XK_MENU, 202 | [KEY_CALC] = XK_CALC, 203 | [KEY_SETUP] = XK_SETUP, 204 | [KEY_SLEEP] = XK_SLEEP, 205 | [KEY_WAKEUP] = XK_WAKEUP, 206 | [KEY_FILE] = XK_FILE, 207 | [KEY_SENDFILE] = XK_SENDFILE, 208 | [KEY_DELETEFILE] = XK_DELETEFILE, 209 | [KEY_XFER] = XK_XFER, 210 | [KEY_PROG1] = XK_PROG1, 211 | [KEY_PROG2] = XK_PROG2, 212 | [KEY_WWW] = XK_WWW, 213 | [KEY_MSDOS] = XK_MSDOS, 214 | [KEY_COFFEE] = XK_COFFEE, 215 | [KEY_SCREENLOCK] = XK_SCREENLOCK, 216 | [KEY_DIRECTION] = XK_DIRECTION, 217 | [KEY_CYCLEWINDOWS] = XK_CYCLEWINDOWS, 218 | [KEY_MAIL] = XK_MAIL, 219 | [KEY_BOOKMARKS] = XK_BOOKMARKS, 220 | [KEY_COMPUTER] = XK_COMPUTER, 221 | [KEY_BACK] = XK_BACK, 222 | [KEY_FORWARD] = XK_FORWARD, 223 | [KEY_CLOSECD] = XK_CLOSECD, 224 | [KEY_EJECTCD] = XK_EJECTCD, 225 | [KEY_EJECTCLOSECD] = XK_EJECTCLOSECD, 226 | [KEY_NEXTSONG] = XK_NEXTSONG, 227 | [KEY_PLAYPAUSE] = XK_PLAYPAUSE, 228 | [KEY_PREVIOUSSONG] = XK_PREVIOUSSONG, 229 | [KEY_STOPCD] = XK_STOPCD, 230 | [KEY_RECORD] = XK_RECORD, 231 | [KEY_REWIND] = XK_REWIND, 232 | [KEY_PHONE] = XK_PHONE, 233 | [KEY_ISO] = XK_ISO, 234 | [KEY_CONFIG] = XK_CONFIG, 235 | [KEY_HOMEPAGE] = XK_HOMEPAGE, 236 | [KEY_REFRESH] = XK_REFRESH, 237 | [KEY_EXIT] = XK_EXIT, 238 | [KEY_MOVE] = XK_MOVE, 239 | [KEY_EDIT] = XK_EDIT, 240 | [KEY_SCROLLUP] = XK_SCROLLUP, 241 | [KEY_SCROLLDOWN] = XK_SCROLLDOWN, 242 | [KEY_KPLEFTPAREN] = XK_KPLEFTPAREN, 243 | [KEY_KPRIGHTPAREN] = XK_KPRIGHTPAREN, 244 | [KEY_NEW] = XK_NEW, 245 | [KEY_REDO] = XK_REDO, 246 | [KEY_F13] = XK_F13, 247 | [KEY_F14] = XK_F14, 248 | [KEY_F15] = XK_F15, 249 | [KEY_F16] = XK_F16, 250 | [KEY_F17] = XK_F17, 251 | [KEY_F18] = XK_F18, 252 | [KEY_F19] = XK_F19, 253 | [KEY_F20] = XK_F20, 254 | [KEY_F21] = XK_F21, 255 | [KEY_F22] = XK_F22, 256 | [KEY_F23] = XK_F23, 257 | [KEY_F24] = XK_F24, 258 | [KEY_PLAYCD] = XK_PLAYCD, 259 | [KEY_PAUSECD] = XK_PAUSECD, 260 | [KEY_PROG3] = XK_PROG3, 261 | [KEY_PROG4] = XK_PROG4, 262 | [KEY_DASHBOARD] = XK_DASHBOARD, 263 | [KEY_SUSPEND] = XK_SUSPEND, 264 | [KEY_CLOSE] = XK_CLOSE, 265 | [KEY_PLAY] = XK_PLAY, 266 | [KEY_FASTFORWARD] = XK_FASTFORWARD, 267 | [KEY_BASSBOOST] = XK_BASSBOOST, 268 | [KEY_PRINT] = XK_PRINT, 269 | [KEY_HP] = XK_HP, 270 | [KEY_CAMERA] = XK_CAMERA, 271 | [KEY_SOUND] = XK_SOUND, 272 | [KEY_QUESTION] = XK_QUESTION, 273 | [KEY_EMAIL] = XK_EMAIL, 274 | [KEY_CHAT] = XK_CHAT, 275 | [KEY_SEARCH] = XK_SEARCH, 276 | [KEY_CONNECT] = XK_CONNECT, 277 | [KEY_FINANCE] = XK_FINANCE, 278 | [KEY_SPORT] = XK_SPORT, 279 | [KEY_SHOP] = XK_SHOP, 280 | [KEY_ALTERASE] = XK_ALTERASE, 281 | [KEY_CANCEL] = XK_CANCEL, 282 | [KEY_BRIGHTNESSDOWN] = XK_BRIGHTNESSDOWN, 283 | [KEY_BRIGHTNESSUP] = XK_BRIGHTNESSUP, 284 | [KEY_MEDIA] = XK_MEDIA, 285 | [KEY_SWITCHVIDEOMODE] = XK_SWITCHVIDEOMODE, 286 | [KEY_KBDILLUMTOGGLE] = XK_KBDILLUMTOGGLE, 287 | [KEY_KBDILLUMDOWN] = XK_KBDILLUMDOWN, 288 | [KEY_KBDILLUMUP] = XK_KBDILLUMUP, 289 | [KEY_SEND] = XK_SEND, 290 | [KEY_REPLY] = XK_REPLY, 291 | [KEY_FORWARDMAIL] = XK_FORWARDMAIL, 292 | [KEY_SAVE] = XK_SAVE, 293 | [KEY_DOCUMENTS] = XK_DOCUMENTS, 294 | [KEY_BATTERY] = XK_BATTERY, 295 | [KEY_BLUETOOTH] = XK_BLUETOOTH, 296 | [KEY_WLAN] = XK_WLAN, 297 | [KEY_UWB] = XK_UWB, 298 | [KEY_UNKNOWN] = XK_UNKNOWN, 299 | [KEY_VIDEO_NEXT] = XK_VIDEO_NEXT, 300 | [KEY_VIDEO_PREV] = XK_VIDEO_PREV, 301 | [KEY_BRIGHTNESS_CYCLE] = XK_BRIGHTNESS_CYCLE, 302 | [KEY_BRIGHTNESS_ZERO] = XK_BRIGHTNESS_ZERO, 303 | [KEY_DISPLAY_OFF] = XK_DISPLAY_OFF, 304 | [KEY_WIMAX] = XK_WIMAX, 305 | [KEY_RFKILL] = XK_RFKILL, 306 | [KEY_MICMUTE] = XK_MICMUTE, 307 | #endif 308 | #endif 309 | }; 310 | 311 | 312 | static void 313 | read_one( 314 | int fd 315 | ) 316 | { 317 | const int max_evs = 8; 318 | struct input_event evs[max_evs]; 319 | const ssize_t rlen = read(fd, evs, sizeof(evs)); 320 | if (rlen < 0) 321 | die("read failed"); 322 | 323 | const int num_ev = rlen / sizeof(*evs); 324 | 325 | int mouse_valid = 0; 326 | int mx = 0; 327 | int my = 0; 328 | 329 | for (int i = 0 ; i < num_ev ; i++) 330 | { 331 | const struct input_event * const ev = &evs[i]; 332 | if (0) 333 | printf("%d: type=%02x code=%x val=%d\n", 334 | i, 335 | ev->type, 336 | ev->code, 337 | ev->value 338 | ); 339 | 340 | switch (ev->type) 341 | { 342 | case EV_SYN: 343 | case EV_MSC: 344 | break; 345 | case EV_REL: 346 | mouse_valid = 1; 347 | if (ev->code == REL_X) 348 | mx = ev->value; 349 | else 350 | if (ev->code == REL_Y) 351 | my = ev->value; 352 | else 353 | warn("EV_REL code=%d unhandled\n", ev->code); 354 | break; 355 | case EV_KEY: 356 | { 357 | int button = ev->code; 358 | int is_press = ev->value; 359 | if (button > 110) 360 | { 361 | button = (button & 0xF) + 1; 362 | XTestFakeButtonEvent(dpy, button, is_press, 0); 363 | } else { 364 | int key = keymap[button]; 365 | if (key != 0) 366 | XTestFakeKeyEvent(dpy, key, is_press, 0); 367 | else 368 | warn("EV_KEY code=%d->%d unhandled\n", ev->code, key); 369 | } 370 | break; 371 | } 372 | default: 373 | warn("type %d code=%d unhandled\n", ev->type, ev->code); 374 | break; 375 | } 376 | } 377 | 378 | if (mouse_valid) 379 | { 380 | // no screen argument? 381 | int rc = XTestFakeRelativeMotionEvent(dpy, mx, my, 0); 382 | } 383 | 384 | XFlush(dpy); 385 | } 386 | 387 | 388 | int 389 | main( 390 | int argc, 391 | char ** argv 392 | ) 393 | { 394 | dpy = XOpenDisplay(NULL); 395 | if (!dpy) 396 | die("Unable to open display\n"); 397 | 398 | const int num_fds = argc - 1; 399 | int * fds = calloc(sizeof(*fds), num_fds); 400 | int max_fd = 0; 401 | 402 | for (int i = 0 ; i < num_fds ; i++) 403 | { 404 | const char * const devname = argv[i+1]; 405 | const int fd = open(devname, O_RDONLY, 0666); 406 | if (fd < 0) 407 | die("%s: failed to open\n", devname); 408 | fds[i] = fd; 409 | 410 | printf("%s (fd %d)\n", devname, fd); 411 | if (fd > max_fd) 412 | max_fd = fd; 413 | } 414 | 415 | while (1) 416 | { 417 | fd_set read_fds; 418 | FD_ZERO(&read_fds); 419 | for (int i = 0 ; i < num_fds ; i++) 420 | { 421 | const int fd = fds[i]; 422 | FD_SET(fd, &read_fds); 423 | } 424 | 425 | int rc = select(max_fd+1, &read_fds, NULL, NULL, NULL); 426 | if (rc < 0) 427 | die("select\n"); 428 | 429 | for (int i = 0 ; i < num_fds ; i++) 430 | { 431 | const int fd = fds[i]; 432 | if (FD_ISSET(fd, &read_fds)) 433 | read_one(fd); 434 | } 435 | } 436 | } 437 | -------------------------------------------------------------------------------- /macboard.brd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | http://trmm.net/Mac-SE_video 127 | 2014-01-28 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | >NAME 565 | >VALUE 566 | >NAME 567 | >VALUE 568 | P8 569 | P9 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 4UCon #01528 668 | http://www.4uconnector.com/online/object/4udrawing/01528.pdf 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | >NAME 680 | + 681 | - 682 | 683 | 684 | 685 | 686 | <b>Molex Connectors</b><p> 687 | <author>Created by librarian@cadsoft.de</author> 688 | 689 | 690 | <b>Mini FIT connector 14 pol</b><p> 691 | Source: http://www.molex.com 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | >NAME 726 | >VALUE 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | <b>EAGLE Design Rules</b> 743 | <p> 744 | Die Standard-Design-Rules sind so gewählt, dass sie für 745 | die meisten Anwendungen passen. Sollte ihre Platine 746 | besondere Anforderungen haben, treffen Sie die erforderlichen 747 | Einstellungen hier und speichern die Design Rules unter 748 | einem neuen Namen ab. 749 | <b>EAGLE Design Rules</b> 750 | <p> 751 | The default Design Rules have been set to cover 752 | a wide range of applications. Your particular design 753 | may have different requirements, so please make the 754 | necessary adjustments and save your customized 755 | design rules under a new name. 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | 1095 | 1096 | 1097 | 1098 | 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1106 | 1107 | 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 | 1129 | 1130 | 1131 | 1132 | 1133 | 1134 | 1135 | 1136 | 1137 | 1138 | 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | -------------------------------------------------------------------------------- /macvideo.c: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Drive a Mac 128/Plus/SE video output. 3 | */ 4 | #include 5 | #include 6 | #include "pru.h" 7 | 8 | #define VRAM_WIDTH 512 9 | #define VRAM_HEIGHT 384 10 | 11 | void 12 | vram_set( 13 | void * const vram_ptr, 14 | int x, 15 | int y, 16 | int val 17 | ) 18 | { 19 | if (x < 0 || x >= VRAM_WIDTH) 20 | die("x %d", x); 21 | if (y < 0 || y >= VRAM_HEIGHT) 22 | die("y %d", y); 23 | 24 | // bits are read out MSB first 25 | const uint32_t bit = 1 << (x % 32); 26 | const uint8_t word = x / 32; 27 | volatile uint32_t * const vram = vram_ptr; 28 | 29 | volatile uint32_t * const p = &vram[word + y * VRAM_WIDTH/32]; 30 | if (val == 1) 31 | *p |= bit; 32 | else 33 | if (val == 0) 34 | *p &= ~bit; 35 | else 36 | if (val == -1) 37 | *p ^= bit; 38 | else 39 | die("set(%d,%d,%d)", x, y, val); 40 | 41 | if (0 && x < 8 && y == 0) 42 | printf("%d,%d, %02x => %d %p %08x\n", x, y, bit, val, p, *p); 43 | 44 | } 45 | 46 | #include "holly.xbm" 47 | 48 | int main(void) 49 | { 50 | pru_t * const pru = pru_init(0); 51 | 52 | uint32_t * const pru_cmd = pru->data_ram; 53 | uint8_t * const vram = pru->ddr; 54 | 55 | pru_gpio(0, 22, 1, 1); 56 | pru_gpio(0, 23, 1, 1); 57 | pru_gpio(0, 27, 1, 1); 58 | 59 | memset(vram, 0x00, VRAM_WIDTH*VRAM_HEIGHT/8); 60 | 61 | #if 1 62 | for (int y = 0 ; y < VRAM_HEIGHT/2 ; y++) 63 | { 64 | for (int x = 0 ; x < VRAM_WIDTH ; x++) 65 | { 66 | // Make a checkerboard 67 | uint8_t c = x ^ y; 68 | int y2 = y; 69 | while (y2 >>= 1) c >>= 1; 70 | 71 | vram_set(vram, x, y, c & 1); 72 | } 73 | } 74 | 75 | for (int y = VRAM_HEIGHT/2 ; y < VRAM_HEIGHT ; y++) 76 | { 77 | for (int x = 0 ; x < VRAM_WIDTH ; x++) 78 | { 79 | // Make a checkerboard 80 | vram_set(vram, x, y, ((x^y) >> 0) & 1); 81 | } 82 | } 83 | 84 | #if 0 85 | for (int x = 90 ; x < 200 ; x++) 86 | for (int y = 90 ; y < 150 ; y++) 87 | vram_set(vram, x, y, 1); 88 | #endif 89 | 90 | #if 0 91 | for (int x = 0 ; x < VRAM_WIDTH ; x++) 92 | { 93 | vram_set(vram, x, 0, 1); 94 | vram_set(vram, x, 1, 1); 95 | vram_set(vram, x, VRAM_HEIGHT-1, 1); 96 | vram_set(vram, x, VRAM_HEIGHT-2, 1); 97 | } 98 | for (int y = 0 ; y < VRAM_HEIGHT ; y++) 99 | { 100 | vram_set(vram, 0, y, 1); 101 | vram_set(vram, 1, y, 1); 102 | vram_set(vram, VRAM_WIDTH-1, y, 1); 103 | vram_set(vram, VRAM_WIDTH-2, y, 1); 104 | } 105 | #endif 106 | 107 | __asm__ __volatile__("dmb"); 108 | #else 109 | memcpy(vram, holly_bits, VRAM_WIDTH*VRAM_HEIGHT/8); 110 | for (int y = 0 ; y < VRAM_HEIGHT ; y++) 111 | { 112 | for (int x = 0 ; x < VRAM_WIDTH ; x++) 113 | { 114 | // invert the image 115 | vram_set(vram, x, y, -1); 116 | } 117 | } 118 | #endif 119 | 120 | pru_exec(pru, "./macvideo.bin"); 121 | printf("pru %p\n", pru); 122 | printf("cmd %p\n", pru_cmd); 123 | printf("ddr %p (%08x)\n", vram, pru->ddr_addr); 124 | 125 | #if 0 126 | for (int y = 0 ; y < VRAM_HEIGHT ; y++) 127 | { 128 | for (int x = 0 ; x < VRAM_WIDTH ; x += 8) 129 | { 130 | printf("%c", vram[x/8 + y*VRAM_WIDTH/8] ? 'X' : '_'); 131 | } 132 | printf("\n"); 133 | } 134 | #endif 135 | 136 | while (1) 137 | { 138 | *pru_cmd = pru->ddr_addr; 139 | usleep(1000); 140 | } 141 | 142 | return 0; 143 | } 144 | -------------------------------------------------------------------------------- /macvideo.p: -------------------------------------------------------------------------------- 1 | // \file 2 | /* PRU based Mac 128/Plus/SE video driver. 3 | * 4 | * The ARM writes a 1-bit color 512x384 bitmap into the shared RAM and the 5 | * PRU writes it to the video output continuously. 6 | * 7 | * During the horizontal blanking interval, the PRU loads an entire 512 8 | * bits of data (16x 32-bit registers). 9 | */ 10 | .origin 0 11 | .entrypoint START 12 | 13 | #include "ws281x.hp" 14 | 15 | /** Mappings of the GPIO devices */ 16 | #define GPIO0 (0x44E07000 + 0x100) 17 | #define GPIO1 (0x4804c000 + 0x100) 18 | #define GPIO2 (0x481AC000 + 0x100) 19 | #define GPIO3 (0x481AE000 + 0x100) 20 | 21 | /** Offsets for the clear and set registers in the devices. 22 | * Since the offsets can only be 0xFF, we deliberately add offsets 23 | */ 24 | #define GPIO_CLRDATAOUT (0x190 - 0x100) 25 | #define GPIO_SETDATAOUT (0x194 - 0x100) 26 | 27 | /** Register map */ 28 | #define data_addr r0 29 | #define row r1 30 | #define col r2 31 | #define video_pin r3 32 | #define hsync_pin r4 33 | #define vsync_pin r5 34 | #define gpio0_base r6 35 | #define sleep_counter r7 // how long to wait 36 | #define timer_ptr r8 37 | #define pixel_data r10 // the next 16 registers, too 38 | #define tmp1 r28 39 | #define tmp2 r29 40 | 41 | /** GPIO0 pin numbers for our outputs */ 42 | #define VIDEO_PIN 23 43 | #define HSYNC_PIN 27 44 | #define VSYNC_PIN 22 45 | 46 | #define VSYNC_LO SBBO vsync_pin, gpio0_base, GPIO_CLRDATAOUT, 4 47 | #define VSYNC_HI SBBO vsync_pin, gpio0_base, GPIO_SETDATAOUT, 4 48 | 49 | #define HSYNC_LO SBBO hsync_pin, gpio0_base, GPIO_CLRDATAOUT, 4 50 | #define HSYNC_HI SBBO hsync_pin, gpio0_base, GPIO_SETDATAOUT, 4 51 | 52 | #define VIDEO_LO SBBO video_pin, gpio0_base, GPIO_CLRDATAOUT, 4 53 | #define VIDEO_HI SBBO video_pin, gpio0_base, GPIO_SETDATAOUT, 4 54 | 55 | #define NOP ADD r0, r0, 0 56 | 57 | /** Wait for the cycle counter to reach a given value; we might 58 | * overshoot by a bit so we ensure that we always have the same 59 | * amount of overshoot. 60 | * 61 | * wake_time += ns; 62 | * while (now = read_timer()) < wake_time) 63 | * ; 64 | * if (now - wake_time < 1) 65 | * nop() 66 | */ 67 | #define WAITNS(ns,lab) \ 68 | MOV tmp1, (ns)/5; \ 69 | ADD sleep_counter, sleep_counter, tmp1; \ 70 | lab: ; \ 71 | LBBO tmp2, timer_ptr, 0xC, 4; /* read the cycle counter */ \ 72 | QBGT lab, tmp2, sleep_counter; \ 73 | SUB tmp2, tmp2, sleep_counter; \ 74 | QBLT lab##_2, tmp2, 1; \ 75 | NOP; \ 76 | lab##_2: ; \ 77 | 78 | 79 | 80 | START: 81 | // Enable OCP master port 82 | // clear the STANDBY_INIT bit in the SYSCFG register, 83 | // otherwise the PRU will not be able to write outside the 84 | // PRU memory space and to the BeagleBon's pins. 85 | LBCO r0, C4, 4, 4 86 | CLR r0, r0, 4 87 | SBCO r0, C4, 4, 4 88 | 89 | // Configure the programmable pointer register for PRU0 by setting 90 | // c28_pointer[15:0] field to 0x0120. This will make C28 point to 91 | // 0x00012000 (PRU shared RAM). 92 | MOV r0, 0x00000120 93 | MOV r1, CTPPR_0 94 | ST32 r0, r1 95 | 96 | // Configure the programmable pointer register for PRU0 by setting 97 | // c31_pointer[15:0] field to 0x0010. This will make C31 point to 98 | // 0x80001000 (DDR memory). 99 | MOV r0, 0x00100000 100 | MOV r1, CTPPR_1 101 | ST32 r0, r1 102 | 103 | // Write a 0x1 into the response field so that they know we have started 104 | MOV r2, #0x1 105 | SBCO r2, CONST_PRUDRAM, 12, 4 106 | 107 | MOV timer_ptr, 0x22000 /* control register */ 108 | 109 | // Configure our output pins 110 | MOV gpio0_base, GPIO0 111 | MOV video_pin, 1 << VIDEO_PIN 112 | MOV hsync_pin, 1 << HSYNC_PIN 113 | MOV vsync_pin, 1 << VSYNC_PIN 114 | 115 | VIDEO_HI 116 | HSYNC_HI 117 | VSYNC_HI 118 | 119 | // Wait for the start condition from the main program to indicate 120 | // that we have a rendered frame ready to clock out. This also 121 | // handles the exit case if an invalid value is written to the start 122 | // start position. 123 | READ_LOOP: 124 | // Load the pointer to the buffer from PRU DRAM into r0 and the 125 | // length (in pixels) into r1. 126 | LBCO data_addr, CONST_PRUDRAM, 0, 4 127 | 128 | // Wait for a non-zero command 129 | QBEQ READ_LOOP, data_addr, #0 130 | 131 | // Command of 0xFF is the signal to exit 132 | QBEQ EXIT, data_addr, #0xFF 133 | 134 | VSYNC_LO 135 | 136 | // Disable the counter and clear it, then re-enable it 137 | // This starts our clock at the start of the row. 138 | LBBO tmp2, timer_ptr, 0, 4 139 | CLR tmp2, tmp2, 3 // disable counter bit 140 | SBBO tmp2, timer_ptr, 0, 4 // write it back 141 | 142 | MOV r10, 0 143 | SBBO r10, timer_ptr, 0xC, 4 // clear the timer 144 | 145 | SET tmp2, tmp2, 3 // enable counter bit 146 | SBBO tmp2, timer_ptr, 0, 4 // write it back 147 | 148 | // Read the current counter value 149 | // Should be zero. 150 | LBBO sleep_counter, timer_ptr, 0xC, 4 151 | 152 | // the hsync pulse starts a bit after the vsync 153 | WAITNS(8000, wait_start) 154 | 155 | // the hsync keeps running at normal speed for 1.2 ms 156 | // 28 frames 157 | MOV row, 29 158 | VSYNC_LOOP: 159 | HSYNC_LO 160 | WAITNS(21500, wait_hsync1) 161 | HSYNC_HI 162 | WAITNS(21500, wait_hsync2) 163 | SUB row, row, 1 164 | QBNE hsync_skip, row, 25 165 | VSYNC_HI 166 | hsync_skip: 167 | QBNE VSYNC_LOOP, row, 0 168 | 169 | 170 | MOV row, 384 171 | 172 | ROW_LOOP: 173 | // start the new row 174 | HSYNC_LO 175 | 176 | // Load the sixteen pixels worth of data outputs into 177 | // This takes about 250 ns 178 | LBBO pixel_data, data_addr, 0, 512/8 179 | 180 | WAITNS(11200, wait_hsync) 181 | MOV col, 0 182 | 183 | 184 | #define OUTPUT_COLUMN(rN) \ 185 | QBBC clr_##rN, rN, col; \ 186 | VIDEO_LO; \ 187 | QBA skip_##rN; \ 188 | col_##rN: ; \ 189 | NOP; \ 190 | NOP; \ 191 | NOP; NOP; NOP; NOP; \ 192 | QBBC clr_##rN, rN, col; \ 193 | VIDEO_LO; \ 194 | QBA skip_##rN; \ 195 | clr_##rN:; \ 196 | NOP; \ 197 | VIDEO_HI; \ 198 | skip_##rN:; \ 199 | ADD col, col, 1; \ 200 | AND col, col, 31; \ 201 | QBNE col_##rN, col, 0; \ 202 | NOP; NOP; NOP; NOP; \ 203 | 204 | OUTPUT_COLUMN(r10); NOP; NOP; 205 | OUTPUT_COLUMN(r11); NOP; NOP; 206 | OUTPUT_COLUMN(r12); NOP; NOP; 207 | OUTPUT_COLUMN(r13); 208 | HSYNC_HI 209 | 210 | OUTPUT_COLUMN(r14); NOP; NOP; 211 | OUTPUT_COLUMN(r15); NOP; NOP; 212 | OUTPUT_COLUMN(r16); NOP; NOP; 213 | OUTPUT_COLUMN(r17); NOP; NOP; 214 | OUTPUT_COLUMN(r18); NOP; NOP; 215 | OUTPUT_COLUMN(r19); NOP; NOP; 216 | OUTPUT_COLUMN(r20); NOP; NOP; 217 | OUTPUT_COLUMN(r21); NOP; NOP; 218 | OUTPUT_COLUMN(r22); NOP; NOP; 219 | OUTPUT_COLUMN(r23); NOP; NOP; 220 | OUTPUT_COLUMN(r24); NOP; NOP; 221 | OUTPUT_COLUMN(r25); NOP; NOP; 222 | 223 | // Always return the video pin to a high state 224 | VIDEO_HI 225 | 226 | // Increment our data_offset to point to the next row 227 | ADD data_addr, data_addr, 512/8 228 | 229 | SUB row, row, 1 230 | 231 | /* 232 | QBNE hold_vsync_lo, row, 150 233 | VSYNC_HI 234 | hold_vsync_lo: 235 | */ 236 | 237 | // Be sure that we wait for the right length of time 238 | // Force each line to be 50 usec 239 | WAITNS(34000, wait_hsync_end) 240 | 241 | QBNE ROW_LOOP, row, 0 242 | WAITNS(5000, wait_hsync_end2) 243 | QBA READ_LOOP 244 | 245 | EXIT: 246 | #ifdef AM33XX 247 | // Send notification to Host for program completion 248 | MOV R31.b0, PRU0_ARM_INTERRUPT+16 249 | #else 250 | MOV R31.b0, PRU0_ARM_INTERRUPT 251 | #endif 252 | 253 | HALT 254 | -------------------------------------------------------------------------------- /start-xvfb: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | killall Xvfb x11mac eventmap 3 | 4 | Xvfb \ 5 | -retro \ 6 | -ac \ 7 | -screen 0 512x384x8 \ 8 | -fbdir /tmp/ \ 9 | +extension XTEST \ 10 | & 11 | 12 | sleep 5 13 | 14 | export DISPLAY=:0 15 | 16 | xterm -geometry +10+10 & 17 | xeyes -geometry -0-0 & 18 | 19 | ./x11mac /tmp/Xvfb_screen0 & 20 | ./eventmap /dev/input/event* & 21 | -------------------------------------------------------------------------------- /x11mac.c: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Drive a Mac 128/Plus/SE video output from the xvfb 3 | * 4 | * apt-get install x11proto-core-dev 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "pru.h" 16 | 17 | #define VRAM_WIDTH 512 18 | #define VRAM_HEIGHT 384 19 | 20 | static uint8_t threshold = 0x80; 21 | 22 | void 23 | fb_copy( 24 | void * const fb, 25 | const XWDFileHeader * const xfb 26 | ) 27 | { 28 | const XWDColor * const xfb_colors 29 | = (const void*)((uintptr_t) xfb) + be32toh(xfb->header_size); 30 | const uint8_t * const xfb_data 31 | = (const uint8_t*)(xfb_colors + be32toh(xfb->ncolors)); 32 | /* 33 | // \todo: What is the correct offset? 34 | const uint8_t * const xfb_data 35 | = ((const uint8_t*)xfb_colors) + be32toh(xfb->ncolors)+0x20; 36 | */ 37 | const size_t line_size = be32toh(xfb->bytes_per_line); 38 | 39 | static int first; 40 | if (first++ == 0) 41 | printf("offset %zx %zx\n", 42 | xfb_data - (const uint8_t*) xfb, 43 | ((const uint8_t*)xfb_colors) - (const uint8_t*) xfb 44 | ); 45 | 46 | //memset(fb, 0, VRAM_WIDTH*VRAM_HEIGHT/8); 47 | 48 | for (int y = 0 ; y < VRAM_HEIGHT ; y++) 49 | { 50 | const uint8_t * const xfb_row = xfb_data + y * line_size; 51 | uint8_t * const fb_row = ((uint8_t*)fb) + y * VRAM_WIDTH/8; 52 | 53 | for (int x = 0 ; x < VRAM_WIDTH ; x += 8) 54 | { 55 | uint8_t pix = 0; 56 | 57 | for (int x2 = 0 ; x2 < 8 ; x2++) 58 | { 59 | uint8_t p = xfb_row[(x + x2)]; 60 | #if 0 61 | const XWDColor * const c = &xfb_colors[p]; 62 | const uint16_t r = c->red; 63 | const uint16_t g = c->green; 64 | const uint16_t b = c->blue; 65 | const uint8_t n1 = be32toh(c->pixel); 66 | const uint8_t n2 = (r+g+b) / (3*256); 67 | if (x == 128 && x2 == 0 && y == 100) 68 | printf("%08x %08x %04x %04x %04x => %02x\n", 69 | p, 70 | n1, 71 | r, 72 | g, 73 | b, 74 | n2 75 | ); 76 | #else 77 | // fixed scale? 78 | if (p == 1) 79 | p = 0xFF; 80 | else 81 | if (p != 0) 82 | p = p - 1; 83 | #endif 84 | 85 | pix >>= 1; 86 | if (p > threshold) 87 | pix |= 0x80; 88 | } 89 | 90 | fb_row[x / 8] = pix; 91 | } 92 | } 93 | } 94 | 95 | 96 | 97 | int 98 | main( 99 | int argc, 100 | char ** argv 101 | ) 102 | { 103 | pru_t * const pru = pru_init(0); 104 | 105 | uint32_t * const pru_cmd = pru->data_ram; 106 | uint8_t * const vram = pru->ddr; 107 | 108 | pru_gpio(0, 22, 1, 1); 109 | pru_gpio(0, 23, 1, 1); 110 | pru_gpio(0, 27, 1, 1); 111 | 112 | const size_t fb_size = VRAM_WIDTH*VRAM_HEIGHT/8; 113 | memset(vram, 0x00, 2 * fb_size); 114 | void * const fb1 = vram + 0 * fb_size; 115 | void * const fb2 = vram + 1 * fb_size; 116 | const uintptr_t fb1_ddr = pru->ddr_addr + 0 * fb_size; 117 | const uintptr_t fb2_ddr = pru->ddr_addr + 1 * fb_size; 118 | 119 | pru_exec(pru, "./macvideo.bin"); 120 | printf("pru %p\n", pru); 121 | printf("cmd %p\n", pru_cmd); 122 | printf("ddr %p (%08x)\n", vram, pru->ddr_addr); 123 | 124 | if (argc <= 1) 125 | die("usage: %s /path/to/Xfb\n", argv[0]); 126 | const char * const xfb_name = argv[1]; 127 | int fd = open(xfb_name, O_RDONLY, 0666); 128 | if (fd < 0) 129 | die("%s: Unable to open\n", xfb_name); 130 | 131 | struct stat sb; 132 | if (fstat(fd, &sb) < 0) 133 | die("%s: Unable to stat\n", xfb_name); 134 | const size_t xfb_len = sb.st_size; 135 | 136 | //if (sb.st_size != VRAM_WIDTH*VRAM_HEIGHT) 137 | 138 | const XWDFileHeader * const xfb = mmap( 139 | NULL, 140 | xfb_len, 141 | PROT_READ, 142 | MAP_SHARED, 143 | fd, 144 | 0 145 | ); 146 | if (xfb == MAP_FAILED) 147 | die("%s: unable to map\n", xfb_name); 148 | close(fd); 149 | 150 | const char * const win_name = (const char *)(xfb + 1); 151 | const size_t line_size = be32toh(xfb->bytes_per_line); 152 | 153 | printf("XWD '%s' fmt=%d.%d.%d %dx%dx%d, %d colors @ %d, %zu bytes per line\n", 154 | win_name, 155 | be32toh(xfb->file_version), 156 | be32toh(xfb->pixmap_format), 157 | be32toh(xfb->visual_class), 158 | be32toh(xfb->pixmap_width), 159 | be32toh(xfb->pixmap_height), 160 | be32toh(xfb->pixmap_depth), 161 | be32toh(xfb->ncolors), 162 | be32toh(xfb->byte_order), 163 | line_size 164 | ); 165 | 166 | while (1) 167 | { 168 | fb_copy(fb1, xfb); 169 | *pru_cmd = fb1_ddr; 170 | usleep(30000); 171 | 172 | fb_copy(fb2, xfb); 173 | *pru_cmd = fb2_ddr; 174 | usleep(30000); 175 | } 176 | 177 | return 0; 178 | } 179 | -------------------------------------------------------------------------------- /xorg.conf: -------------------------------------------------------------------------------- 1 | Section "Device" 2 | Identifier "Frame Buffer" 3 | Driver "fbdev" 4 | EndSection 5 | --------------------------------------------------------------------------------