1
0

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Kai Ryu 2014-05-07 11:16:59 +09:00
commit f46568ca0a
28 changed files with 780 additions and 130 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "protocol/usb_hid/USB_Host_Shield_2.0"]
path = protocol/usb_hid/USB_Host_Shield_2.0
url = git@github.com:tmk/USB_Host_Shield_2.0.git
[submodule "protocol/lufa/LUFA-git"]
path = protocol/lufa/LUFA-git
url = https://github.com/abcminiuser/lufa.git

View File

@ -33,13 +33,15 @@ You can find some keyboard specific projects under `converter` and `keyboard` di
### converter
* [ps2_usb](converter/ps2_usb/) - [PS/2 keyboard to USB][GH_ps2]
* [adb_usb](converter/adb_usb/) - [ADB keyboard to USB][GH_adb]
* [m0110_usb](converter/m0110_usb) - [Machintosh 128K/512K/Plus keyboard to USB][GH_m0110]
* [m0110_usb](converter/m0110_usb) - [Macintosh 128K/512K/Plus keyboard to USB][GH_m0110]
* [terminal_usb](converter/terminal_usb/) - [IBM Model M terminal keyboard(PS/2 scancode set3) to USB][GH_terminal]
* [news_usb](converter/news_usb/) - [Sony NEWS keyboard to USB][GH_news]
* [x68k_usb](converter/x68k_usb/) - [Sharp X68000 keyboard to USB][GH_x68k]
* [sun_usb](converter/sun_usb/) - [Sun] to USB(type4, 5 and 3?)
* [pc98_usb](converter/pc98_usb/) - [PC98] to USB
* [usb_usb](converter/usb_usb/) - USB to USB(experimental)
* [ascii_usb](converter/ascii_usb/) - ASCII(Serial console terminal) to USB
* [ibm4704_usb](converter/ibm4704_usb) - [IBM 4704 keyboard Converter][GH_ibm4704]
### keyboard
* [hhkb](keyboard/hhkb/) - [Happy Hacking Keyboard pro][GH_hhkb] **my main board**
@ -50,6 +52,7 @@ You can find some keyboard specific projects under `converter` and `keyboard` di
* [IIgs_Standard](keyboard/IIgs/) - Apple [IIGS] keyboard mod(by JeffreySung)
* [macway](keyboard/macway/) - [Compact keyboard mod][GH_macway] [retired]
* [KMAC](keyboard/kmac/) - Korean custom keyboard
* [Lightsaber](keyboard/lightsaber/) - Korean custom keyboard
[GH_macway]: http://geekhack.org/showwiki.php?title=Island:11930
[GH_hhkb]: http://geekhack.org/showwiki.php?title=Island:12047
@ -61,6 +64,7 @@ You can find some keyboard specific projects under `converter` and `keyboard` di
[GH_terminal]: http://geekhack.org/showwiki.php?title=Island:27272
[GH_x68k]: http://geekhack.org/showwiki.php?title=Island:29060
[GH_hbkb]: http://geekhack.org/showwiki.php?title=Island:29483
[GH_ibm4704]: http://geekhack.org/index.php?topic=54706.0
[HID_liber]: http://deskthority.net/wiki/HID_Liberation_Device_-_DIY_Instructions
[Phantom]: http://geekhack.org/index.php?topic=26742
[GH60]: http://geekhack.org/index.php?topic=34959
@ -90,7 +94,7 @@ See [doc/keymap.md](doc/keymap.md).
Magic Comannds
Magic Commands
--------------
To see help press `Magic` + `H`.
@ -121,7 +125,7 @@ Following commands can be also executed with `Magic` + key. In console mode `Mag
**TBD**
### Boot Magic Configuration - Virtual DIP Switch
Boot Magic are executed during boot up time. Press Magic key below then pulgin keyboard cable.
Boot Magic are executed during boot up time. Press Magic key below then plug in keyboard cable.
Note that you must use keys of **Layer 0** as Magic keys. These settings are stored in EEPROM so that retain your configure over power cycles.
To avoid configuring accidentally additive salt key `KC_SPACE` also needs to be pressed along with the following configuration keys. The salt key is configurable in `config.h`. See [common/bootmagic.h](common/bootmagic.h).
@ -141,7 +145,7 @@ To avoid configuring accidentally additive salt key `KC_SPACE` also needs to be
#### Keymap
- Swap Control and CapsLock(`Left Control`)
- Change CapsLock to Control(`Casp Lock`)
- Change CapsLock to Control(`Caps Lock`)
- Swap LeftAlt and Gui(`Left Alt`)
- Swap RightAlt and Gui(`Right Alt`)
- Disable Gui(`Left Gui`)
@ -210,7 +214,7 @@ Architecture
Debuging
Debugging
--------
Use PJRC's `hid_listen` to see debug messages. You can use the tool for debug even if firmware use LUFA stack.
@ -227,7 +231,7 @@ Files and Directories
* converter/ - protocol converter projects
* doc/ - documents
* common.mk - Makefile for common
* protoco.mk - Makefile for protocol
* protocol.mk - Makefile for protocol
* rules.mk - Makefile for build rules
### Common
@ -263,7 +267,7 @@ Files and Directories
Conding Style
Coding Style
-------------
- Doesn't use Tab to indent, use 4-spaces instead.

View File

@ -294,7 +294,7 @@ void process_action(keyrecord_t *record)
#ifdef BACKLIGHT_ENABLE
case ACT_BACKLIGHT:
if (!event.pressed) {
switch (action.backlight.id) {
switch (action.backlight.opt) {
case BACKLIGHT_INCREASE:
backlight_increase();
break;
@ -307,6 +307,9 @@ void process_action(keyrecord_t *record)
case BACKLIGHT_STEP:
backlight_step();
break;
case BACKLIGHT_LEVEL:
backlight_level(action.backlight.level);
break;
}
}
break;

View File

@ -87,7 +87,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* 1100|1111| id(8) Macro record?
*
* ACT_BACKLIGHT(1101):
* 1101|xxxx| id(8) Backlight commands
* 1101|opt |level(8) Backlight commands
*
* ACT_COMMAND(1110):
* 1110|opt | id(8) Built-in Command exec
@ -163,7 +163,9 @@ typedef union {
uint8_t kind :4;
} usage;
struct action_backlight {
uint8_t id :8;
uint8_t level :8;
uint8_t opt :4;
uint8_t kind :4;
} backlight;
struct action_command {
uint8_t id :8;
@ -282,21 +284,23 @@ enum layer_pram_tap_op {
/*
* Extensions
*/
enum backlight_id {
enum backlight_opt {
BACKLIGHT_INCREASE = 0,
BACKLIGHT_DECREASE = 1,
BACKLIGHT_TOGGLE = 2,
BACKLIGHT_STEP = 3,
BACKLIGHT_LEVEL = 4,
};
/* Macro */
#define ACTION_MACRO(id) ACTION(ACT_MACRO, (id))
#define ACTION_MACRO_TAP(id) ACTION(ACT_MACRO, FUNC_TAP<<8 | (id))
#define ACTION_MACRO_OPT(id, opt) ACTION(ACT_MACRO, (opt)<<8 | (id))
/* Backlight */
#define ACTION_BACKLIGHT_INCREASE() ACTION(ACT_BACKLIGHT, BACKLIGHT_INCREASE)
#define ACTION_BACKLIGHT_DECREASE() ACTION(ACT_BACKLIGHT, BACKLIGHT_DECREASE)
#define ACTION_BACKLIGHT_TOGGLE() ACTION(ACT_BACKLIGHT, BACKLIGHT_TOGGLE)
#define ACTION_BACKLIGHT_STEP() ACTION(ACT_BACKLIGHT, BACKLIGHT_STEP)
#define ACTION_BACKLIGHT_INCREASE() ACTION(ACT_BACKLIGHT, BACKLIGHT_INCREASE << 8)
#define ACTION_BACKLIGHT_DECREASE() ACTION(ACT_BACKLIGHT, BACKLIGHT_DECREASE << 8)
#define ACTION_BACKLIGHT_TOGGLE() ACTION(ACT_BACKLIGHT, BACKLIGHT_TOGGLE << 8)
#define ACTION_BACKLIGHT_STEP() ACTION(ACT_BACKLIGHT, BACKLIGHT_STEP << 8)
#define ACTION_BACKLIGHT_LEVEL(level) ACTION(ACT_BACKLIGHT, BACKLIGHT_LEVEL << 8 | level)
/* Command */
#define ACTION_COMMAND(id, opt) ACTION(ACT_COMMAND, (opt)<<8 | (addr))
/* Function */

View File

@ -16,6 +16,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <util/delay.h>
#include "action.h"
#include "action_util.h"
#include "action_macro.h"
#ifdef DEBUG_ACTION
@ -39,12 +40,20 @@ void action_macro_play(const macro_t *macro_p)
case KEY_DOWN:
MACRO_READ();
dprintf("KEY_DOWN(%02X)\n", macro);
register_code(macro);
if (IS_MOD(macro)) {
add_weak_mods(MOD_BIT(macro));
} else {
register_code(macro);
}
break;
case KEY_UP:
MACRO_READ();
dprintf("KEY_UP(%02X)\n", macro);
unregister_code(macro);
if (IS_MOD(macro)) {
del_weak_mods(MOD_BIT(macro));
} else {
unregister_code(macro);
}
break;
case WAIT:
MACRO_READ();

View File

@ -104,3 +104,11 @@ void backlight_step(void)
dprintf("backlight step: %u\n", backlight_config.level);
backlight_set(backlight_config.level);
}
void backlight_level(uint8_t level)
{
backlight_config.level ^= level;
backlight_config.enable = !!backlight_config.level;
eeconfig_write_backlight(backlight_config.raw);
backlight_set(backlight_config.level);
}

View File

@ -24,18 +24,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
typedef union {
uint8_t raw;
struct {
bool enable:1;
uint8_t level:7;
bool enable :1;
uint8_t level :7;
};
} backlight_config_t;
void backlight_init(void);
void backlight_increase(void);
void backlight_decrease(void);
void backlight_toggle(void);
void backlight_step(void);
void backlight_set(uint8_t level);
void backlight_level(uint8_t level);
#endif

View File

@ -301,13 +301,13 @@ static bool command_common(uint8_t code)
case KC_S:
print("\n\n----- Status -----\n");
print_val_hex8(host_keyboard_leds());
print_val_hex8(keyboard_protocol);
print_val_hex8(keyboard_idle);
#ifdef PROTOCOL_PJRC
print_val_hex8(UDCON);
print_val_hex8(UDIEN);
print_val_hex8(UDINT);
print_val_hex8(usb_keyboard_leds);
print_val_hex8(usb_keyboard_protocol);
print_val_hex8(usb_keyboard_idle_config);
print_val_hex8(usb_keyboard_idle_count);
#endif

View File

@ -24,7 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef NKRO_ENABLE
bool keyboard_nkro = false;
bool keyboard_nkro = true;
#endif
static host_driver_t *driver;

View File

@ -32,6 +32,9 @@ extern "C" {
extern bool keyboard_nkro;
#endif
uint8_t keyboard_idle;
uint8_t keyboard_protocol;
/* host driver */
void host_set_driver(host_driver_t *driver);

View File

@ -94,6 +94,26 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
extern "C" {
#endif
/*
* keyboard report is 8-byte array retains state of 8 modifiers and 6 keys.
*
* byte |0 |1 |2 |3 |4 |5 |6 |7
* -----+--------+--------+--------+--------+--------+--------+--------+--------
* desc |mods |reserved|keys[0] |keys[1] |keys[2] |keys[3] |keys[4] |keys[5]
*
* It is exended to 16 bytes to retain 120keys+8mods when NKRO mode.
*
* byte |0 |1 |2 |3 |4 |5 |6 |7 ... |15
* -----+--------+--------+--------+--------+--------+--------+--------+-------- +--------
* desc |mods |bits[0] |bits[1] |bits[2] |bits[3] |bits[4] |bits[5] |bits[6] ... |bit[14]
*
* mods retains state of 8 modifiers.
*
* bit |0 |1 |2 |3 |4 |5 |6 |7
* -----+--------+--------+--------+--------+--------+--------+--------+--------
* desc |Lcontrol|Lshift |Lalt |Lgui |Rcontrol|Rshift |Ralt |Rgui
*
*/
typedef union {
uint8_t raw[REPORT_SIZE];
struct {

View File

@ -14,7 +14,7 @@ dfj's NKRO(2010/06)
http://geekhack.org/showthread.php?p=204389#post204389
Terminogy
Terminology
---------
NKRO
ghost
@ -26,7 +26,7 @@ membrane
OS Support Status
-----------------
USB NKRO is possible *without* a custom driver.
At least following OSes supports.
At least following OS's supports.
Windows7 64bit
WindowsXP
Windows2000 SP4
@ -37,7 +37,7 @@ At least following OSes supports.
Custom Driver for USB NKRO
--------------------------
NOT NEEDED
at least when using fllowing report formats on Windows, Linux or MacOSX.
at least when using following report formats on Windows, Linux or MacOSX.
USB NKRO methods
@ -47,8 +47,8 @@ USB NKRO methods
If the keyboard has 2 virtual keyboard with Standard report(6KRO), it gets 12KRO.
Using this method means the keyboard is a composite device.
2. Exteded report
It needs large report size for this method to achive NKRO.
2. Extended report
It needs large report size for this method to achieve NKRO.
If a keyboard has 101keys, it needs 103byte report. It seems to be inefficient.
3. Bitmap report
@ -122,8 +122,8 @@ Considerations
Compatibility
boot protocol
minor/old system
Some BIOS doesn't send SET_PROTCOL request, a keyboard can't switch to boot protocol mode.
This may cuase a problem on a keyboard which uses other report than Standard.
Some BIOS doesn't send SET_PROTOCOL request, a keyboard can't switch to boot protocol mode.
This may cause a problem on a keyboard which uses other report than Standard.
Reactivity
USB polling time
OS/Driver processing time

View File

@ -40,7 +40,7 @@ Move to project directory in the firmware source.
Build firmware using GNU `make` command. You'll see `<project>_<variant>.hex` file in that directory unless something unexpected occurs in build process.
mkae -f Makefile.<variant> clean
make -f Makefile.<variant> clean
make -f Makefile.<variant>
@ -71,14 +71,14 @@ Or to program with `dfu-programmer` run:
#### FLIP GUI tutorial
1. On menu bar click Device -> Select, then. `ATmega32u4`.
2. On menu bar click Settings -> Communication -> USB, then click 'Open' button on 'USB Port Connection' dialog.
At this point you'll see greyouted widgets on the app get colored and ready.
At this point you'll see grey-outed widgets on the app get colored and ready.
3. On menu bar click File -> Load HEX File, then select your firmware hex file on File Selector dialog.
4. On 'Operations Flow' panel click 'Run' button to load the firmware binary to the chip. Note that you should keep 'Erase', 'Blank Check', 'Program' and 'Verify' check boxes selected.
5. Re-plug USB cord or click 'Start Application' button to restart your controller.
Done.
See also these instaructions if you need.
See also these instructions if you need.
- <http://code.google.com/p/micropendous/wiki/LoadingFirmwareWithFLIP>
- <http://www.atmel.com/Images/doc7769.pdf>
@ -95,7 +95,7 @@ Or use this command if you have command line version of Teensy Loader installed.
### 4. Program with Other programmer
You may want to use other programmer like `avrdude` with AVRISPmkII, Aruduino or USBasp. In that case you can still use make target `program` for build with configuring `PROGRAM_CMD` in Makefile.
You may want to use other programmer like `avrdude` with AVRISPmkII, Arduino or USBasp. In that case you can still use make target `program` for build with configuring `PROGRAM_CMD` in Makefile.
$ make -f Makefile.<variant> program
@ -135,7 +135,7 @@ Optional. Note that ***comment out*** to disable them.
#BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality
### 3. Programmer
Optional. Set proper command for your controller, bootloader and programmer. This command can be used with `make program`. Not needed if you use `FLIP`, `dfu-programmer` or `Teesy Loader`.
Optional. Set proper command for your controller, bootloader and programmer. This command can be used with `make program`. Not needed if you use `FLIP`, `dfu-programmer` or `Teensy Loader`.
# avrdude with AVRISPmkII
PROGRAM_CMD = avrdude -p $(MCU) -c avrispmkII -P USB -U flash:w:$(TARGET).hex
@ -158,7 +158,7 @@ Config.h Options
/* Mechanical locking CapsLock support. Use KC_LCAP instead of KC_CAPS in keymap */
#define CAPSLOCK_LOCKING_ENABLE
/* Locking CapsLock resynchronize hack */
/* Locking CapsLock re-synchronize hack */
#define CAPSLOCK_LOCKING_RESYNC_ENABLE
### 3. Disable Debug and Print

View File

@ -68,7 +68,7 @@ On the other hand, you shall change `layer_state` to overlay base layer with som
Note that ***higher layer has higher priority on stack of layers***, namely firmware falls down from top layer to bottom to look up keycode. Once it spots keycode other than **`KC_TRNS`**(transparent) on a layer it stops searching and lower layers aren't referred.
You can place `KC_TRNS` on overlay layer changes just part of layout to fall back on lower or base layer.
Key with `KC_TRANS` doen't has its own keycode and refers to lower valid layers for keycode, instead.
Key with `KC_TRANS` doesn't has its own keycode and refers to lower valid layers for keycode, instead.
See example below.
@ -155,12 +155,12 @@ You can find other keymap definitions in file `keymap.c` located on project dire
## 1. Keycode
See [`common/keycode.h`](../common/keycode.h) or keycode table below for the detail. Keycode is internal **8bit code** to inidicate action performed on key in keymap. Keycode has `KC_` prefixed symbol respectively. Most of keycodes like `KC_A` have simple action registers key to host on press and unregister on release, while some of other keycodes has some special actions like `Fn` keys, Media contorl keys, System control keys and Mousekeys.
See [`common/keycode.h`](../common/keycode.h) or keycode table below for the detail. Keycode is internal **8bit code** to indicate action performed on key in keymap. Keycode has `KC_` prefixed symbol respectively. Most of keycodes like `KC_A` have simple action registers key to host on press and unregister on release, while some of other keycodes has some special actions like `Fn` keys, Media control keys, System control keys and Mousekeys.
***In `KEYMAP()` macro you should omit prefix part `KC_` of keycode to keep keymap compact.*** For example, just use `A` instead you place `KC_A` in `KEYMAP()`. Some keycodes has 4-letter **short name** in addition to descriptive name, you'll prefer short one in `KEYMAP()`.
### 1.0 Other key
- `KC_NO` for no aciton
- `KC_NO` for no action
- `KC_TRNS` for layer transparency (See above)
### 1.1 Normal key
@ -192,7 +192,7 @@ There are 8 modifiers which has discrimination between left and right.
- `KC_WSCH`, `KC_WHOM`, `KC_WBAK`, `KC_WFWD`, `KC_WSTP`, `KC_WREF`, `KC_WFAV` for web browser operation
### 1.5 Fn key
`KC_FNnn` are keycodes for `Fn` key which not given any actions at the beginning unlike most of keycodes has its own inborn action. To use these keycodes in `KEYMAP()` you need to assign action you want at first. Action of `Fn` key is defined in `fn_actions[]` and its index of the array is identical with number part of `KC_FNnn`. Thus `KC_FN0` keyocde indicates the action defined in first element of the array. ***32 `Fn` keys can be defined at most.***
`KC_FNnn` are keycodes for `Fn` key which not given any actions at the beginning unlike most of keycodes has its own inborn action. To use these keycodes in `KEYMAP()` you need to assign action you want at first. Action of `Fn` key is defined in `fn_actions[]` and its index of the array is identical with number part of `KC_FNnn`. Thus `KC_FN0` keycode indicates the action defined in first element of the array. ***32 `Fn` keys can be defined at most.***
### 1.6 Keycode Table
See keycode table in [`doc/keycode.txt`](./keycode.txt) for description of keycodes.
@ -205,7 +205,7 @@ There are 8 modifiers which has discrimination between left and right.
## 2. Action
See [`common/action_code.h`](../common/action_code.h). Action is a **16bit code** and defines function to perform on events of a key like press, release, holding and tapping.
Most of keys just register 8bit scancode to host, but to support other complex features needs 16bit extended action codes internally. However, using 16bit action codes in keymap results in double size in memory compared to using jsut keycodes. To avoid this waste 8bit keycodes are used in `KEYMAP()` instead of action codes.
Most of keys just register 8bit scancode to host, but to support other complex features needs 16bit extended action codes internally. However, using 16bit action codes in keymap results in double size in memory compared to using just keycodes. To avoid this waste 8bit keycodes are used in `KEYMAP()` instead of action codes.
***You can just use keycodes of `Normal key`, `Modifier`, `Mousekey` and `System & Media key` in keymap*** to indicate corresponding actions instead of using action codes. While ***to use other special actions you should use keycode of `Fn` key defined in `fn_actions[]`.***
@ -230,7 +230,7 @@ You can define these actions on *'A'* key and *'left shift'* modifier with:
#### 2.1.2 Modified key
This action is comprised of strokes of modifiers and a key. `Macro` action is needed if you want more complex key strokes.
Say you want to assign a key to `Shift + 1` to get charactor *'!'* or `Alt + Tab` to switch application windows.
Say you want to assign a key to `Shift + 1` to get character *'!'* or `Alt + Tab` to switch application windows.
ACTION_MODS_KEY(MOD_LSFT, KC_1)
ACTION_MODS_KEY(MOD_LALT, KC_TAB)
@ -269,10 +269,10 @@ Default Layer is a layer which always is valid and referred to when actions is n
This sets Default Layer to given parameter `layer` and activate it.
ACTION_DEFAULT_LAYER(layer)
ACTION_DEFAULT_LAYER_SET(layer)
#### 2.2.2 Momentary Switch
#### 2.2.2 Momentary
Turns on `layer` momentarily while holding, in other words it activates when key is pressed and deactivate when released.
ACTION_LAYER_MOMENTARY(layer)
@ -342,7 +342,7 @@ Turns on layer only and clear all layer on release..
ACTION_LAYER_BIT_XOR(part, bits, on)
ACTION_LAYER_BIT_SET(part, bits, on)
These actions works with prameters as following code.
These actions works with parameters as following code.
uint8_t shift = part*4;
uint32_t mask = (bits&0x10) ? ~(0xf<<shift) : 0;
@ -368,7 +368,7 @@ Default Layer also has bitwise operations, they are executed when key is release
MACRO( I(255), T(H), T(E), T(L), T(L), W(255), T(O), END )
#### 2.3.1 Macro Commands
- **I()** change interavl of stroke.
- **I()** change interval of stroke.
- **D()** press key
- **U()** release key
- **T()** type key(press and release)
@ -377,7 +377,7 @@ Default Layer also has bitwise operations, they are executed when key is release
#### 2.3.2 Examples
***TODO: sample impl***
***TODO: sample implementation***
See `keyboard/hhkb/keymap.c` for sample.
@ -403,7 +403,7 @@ To define tappable `Function` action in keymap use this.
void keymap_call_function(keyrecord_t *event, uint8_t id, uint8_t opt)
This C function is called every time key is operated, argument `id` selects action to be performed and `opt` can be used for option. Functon `id` can be 0-255 and `opt` can be 0-15.
This C function is called every time key is operated, argument `id` selects action to be performed and `opt` can be used for option. Function `id` can be 0-255 and `opt` can be 0-15.
`keyrecord_t` is comprised of key event and tap count. `keyevent_t` indicates which and when key is pressed or released. From `tap_count` you can know tap state, 0 means no tap. These information will be used in user function to decide how action of key is performed.
@ -423,7 +423,7 @@ This C function is called every time key is operated, argument `id` selects acti
uint8_t row;
} key_t;
***TODO: sample impl***
***TODO: sample implementation***
See `keyboard/hhkb/keymap.c` for sample.
@ -444,6 +444,10 @@ Step through backlight levels.
ACTION_BACKLIGHT_STEP()
Turn a specific backlight level on or off.
ACTION_BACKLIGHT_LEVEL(1)
#### 2.5.2 Turn on / off backlight
Turn the backlight on and off without changing level.
@ -462,8 +466,8 @@ This action makes 'Layer 1' active(valid) on key press event and inactive on rel
ACTION_LAYER_MOMENTARY(1)
Note that after switching on press the actions on destinaton layer(Layer 1) are perfomed.
***Thus you shall need to place an action to go back on destination layer***, or you will be stuck in destination layer without way to get back. Usually you need to palce same action or 'KC_TRNS` on destination layer to get back.
Note that after switching on press the actions on destination layer(Layer 1) are performed.
***Thus you shall need to place an action to go back on destination layer***, or you will be stuck in destination layer without way to get back. Usually you need to place same action or 'KC_TRNS` on destination layer to get back.
### 3.2 Toggle switching
@ -480,7 +484,7 @@ These actions switch a layer only while holding a key but register the key on ta
ACTION_LAYER_TAP_KEY(2, KC_SCLN)
With this you can place a layer switching action on normal key like ';' without losing its original key register function. This action allows you to have layer switchig action without necessity of a dedicated key. It means you can have it even on home row of keyboard.
With this you can place a layer switching action on normal key like ';' without losing its original key register function. This action allows you to have layer switching action without necessity of a dedicated key. It means you can have it even on home row of keyboard.
@ -511,17 +515,17 @@ Layer switching with tap key:
### 4.2 Tap Toggle
This is a feature to assign both toggle layer and momentary switch layer action to just same one physical key. It works as mementary layer switch when holding a key but toggle switch with several taps.
This is a feature to assign both toggle layer and momentary switch layer action to just same one physical key. It works as momentary layer switch when holding a key but toggle switch with several taps.
ACTION_LAYER_TAP_TOGGLE(1)
### 4.3 Oneshot Modifier
This runs onetime effect swhich modify only on just one following key. It works as normal modifier key when holding down while oneshot modifier when tapping.
This runs onetime effects which modify only on just one following key. It works as normal modifier key when holding down while oneshot modifier when tapping.
ACTION_MODS_ONESHOT(MOD_LSFT)
Say you want to type 'The', you have to push and hold Shift key before type 't' then release it before type 'h' and 'e', otherwise you'll get 'THe' or 'the' unintentionally. With Oneshot Modifier you can tap Shift then type 't', 'h' and 'e' normally, you don't need to holding Shift key properly here. This mean you can realease Shift before 't' is pressed down.
Say you want to type 'The', you have to push and hold Shift key before type 't' then release it before type 'h' and 'e', otherwise you'll get 'THe' or 'the' unintentionally. With Oneshot Modifier you can tap Shift then type 't', 'h' and 'e' normally, you don't need to holding Shift key properly here. This mean you can release Shift before 't' is pressed down.
Oneshot effect is cancel unless following key is pressed down within `ONESHOT_TIMEOUT` of `config.h`. No timeout when it is `0` or not defined.

View File

@ -48,7 +48,7 @@ Other Keyboard Firmware Projects
- <http://geekhack.org/index.php?topic=19458.0>
## kbdbabel.org[converter][vintage][protocol][8051]
Great resourse of vintage keyboard protocol information and code
Great resource of vintage keyboard protocol information and code
- <http://www.kbdbabel.org/>

169
protocol/ibm4704.c Normal file
View File

@ -0,0 +1,169 @@
/*
Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
*/
#include <stdbool.h>
#include <util/delay.h>
#include "debug.h"
#include "ibm4704.h"
#define WAIT(stat, us, err) do { \
if (!wait_##stat(us)) { \
ibm4704_error = err; \
goto ERROR; \
} \
} while (0)
uint8_t ibm4704_error = 0;
void ibm4704_init(void)
{
inhibit();
}
/*
Host to Keyboard
----------------
Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
____ __ __ __ __ __ __ __ __ __ ________
Clock \______/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
^ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___
Data ____|__/ X____X____X____X____X____X____X____X____X____X \___
| Start 0 1 2 3 4 5 6 7 P Stop
Request by host
Start bit: can be long as 300-350us.
Request: Host pulls Clock line down to request to send a command.
Timing: After Request keyboard pull up Data and down Clock line to low for start bit.
After request host release Clock line once Data line becomes hi.
Host writes a bit while Clock is hi and Keyboard reads while low.
Stop bit: Host releases or pulls up Data line to hi after 9th clock and waits for keyboard pull down the line to lo.
*/
uint8_t ibm4704_send(uint8_t data)
{
bool parity = true; // odd parity
ibm4704_error = 0;
/* Request to send */
idle();
clock_lo();
/* wait for Start bit(Clock:lo/Data:hi) */
WAIT(data_hi, 300, 0x30);
/* Data bit */
for (uint8_t i = 0; i < 8; i++) {
WAIT(clock_hi, 100, 0x40+i);
//_delay_us(5);
if (data&(1<<i)) {
parity = !parity;
data_hi();
} else {
data_lo();
}
WAIT(clock_lo, 100, 0x48+i);
}
/* Parity bit */
WAIT(clock_hi, 100, 0x34);
if (parity) { data_hi(); } else { data_lo(); }
WAIT(clock_lo, 100, 0x35);
/* Stop bit */
WAIT(clock_hi, 100, 0x34);
data_hi();
/* End */
WAIT(data_lo, 100, 0x36);
inhibit();
_delay_us(200); // wait to recover clock to hi
return 0;
ERROR:
inhibit();
if (ibm4704_error >= 0x30) {
xprintf("x%02X ", ibm4704_error);
}
_delay_us(200); // wait to recover clock to hi
return -1;
}
/* receive data when host want else inhibit communication */
uint8_t ibm4704_recv_response(void)
{
// 250 * 100us(wait start bit in ibm4704_recv)
uint8_t data = 0;
uint8_t try = 250;
do {
data = ibm4704_recv();
} while (try-- && ibm4704_error);
return data;
}
/*
Keyboard to Host
----------------
Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
____ __ __ __ __ __ __ __ __ __ ________
Clock \____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
____ ____ ____ ____ ____ ____ ____ ____ ____ ____
Data ____/ X____X____X____X____X____X____X____X____X____X________
Start 0 1 2 3 4 5 6 7 P Stop
Start bit: can be long as 300-350us.
Inhibit: Pull Data line down to inhibit keyboard to send.
Timing: Host reads bit while Clock is hi.
Stop bit: Keyboard pulls down Data line to lo after 9th clock.
*/
uint8_t ibm4704_recv(void)
{
uint8_t data = 0;
bool parity = true; // odd parity
ibm4704_error = IBM4704_ERR_NONE;
idle();
_delay_us(5); // wait for line settles
/* start bit */
WAIT(clock_lo, 100, 0x11); // wait for keyboard to send
WAIT(data_hi, 100, 0x12); // can be delayed that long
WAIT(clock_hi, 100, 0x13); // first rising edge which can take longer
/* data */
for (uint8_t i = 0; i < 8; i++) {
WAIT(clock_hi, 100, 0x20+i);
//_delay_us(5);
if (data_in()) {
parity = !parity;
data |= (1<<i);
}
WAIT(clock_lo, 150, 0x28+i);
}
/* parity */
WAIT(clock_hi, 100, 0x17);
if (data_in() != parity) {
ibm4704_error = IBM4704_ERR_PARITY;
goto ERROR;
}
WAIT(clock_lo, 150, 0x18);
/* stop bit */
WAIT(clock_hi, 100, 0x19);
WAIT(data_lo, 1, 0x19);
inhibit();
_delay_us(200); // wait to recover clock to hi
return data;
ERROR:
if (ibm4704_error > 0x12) {
xprintf("x%02X ", ibm4704_error);
}
inhibit();
_delay_us(200); // wait to recover clock to hi
return -1;
}

110
protocol/ibm4704.h Normal file
View File

@ -0,0 +1,110 @@
/*
Copyright 2014 Jun WAKO <wakojun@gmail.com>
*/
#ifndef IBM4704_H
#define IBM4704_H
#define IBM4704_ERR_NONE 0
#define IBM4704_ERR_PARITY 0x70
void ibm4704_init(void);
uint8_t ibm4704_send(uint8_t data);
uint8_t ibm4704_recv_response(void);
uint8_t ibm4704_recv(void);
/* Check pin configuration */
#if !(defined(IBM4704_CLOCK_PORT) && \
defined(IBM4704_CLOCK_PIN) && \
defined(IBM4704_CLOCK_DDR) && \
defined(IBM4704_CLOCK_BIT))
# error "ibm4704 clock pin configuration is required in config.h"
#endif
#if !(defined(IBM4704_DATA_PORT) && \
defined(IBM4704_DATA_PIN) && \
defined(IBM4704_DATA_DDR) && \
defined(IBM4704_DATA_BIT))
# error "ibm4704 data pin configuration is required in config.h"
#endif
/*--------------------------------------------------------------------
* static functions
*------------------------------------------------------------------*/
static inline void clock_lo(void)
{
IBM4704_CLOCK_PORT &= ~(1<<IBM4704_CLOCK_BIT);
IBM4704_CLOCK_DDR |= (1<<IBM4704_CLOCK_BIT);
}
static inline void clock_hi(void)
{
/* input with pull up */
IBM4704_CLOCK_DDR &= ~(1<<IBM4704_CLOCK_BIT);
IBM4704_CLOCK_PORT |= (1<<IBM4704_CLOCK_BIT);
}
static inline bool clock_in(void)
{
IBM4704_CLOCK_DDR &= ~(1<<IBM4704_CLOCK_BIT);
IBM4704_CLOCK_PORT |= (1<<IBM4704_CLOCK_BIT);
_delay_us(1);
return IBM4704_CLOCK_PIN&(1<<IBM4704_CLOCK_BIT);
}
static inline void data_lo(void)
{
IBM4704_DATA_PORT &= ~(1<<IBM4704_DATA_BIT);
IBM4704_DATA_DDR |= (1<<IBM4704_DATA_BIT);
}
static inline void data_hi(void)
{
/* input with pull up */
IBM4704_DATA_DDR &= ~(1<<IBM4704_DATA_BIT);
IBM4704_DATA_PORT |= (1<<IBM4704_DATA_BIT);
}
static inline bool data_in(void)
{
IBM4704_DATA_DDR &= ~(1<<IBM4704_DATA_BIT);
IBM4704_DATA_PORT |= (1<<IBM4704_DATA_BIT);
_delay_us(1);
return IBM4704_DATA_PIN&(1<<IBM4704_DATA_BIT);
}
static inline uint16_t wait_clock_lo(uint16_t us)
{
while (clock_in() && us) { asm(""); _delay_us(1); us--; }
return us;
}
static inline uint16_t wait_clock_hi(uint16_t us)
{
while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
return us;
}
static inline uint16_t wait_data_lo(uint16_t us)
{
while (data_in() && us) { asm(""); _delay_us(1); us--; }
return us;
}
static inline uint16_t wait_data_hi(uint16_t us)
{
while (!data_in() && us) { asm(""); _delay_us(1); us--; }
return us;
}
/* idle state that device can send */
static inline void idle(void)
{
clock_hi();
data_hi();
}
/* inhibit device to send
* keyboard checks Data line on start bit(Data:hi) and it stops sending if Data line is low.
*/
static inline void inhibit(void)
{
clock_hi();
data_lo();
}
#endif

View File

@ -1,7 +1,12 @@
LUFA_DIR = protocol/lufa
# Path to the LUFA library
LUFA_PATH ?= protocol/lufa/LUFA-120730
ifeq (, $(wildcard $(TOP_DIR)/$(LUFA_DIR)/LUFA-git/LUFA/Version.h))
LUFA_PATH ?= $(LUFA_DIR)/LUFA-120730
else
LUFA_PATH ?= $(LUFA_DIR)/LUFA-git
endif
# Create the LUFA source path variables by including the LUFA makefile
ifneq (, $(wildcard $(TOP_DIR)/$(LUFA_PATH)/LUFA/Build/lufa_sources.mk))
@ -30,9 +35,12 @@ VPATH += $(TOP_DIR)/$(LUFA_PATH)
#endif
# LUFA library compile-time options and predefined tokens
LUFA_OPTS = -D USB_DEVICE_ONLY
LUFA_OPTS += -D USE_FLASH_DESCRIPTORS
LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
LUFA_OPTS = -DUSB_DEVICE_ONLY
LUFA_OPTS += -DUSE_FLASH_DESCRIPTORS
LUFA_OPTS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
#LUFA_OPTS += -DINTERRUPT_CONTROL_ENDPOINT
LUFA_OPTS += -DFIXED_CONTROL_ENDPOINT_SIZE=8
LUFA_OPTS += -DFIXED_NUM_CONFIGURATIONS=1
OPT_DEFS += -DF_USB=$(F_USB)UL
OPT_DEFS += -DARCH=ARCH_$(ARCH)

@ -0,0 +1 @@
Subproject commit b6c18b2a7c544653efbe12a1d4e8ba65e7d83c35

View File

@ -230,12 +230,12 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
{
.Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
.USBSpecification = VERSION_BCD(01.10),
.USBSpecification = VERSION_BCD(1,1,0),
.Class = USB_CSCP_NoDeviceClass,
.SubClass = USB_CSCP_NoDeviceSubclass,
.Protocol = USB_CSCP_NoDeviceProtocol,
.Endpoint0Size = 8,
.Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE,
/* specified in config.h */
.VendorID = VENDOR_ID,
@ -246,7 +246,7 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
.ProductStrIndex = 0x02,
.SerialNumStrIndex = NO_DESCRIPTOR,
.NumberOfConfigurations = 1
.NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
};
/*******************************************************************************
@ -292,7 +292,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
{
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
.HIDSpec = VERSION_BCD(01.11),
.HIDSpec = VERSION_BCD(1,1,1),
.CountryCode = 0x00,
.TotalReportDescriptors = 1,
.HIDReportType = HID_DTYPE_Report,
@ -306,7 +306,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.EndpointAddress = (ENDPOINT_DIR_IN | KEYBOARD_IN_EPNUM),
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = KEYBOARD_EPSIZE,
.PollingIntervalMS = 0x01
.PollingIntervalMS = 0x0A
},
/*
@ -333,7 +333,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
{
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
.HIDSpec = VERSION_BCD(01.11),
.HIDSpec = VERSION_BCD(1,1,1),
.CountryCode = 0x00,
.TotalReportDescriptors = 1,
.HIDReportType = HID_DTYPE_Report,
@ -347,7 +347,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.EndpointAddress = (ENDPOINT_DIR_IN | MOUSE_IN_EPNUM),
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = MOUSE_EPSIZE,
.PollingIntervalMS = 0x01
.PollingIntervalMS = 0x0A
},
#endif
@ -375,7 +375,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
{
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
.HIDSpec = VERSION_BCD(01.11),
.HIDSpec = VERSION_BCD(1,1,1),
.CountryCode = 0x00,
.TotalReportDescriptors = 1,
.HIDReportType = HID_DTYPE_Report,
@ -389,7 +389,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.EndpointAddress = (ENDPOINT_DIR_IN | EXTRAKEY_IN_EPNUM),
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = EXTRAKEY_EPSIZE,
.PollingIntervalMS = 0x01
.PollingIntervalMS = 0x0A
},
#endif
@ -417,7 +417,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
{
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
.HIDSpec = VERSION_BCD(01.11),
.HIDSpec = VERSION_BCD(1,1,1),
.CountryCode = 0x00,
.TotalReportDescriptors = 1,
.HIDReportType = HID_DTYPE_Report,
@ -469,7 +469,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
{
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
.HIDSpec = VERSION_BCD(01.11),
.HIDSpec = VERSION_BCD(1,1,1),
.CountryCode = 0x00,
.TotalReportDescriptors = 1,
.HIDReportType = HID_DTYPE_Report,

View File

@ -137,13 +137,17 @@ typedef struct
#ifdef CONSOLE_ENABLE
# define CONSOLE_IN_EPNUM (EXTRAKEY_IN_EPNUM + 1)
# define CONSOLE_OUT_EPNUM (EXTRAKEY_IN_EPNUM + 2)
# define CONSOLE_OUT_EPNUM (EXTRAKEY_IN_EPNUM + 1)
//# define CONSOLE_OUT_EPNUM (EXTRAKEY_IN_EPNUM + 2)
#else
# define CONSOLE_OUT_EPNUM EXTRAKEY_IN_EPNUM
#endif
#ifdef NKRO_ENABLE
# define NKRO_IN_EPNUM (CONSOLE_OUT_EPNUM + 1)
# if defined(__AVR_ATmega32U2__) && NKRO_IN_EPNUM > 4
# error "Endpoints are not available enough to support all functions. Remove some in Makefile.(MOUSEKEY, EXTRAKEY, CONSOLE, NKRO)"
# endif
#endif
@ -159,4 +163,14 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
const void** const DescriptorAddress)
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
/* new API */
#if LUFA_VERSION_INTEGER < 0x140302
#undef VERSION_BCD
#define VERSION_BCD(Major, Minor, Revision) \
CPU_TO_LE16( ((Major & 0xFF) << 8) | \
((Minor & 0x0F) << 4) | \
(Revision & 0x0F) )
#endif
#endif

View File

@ -52,8 +52,8 @@
#include "descriptor.h"
#include "lufa.h"
static uint8_t idle_duration = 0;
static uint8_t protocol_report = 1;
uint8_t keyboard_idle = 0;
uint8_t keyboard_protocol = 1;
static uint8_t keyboard_led_stats = 0;
static report_keyboard_t keyboard_report_sent;
@ -184,15 +184,6 @@ void EVENT_USB_Device_StartOfFrame(void)
/** Event handler for the USB_ConfigurationChanged event.
* This is fired when the host sets the current configuration of the USB device after enumeration.
*/
#if LUFA_VERSION_INTEGER < 0x120730
/* old API 120219 */
#define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint(epnum, eptype, epdir, epsize, epbank)
#else
/* new API >= 120730 */
#define ENDPOINT_BANK_SINGLE 1
#define ENDPOINT_BANK_DOUBLE 2
#define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint((epdir) | (epnum) , eptype, epsize, epbank)
#endif
void EVENT_USB_Device_ConfigurationChanged(void)
{
bool ConfigSuccess = true;
@ -217,9 +208,11 @@ void EVENT_USB_Device_ConfigurationChanged(void)
/* Setup Console HID Report Endpoints */
ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
#if 0
ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
#endif
#endif
#ifdef NKRO_ENABLE
/* Setup NKRO HID Report Endpoints */
@ -279,6 +272,7 @@ void EVENT_USB_Device_ControlRequest(void)
// Interface
switch (USB_ControlRequest.wIndex) {
case KEYBOARD_INTERFACE:
case NKRO_INTERFACE:
Endpoint_ClearSETUP();
while (!(Endpoint_IsOUTReceived())) {
@ -299,21 +293,29 @@ void EVENT_USB_Device_ControlRequest(void)
case HID_REQ_GetProtocol:
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
{
Endpoint_ClearSETUP();
while (!(Endpoint_IsINReady()));
Endpoint_Write_8(protocol_report);
Endpoint_ClearIN();
Endpoint_ClearStatusStage();
if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
Endpoint_ClearSETUP();
while (!(Endpoint_IsINReady()));
Endpoint_Write_8(keyboard_protocol);
Endpoint_ClearIN();
Endpoint_ClearStatusStage();
}
}
break;
case HID_REQ_SetProtocol:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
protocol_report = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
keyboard_protocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
#ifdef NKRO_ENABLE
keyboard_nkro = !!keyboard_protocol;
#endif
clear_keyboard();
}
}
break;
@ -323,7 +325,7 @@ void EVENT_USB_Device_ControlRequest(void)
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
idle_duration = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
}
break;
@ -332,7 +334,7 @@ void EVENT_USB_Device_ControlRequest(void)
{
Endpoint_ClearSETUP();
while (!(Endpoint_IsINReady()));
Endpoint_Write_8(idle_duration);
Endpoint_Write_8(keyboard_idle);
Endpoint_ClearIN();
Endpoint_ClearStatusStage();
}
@ -351,7 +353,7 @@ static uint8_t keyboard_leds(void)
static void send_keyboard(report_keyboard_t *report)
{
uint8_t timeout = 0;
uint8_t timeout = 255;
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
@ -359,26 +361,27 @@ static void send_keyboard(report_keyboard_t *report)
/* Select the Keyboard Report Endpoint */
#ifdef NKRO_ENABLE
if (keyboard_nkro) {
/* Report protocol - NKRO */
Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
}
else
#endif
{
Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
}
/* Check if Keyboard Endpoint Ready for Read/Write */
while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
/* Check if write ready for a polling interval around 1ms */
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(4);
if (!Endpoint_IsReadWriteAllowed()) return;
/* Write Keyboard Report Data */
#ifdef NKRO_ENABLE
if (keyboard_nkro) {
/* Write Keyboard Report Data */
Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
}
else
#endif
{
/* boot mode */
/* Boot protocol */
Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
/* Check if write ready for a polling interval around 10ms */
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
if (!Endpoint_IsReadWriteAllowed()) return;
/* Write Keyboard Report Data */
Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
}
@ -391,7 +394,7 @@ static void send_keyboard(report_keyboard_t *report)
static void send_mouse(report_mouse_t *report)
{
#ifdef MOUSE_ENABLE
uint8_t timeout = 0;
uint8_t timeout = 255;
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
@ -399,8 +402,9 @@ static void send_mouse(report_mouse_t *report)
/* Select the Mouse Report Endpoint */
Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
/* Check if Mouse Endpoint Ready for Read/Write */
while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
/* Check if write ready for a polling interval around 10ms */
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
if (!Endpoint_IsReadWriteAllowed()) return;
/* Write Mouse Report Data */
Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
@ -412,7 +416,7 @@ static void send_mouse(report_mouse_t *report)
static void send_system(uint16_t data)
{
uint8_t timeout = 0;
uint8_t timeout = 255;
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
@ -422,14 +426,18 @@ static void send_system(uint16_t data)
.usage = data
};
Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
/* Check if write ready for a polling interval around 10ms */
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
if (!Endpoint_IsReadWriteAllowed()) return;
Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
Endpoint_ClearIN();
}
static void send_consumer(uint16_t data)
{
uint8_t timeout = 0;
uint8_t timeout = 255;
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
@ -439,7 +447,11 @@ static void send_consumer(uint16_t data)
.usage = data
};
Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
/* Check if write ready for a polling interval around 10ms */
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
if (!Endpoint_IsReadWriteAllowed()) return;
Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
Endpoint_ClearIN();
}

View File

@ -66,4 +66,15 @@ typedef struct {
uint16_t usage;
} __attribute__ ((packed)) report_extra_t;
#if LUFA_VERSION_INTEGER < 0x120730
/* old API 120219 */
#define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint(epnum, eptype, epdir, epsize, epbank)
#else
/* new API >= 120730 */
#define ENDPOINT_BANK_SINGLE 1
#define ENDPOINT_BANK_DOUBLE 2
#define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint((epdir) | (epnum) , eptype, epsize, epbank)
#endif
#endif

204
protocol/next_kbd.c Normal file
View File

@ -0,0 +1,204 @@
/*
NeXT non-ADB Keyboard Protocol
Copyright 2013, Benjamin Gould (bgould@github.com)
Based on:
TMK firmware code Copyright 2011,2012 Jun WAKO <wakojun@gmail.com>
Arduino code by "Ladyada" Limor Fried (http://ladyada.net/, http://adafruit.com/), released under BSD license
Timing reference thanks to http://m0115.web.fc2.com/ (dead link), http://cfile7.uf.tistory.com/image/14448E464F410BF22380BB
Pinouts thanks to http://www.68k.org/~degs/nextkeyboard.html
Keycodes from http://ftp.netbsd.org/pub/NetBSD/NetBSD-release-6/src/sys/arch/next68k/dev/
This software is licensed with a Modified BSD License.
All of this is supposed to be Free Software, Open Source, DFSG-free,
GPL-compatible, and OK to use in both free and proprietary applications.
Additions and corrections to this file are welcome.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdint.h>
#include <stdbool.h>
#include <util/atomic.h>
#include <util/delay.h>
#include "next_kbd.h"
#include "debug.h"
static inline void out_lo(void);
static inline void out_hi(void);
static inline void query(void);
static inline void reset(void);
static inline uint32_t response(void);
#define out_hi_delay(intervals) do { out_hi(); _delay_us(NEXT_KBD_TIMING * intervals); } while (0);
#define out_lo_delay(intervals) do { out_lo(); _delay_us(NEXT_KBD_TIMING * intervals); } while (0);
#define query_delay(intervals) do { query(); _delay_us(NEXT_KBD_TIMING * intervals); } while (0);
#define reset_delay(intervals) do { reset(); _delay_us(NEXT_KBD_TIMING * intervals); } while (0);
void next_kbd_init(void)
{
out_hi();
NEXT_KBD_IN_DDR &= ~(1<<NEXT_KBD_IN_BIT); // KBD_IN to input
NEXT_KBD_IN_PORT |= (1<<NEXT_KBD_IN_BIT); // KBD_IN pull up
query_delay(5);
reset_delay(8);
query_delay(5);
reset_delay(8);
}
void next_kbd_set_leds(bool left, bool right)
{
out_lo_delay(9);
out_hi_delay(3);
out_lo_delay(1);
if (left) {
out_hi_delay(1);
} else {
out_lo_delay(1);
}
if (right) {
out_hi_delay(1);
} else {
out_lo_delay(1);
}
out_lo_delay(7);
out_hi();
}
#define NEXT_KBD_READ (NEXT_KBD_IN_PIN&(1<<NEXT_KBD_IN_BIT))
uint32_t next_kbd_recv(void)
{
// First check to make sure that the keyboard is actually connected;
// if not, just return
// TODO: reflect the status of the keyboard in a return code
if (!NEXT_KBD_READ) {
sei();
return 0;
}
query();
uint32_t resp = response();
return resp;
}
static inline uint32_t response(void)
{
cli();
// try a 5ms read; this should be called after the query method has
// been run so if a key is pressed we should get a response within
// 5ms; if not then send a reset and exit
uint8_t i = 0;
uint32_t data = 0;
uint16_t reset_timeout = 50000;
while (NEXT_KBD_READ && reset_timeout) {
asm(""); _delay_us(1); reset_timeout--;
}
if (!reset_timeout) {
reset();
sei();
return 0;
}
_delay_us(NEXT_KBD_TIMING / 2);
for (; i < 22; i++)
{
if (NEXT_KBD_READ)
{
data |= ((uint32_t) 1 << i);
/* Note:
* My testing with the ATmega32u4 showed that there might
* something wrong with the timing here; by the end of the
* second data byte some of the modifiers can get bumped out
* to the next bit over if we just cycle through the data
* based on the expected interval. There is a bit (i = 10)
* in the middle of the data that is always on followed by
* one that is always off - so we'll use that to reset our
* timing in case we've gotten ahead of the keyboard;
*/
if (i == 10)
{
i++;
while (NEXT_KBD_READ) ;
_delay_us(NEXT_KBD_TIMING / 2);
}
} else {
/* redundant - but I don't want to remove if it might screw
* up the timing
*/
data |= ((uint32_t) 0 << i);
}
_delay_us(NEXT_KBD_TIMING);
}
sei();
return data;
}
static inline void out_lo(void)
{
NEXT_KBD_OUT_PORT &= ~(1<<NEXT_KBD_OUT_BIT);
NEXT_KBD_OUT_DDR |= (1<<NEXT_KBD_OUT_BIT);
}
static inline void out_hi(void)
{
/* input with pull up */
NEXT_KBD_OUT_DDR &= ~(1<<NEXT_KBD_OUT_BIT);
NEXT_KBD_OUT_PORT |= (1<<NEXT_KBD_OUT_BIT);
}
static inline void query(void)
{
out_lo_delay(5);
out_hi_delay(1);
out_lo_delay(3);
out_hi();
}
static inline void reset(void)
{
out_lo_delay(1);
out_hi_delay(4);
out_lo_delay(1);
out_hi_delay(6);
out_lo_delay(10);
out_hi();
}

63
protocol/next_kbd.h Normal file
View File

@ -0,0 +1,63 @@
/*
NeXT non-ADB Keyboard Protocol
Copyright 2013, Benjamin Gould (bgould@github.com)
Based on:
TMK firmware code Copyright 2011,2012 Jun WAKO <wakojun@gmail.com>
Arduino code by "Ladyada" Limor Fried (http://ladyada.net/, http://adafruit.com/), released under BSD license
Timing reference thanks to http://m0115.web.fc2.com/ (dead link), http://cfile7.uf.tistory.com/image/14448E464F410BF22380BB
Pinouts thanks to http://www.68k.org/~degs/nextkeyboard.html
Keycodes from http://ftp.netbsd.org/pub/NetBSD/NetBSD-release-6/src/sys/arch/next68k/dev/
This software is licensed with a Modified BSD License.
All of this is supposed to be Free Software, Open Source, DFSG-free,
GPL-compatible, and OK to use in both free and proprietary applications.
Additions and corrections to this file are welcome.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdbool.h>
#ifndef NEXT_KBD_H
#define NEXT_KBD_H
#define NEXT_KBD_KMBUS_IDLE 0x300600
#define NEXT_KBD_TIMING 50
extern uint8_t next_kbd_error;
/* host role */
void next_kbd_init(void);
void next_kbd_set_leds(bool left, bool right);
uint32_t next_kbd_recv(void);
#endif

View File

@ -38,6 +38,7 @@
#include "sleep_led.h"
#endif
#include "suspend.h"
#include "action.h"
#include "action_util.h"
@ -628,6 +629,7 @@ uint8_t usb_configured(void)
void usb_remote_wakeup(void)
{
UDCON |= (1<<RMWKUP);
while (UDCON & (1<<RMWKUP));
}
@ -692,20 +694,20 @@ ISR(USB_GEN_vect)
}
/* TODO: should keep IDLE rate on each keyboard interface */
#ifdef NKRO_ENABLE
if (!keyboard_nkro && usb_keyboard_idle_config && (++div4 & 3) == 0) {
if (!keyboard_nkro && keyboard_idle && (++div4 & 3) == 0) {
#else
if (usb_keyboard_idle_config && (++div4 & 3) == 0) {
if (keyboard_idle && (++div4 & 3) == 0) {
#endif
UENUM = KBD_ENDPOINT;
if (UEINTX & (1<<RWAL)) {
usb_keyboard_idle_count++;
if (usb_keyboard_idle_count == usb_keyboard_idle_config) {
if (usb_keyboard_idle_count == keyboard_idle) {
usb_keyboard_idle_count = 0;
/* TODO: fix keyboard_report inconsistency */
/* To avoid Mac SET_IDLE behaviour.
UEDATX = keyboard_report_prev->mods;
UEDATX = 0;
uint8_t keys = usb_keyboard_protocol ? KBD_REPORT_KEYS : 6;
uint8_t keys = keyboard_protocol ? KBD_REPORT_KEYS : 6;
for (uint8_t i=0; i<keys; i++) {
UEDATX = keyboard_report_prev->keys[i];
}
@ -901,13 +903,13 @@ ISR(USB_COM_vect)
}
if (bRequest == HID_GET_IDLE) {
usb_wait_in_ready();
UEDATX = usb_keyboard_idle_config;
UEDATX = keyboard_idle;
usb_send_in();
return;
}
if (bRequest == HID_GET_PROTOCOL) {
usb_wait_in_ready();
UEDATX = usb_keyboard_protocol;
UEDATX = keyboard_protocol;
usb_send_in();
return;
}
@ -921,14 +923,18 @@ ISR(USB_COM_vect)
return;
}
if (bRequest == HID_SET_IDLE) {
usb_keyboard_idle_config = (wValue >> 8);
keyboard_idle = (wValue >> 8);
usb_keyboard_idle_count = 0;
//usb_wait_in_ready();
usb_send_in();
return;
}
if (bRequest == HID_SET_PROTOCOL) {
usb_keyboard_protocol = wValue;
keyboard_protocol = wValue;
#ifdef NKRO_ENABLE
keyboard_nkro = !!keyboard_protocol;
#endif
clear_keyboard();
//usb_wait_in_ready();
usb_send_in();
return;

View File

@ -34,12 +34,12 @@
// protocol setting from the host. We use exactly the same report
// either way, so this variable only stores the setting since we
// are required to be able to report which setting is in use.
uint8_t usb_keyboard_protocol=1;
uint8_t keyboard_protocol=1;
// the idle configuration, how often we send the report to the
// host (ms * 4) even when it hasn't changed
// Windows and Linux set 0 while OS X sets 6(24ms) by SET_IDLE request.
uint8_t usb_keyboard_idle_config=125;
uint8_t keyobard_idle=125;
// count until idle timeout
uint8_t usb_keyboard_idle_count=0;
@ -61,10 +61,7 @@ int8_t usb_keyboard_send_report(report_keyboard_t *report)
else
#endif
{
if (usb_keyboard_protocol)
result = send_report(report, KBD_ENDPOINT, 0, KBD_SIZE);
else
result = send_report(report, KBD_ENDPOINT, 0, 6);
result = send_report(report, KBD_ENDPOINT, 0, KBD_SIZE);
}
if (result) return result;

View File

@ -30,8 +30,6 @@
#include "host.h"
extern uint8_t usb_keyboard_protocol;
extern uint8_t usb_keyboard_idle_config;
extern uint8_t usb_keyboard_idle_count;
extern volatile uint8_t usb_keyboard_leds;