aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorsago35 <[email protected]>2022-06-02 08:29:13 +0900
committerRon Evans <[email protected]>2022-06-11 09:44:09 +0200
commit1b2e764835fb5278de144caf059cb094bad4db23 (patch)
tree1a28c06af78d4a1d2db023a752817ae2ecc42808
parent2c93a4085cf3b8783d10129698ddaaa2d9e1fbc4 (diff)
downloadtinygo-1b2e764835fb5278de144caf059cb094bad4db23.tar.gz
tinygo-1b2e764835fb5278de144caf059cb094bad4db23.zip
samd21,samd51,nrf52840: add support for USBHID (keyboard / mouse)
-rw-r--r--Makefile9
-rw-r--r--src/examples/hid-keyboard/main.go21
-rw-r--r--src/examples/hid-mouse/main.go37
-rw-r--r--src/machine/machine_atsamd21.go53
-rw-r--r--src/machine/machine_atsamd51.go54
-rw-r--r--src/machine/machine_nrf52840_usb.go49
-rw-r--r--src/machine/usb.go493
-rw-r--r--src/machine/usb/hid/buffer.go52
-rw-r--r--src/machine/usb/hid/hid.go51
-rw-r--r--src/machine/usb/hid/keyboard/keyboard.go478
-rw-r--r--src/machine/usb/hid/keyboard/keycode.go532
-rw-r--r--src/machine/usb/hid/mouse/mouse.go90
-rw-r--r--src/machine/usb_descriptor.go70
13 files changed, 1510 insertions, 479 deletions
diff --git a/Makefile b/Makefile
index c5afd2bbc..3610348e6 100644
--- a/Makefile
+++ b/Makefile
@@ -414,6 +414,10 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/test
@$(MD5SUM) test.hex
+ $(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-mouse
+ @$(MD5SUM) test.hex
+ $(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-keyboard
+ @$(MD5SUM) test.hex
# test simulated boards on play.tinygo.org
ifneq ($(WASM), 0)
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
@@ -555,6 +559,11 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/pwm
@$(MD5SUM) test.hex
+ # test usbhid
+ $(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/hid-keyboard
+ @$(MD5SUM) test.hex
+ $(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/hid-keyboard
+ @$(MD5SUM) test.hex
ifneq ($(STM32), 0)
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
@$(MD5SUM) test.hex
diff --git a/src/examples/hid-keyboard/main.go b/src/examples/hid-keyboard/main.go
new file mode 100644
index 000000000..9f0c478b7
--- /dev/null
+++ b/src/examples/hid-keyboard/main.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+ "machine"
+ "machine/usb/hid/keyboard"
+ "time"
+)
+
+func main() {
+ button := machine.BUTTON
+ button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
+
+ kb := keyboard.New()
+
+ for {
+ if !button.Get() {
+ kb.Write([]byte("tinygo"))
+ time.Sleep(200 * time.Millisecond)
+ }
+ }
+}
diff --git a/src/examples/hid-mouse/main.go b/src/examples/hid-mouse/main.go
new file mode 100644
index 000000000..1617c6b6a
--- /dev/null
+++ b/src/examples/hid-mouse/main.go
@@ -0,0 +1,37 @@
+package main
+
+import (
+ "machine"
+ "machine/usb/hid/mouse"
+ "time"
+)
+
+func main() {
+ button := machine.BUTTON
+ button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
+
+ mouse := mouse.New()
+
+ for {
+ if !button.Get() {
+ for j := 0; j < 5; j++ {
+ for i := 0; i < 100; i++ {
+ mouse.Move(1, 0)
+ time.Sleep(1 * time.Millisecond)
+ }
+
+ for i := 0; i < 100; i++ {
+ mouse.Move(0, 1)
+ time.Sleep(1 * time.Millisecond)
+ }
+
+ for i := 0; i < 100; i++ {
+ mouse.Move(-1, -1)
+ time.Sleep(1 * time.Millisecond)
+ }
+ }
+
+ time.Sleep(100 * time.Millisecond)
+ }
+ }
+}
diff --git a/src/machine/machine_atsamd21.go b/src/machine/machine_atsamd21.go
index 9b18a3130..d88190254 100644
--- a/src/machine/machine_atsamd21.go
+++ b/src/machine/machine_atsamd21.go
@@ -1746,7 +1746,8 @@ type USBCDC struct {
}
var (
- USB = &USBCDC{Buffer: NewRingBuffer()}
+ USB = &USBCDC{Buffer: NewRingBuffer()}
+ waitHidTxc bool
)
const (
@@ -1999,6 +2000,9 @@ func handleUSB(intr interrupt.Interrupt) {
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
USB.Flush()
// if you want to blink LED showing traffic, this would be the place...
+ if hidCallback != nil && !waitHidTxc {
+ hidCallback()
+ }
}
// Endpoint 0 Setup interrupt
@@ -2021,6 +2025,9 @@ func handleUSB(intr interrupt.Interrupt) {
// Class Interface Requests
if setup.wIndex == usb_CDC_ACM_INTERFACE {
ok = cdcSetup(setup)
+ } else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE {
+ sendZlp()
+ ok = true
}
}
@@ -2059,6 +2066,9 @@ func handleUSB(intr interrupt.Interrupt) {
if i == usb_CDC_ENDPOINT_IN {
USB.waitTxc = false
}
+ case usb_HID_ENDPOINT_IN:
+ setEPINTFLAG(i, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
+ waitHidTxc = false
}
}
}
@@ -2156,7 +2166,7 @@ func handleStandardSetup(setup usbSetup) bool {
}
}
- sendUSBPacket(0, buf)
+ sendUSBPacket(0, buf, setup.wLength)
return true
case usb_CLEAR_FEATURE:
@@ -2212,7 +2222,7 @@ func handleStandardSetup(setup usbSetup) bool {
case usb_GET_CONFIGURATION:
buff := []byte{usbConfiguration}
- sendUSBPacket(0, buff)
+ sendUSBPacket(0, buff, setup.wLength)
return true
case usb_SET_CONFIGURATION:
@@ -2229,6 +2239,11 @@ func handleStandardSetup(setup usbSetup) bool {
// Enable interrupt for CDC data messages from host
setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_EPINTENSET_TRCPT0)
+ // Enable interrupt for HID messages from host
+ if hidCallback != nil {
+ setEPINTENSET(usb_HID_ENDPOINT_IN, sam.USB_DEVICE_EPINTENSET_TRCPT1)
+ }
+
sendZlp()
return true
} else {
@@ -2237,7 +2252,7 @@ func handleStandardSetup(setup usbSetup) bool {
case usb_GET_INTERFACE:
buff := []byte{usbSetInterface}
- sendUSBPacket(0, buff)
+ sendUSBPacket(0, buff, setup.wLength)
return true
case usb_SET_INTERFACE:
@@ -2263,7 +2278,7 @@ func cdcSetup(setup usbSetup) bool {
b[5] = byte(usbLineInfo.bParityType)
b[6] = byte(usbLineInfo.bDataBits)
- sendUSBPacket(0, b[:])
+ sendUSBPacket(0, b[:], setup.wLength)
return true
}
}
@@ -2306,9 +2321,31 @@ func cdcSetup(setup usbSetup) bool {
return false
}
+// SendUSBHIDPacket sends a packet for USBHID (interrupt / in).
+func SendUSBHIDPacket(ep uint32, data []byte) bool {
+ if waitHidTxc {
+ return false
+ }
+ sendUSBPacket(ep, data, 0)
+
+ // clear transfer complete flag
+ setEPINTFLAG(ep, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
+
+ // send data by setting bank ready
+ setEPSTATUSSET(ep, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
+
+ waitHidTxc = true
+
+ return true
+}
+
//go:noinline
-func sendUSBPacket(ep uint32, data []byte) {
- copy(udd_ep_in_cache_buffer[ep][:], data)
+func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
+ l := uint16(len(data))
+ if 0 < maxsize && maxsize < l {
+ l = maxsize
+ }
+ copy(udd_ep_in_cache_buffer[ep][:], data[:l])
// Set endpoint address for sending data
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
@@ -2318,7 +2355,7 @@ func sendUSBPacket(ep uint32, data []byte) {
// set byte count, which is total number of bytes to be sent
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
- usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(uint32((len(data) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos))
+ usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
}
func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
diff --git a/src/machine/machine_atsamd51.go b/src/machine/machine_atsamd51.go
index 65effd594..db2fea71e 100644
--- a/src/machine/machine_atsamd51.go
+++ b/src/machine/machine_atsamd51.go
@@ -1987,7 +1987,8 @@ type USBCDC struct {
var (
// USB is a USB CDC interface.
- USB = &USBCDC{Buffer: NewRingBuffer()}
+ USB = &USBCDC{Buffer: NewRingBuffer()}
+ waitHidTxc bool
)
const (
@@ -2241,6 +2242,9 @@ func handleUSBIRQ(interrupt.Interrupt) {
// Start of frame
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
USB.Flush()
+ if hidCallback != nil && !waitHidTxc {
+ hidCallback()
+ }
// if you want to blink LED showing traffic, this would be the place...
}
@@ -2264,6 +2268,9 @@ func handleUSBIRQ(interrupt.Interrupt) {
// Class Interface Requests
if setup.wIndex == usb_CDC_ACM_INTERFACE {
ok = cdcSetup(setup)
+ } else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE {
+ sendZlp()
+ ok = true
}
}
@@ -2302,6 +2309,9 @@ func handleUSBIRQ(interrupt.Interrupt) {
if i == usb_CDC_ENDPOINT_IN {
USB.waitTxc = false
}
+ case usb_HID_ENDPOINT_IN:
+ setEPINTFLAG(i, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
+ waitHidTxc = false
}
}
}
@@ -2399,7 +2409,7 @@ func handleStandardSetup(setup usbSetup) bool {
}
}
- sendUSBPacket(0, buf)
+ sendUSBPacket(0, buf, setup.wLength)
return true
case usb_CLEAR_FEATURE:
@@ -2455,7 +2465,7 @@ func handleStandardSetup(setup usbSetup) bool {
case usb_GET_CONFIGURATION:
buff := []byte{usbConfiguration}
- sendUSBPacket(0, buff)
+ sendUSBPacket(0, buff, setup.wLength)
return true
case usb_SET_CONFIGURATION:
@@ -2472,6 +2482,11 @@ func handleStandardSetup(setup usbSetup) bool {
// Enable interrupt for CDC data messages from host
setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
+ // Enable interrupt for HID messages from host
+ if hidCallback != nil {
+ setEPINTENSET(usb_HID_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1)
+ }
+
sendZlp()
return true
} else {
@@ -2480,7 +2495,7 @@ func handleStandardSetup(setup usbSetup) bool {
case usb_GET_INTERFACE:
buff := []byte{usbSetInterface}
- sendUSBPacket(0, buff)
+ sendUSBPacket(0, buff, setup.wLength)
return true
case usb_SET_INTERFACE:
@@ -2506,7 +2521,7 @@ func cdcSetup(setup usbSetup) bool {
b[5] = byte(usbLineInfo.bParityType)
b[6] = byte(usbLineInfo.bDataBits)
- sendUSBPacket(0, b[:])
+ sendUSBPacket(0, b[:], setup.wLength)
return true
}
}
@@ -2549,9 +2564,32 @@ func cdcSetup(setup usbSetup) bool {
return false
}
+// SendUSBHIDPacket sends a packet for USBHID (interrupt / in).
+func SendUSBHIDPacket(ep uint32, data []byte) bool {
+ if waitHidTxc {
+ return false
+ }
+
+ sendUSBPacket(ep, data, 0)
+
+ // clear transfer complete flag
+ setEPINTFLAG(ep, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
+
+ // send data by setting bank ready
+ setEPSTATUSSET(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
+
+ waitHidTxc = true
+
+ return true
+}
+
//go:noinline
-func sendUSBPacket(ep uint32, data []byte) {
- copy(udd_ep_in_cache_buffer[ep][:], data)
+func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
+ l := uint16(len(data))
+ if 0 < maxsize && maxsize < l {
+ l = maxsize
+ }
+ copy(udd_ep_in_cache_buffer[ep][:], data[:l])
// Set endpoint address for sending data
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
@@ -2561,7 +2599,7 @@ func sendUSBPacket(ep uint32, data []byte) {
// set byte count, which is total number of bytes to be sent
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
- usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(uint32((len(data) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos))
+ usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
}
func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
diff --git a/src/machine/machine_nrf52840_usb.go b/src/machine/machine_nrf52840_usb.go
index 098424a35..7260ac15f 100644
--- a/src/machine/machine_nrf52840_usb.go
+++ b/src/machine/machine_nrf52840_usb.go
@@ -121,8 +121,9 @@ func (usbcdc *USBCDC) RTS() bool {
}
var (
- USB = &_USB
- _USB = USBCDC{Buffer: NewRingBuffer()}
+ USB = &_USB
+ _USB = USBCDC{Buffer: NewRingBuffer()}
+ waitHidTxc bool
usbEndpointDescriptors [8]usbDeviceDescriptor
@@ -201,6 +202,9 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) {
if nrf.USBD.EVENTS_SOF.Get() == 1 {
nrf.USBD.EVENTS_SOF.Set(0)
usbcdc.Flush()
+ if hidCallback != nil && !waitHidTxc {
+ hidCallback()
+ }
// if you want to blink LED showing traffic, this would be the place...
}
@@ -262,6 +266,9 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) {
} else {
if setup.wIndex == usb_CDC_ACM_INTERFACE {
ok = cdcSetup(setup)
+ } else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE {
+ sendZlp()
+ ok = true
}
}
@@ -297,6 +304,8 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) {
usbcdc.waitTxc = false
exitCriticalSection()
}
+ case usb_HID_ENDPOINT_IN:
+ waitHidTxc = false
}
}
}
@@ -378,7 +387,7 @@ func handleStandardSetup(setup usbSetup) bool {
}
}
- sendUSBPacket(0, buf)
+ sendUSBPacket(0, buf, setup.wLength)
return true
case usb_CLEAR_FEATURE:
@@ -412,7 +421,7 @@ func handleStandardSetup(setup usbSetup) bool {
case usb_GET_CONFIGURATION:
buff := []byte{usbConfiguration}
- sendUSBPacket(0, buff)
+ sendUSBPacket(0, buff, setup.wLength)
return true
case usb_SET_CONFIGURATION:
@@ -422,6 +431,11 @@ func handleStandardSetup(setup usbSetup) bool {
initEndpoint(uint32(i), endPoints[i])
}
+ // Enable interrupt for HID messages from host
+ if hidCallback != nil {
+ nrf.USBD.INTENSET.Set(nrf.USBD_INTENSET_ENDEPOUT0 << usb_HID_ENDPOINT_IN)
+ }
+
usbConfiguration = setup.wValueL
return true
} else {
@@ -430,7 +444,7 @@ func handleStandardSetup(setup usbSetup) bool {
case usb_GET_INTERFACE:
buff := []byte{usbSetInterface}
- sendUSBPacket(0, buff)
+ sendUSBPacket(0, buff, setup.wLength)
return true
case usb_SET_INTERFACE:
@@ -456,7 +470,7 @@ func cdcSetup(setup usbSetup) bool {
b[5] = byte(usbLineInfo.bParityType)
b[6] = byte(usbLineInfo.bDataBits)
- sendUSBPacket(0, b[:])
+ sendUSBPacket(0, b[:], setup.wLength)
return true
}
}
@@ -482,10 +496,29 @@ func cdcSetup(setup usbSetup) bool {
return false
}
+// SendUSBHIDPacket sends a packet for USBHID (interrupt / in).
+func SendUSBHIDPacket(ep uint32, data []byte) bool {
+ if waitHidTxc {
+ return false
+ }
+
+ sendUSBPacket(ep, data, 0)
+
+ // clear transfer complete flag
+ nrf.USBD.INTENCLR.Set(nrf.USBD_INTENCLR_ENDEPOUT0 << 4)
+
+ waitHidTxc = true
+
+ return true
+}
+
//go:noinline
-func sendUSBPacket(ep uint32, data []byte) {
+func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
count := len(data)
- copy(udd_ep_in_cache_buffer[ep][:], data)
+ if 0 < int(maxsize) && int(maxsize) < count {
+ count = int(maxsize)
+ }
+ copy(udd_ep_in_cache_buffer[ep][:], data[:count])
if ep == 0 && count > usbEndpointPacketSize {
sendOnEP0DATADONE.ptr = &udd_ep_in_cache_buffer[ep][usbEndpointPacketSize]
sendOnEP0DATADONE.count = count - usbEndpointPacketSize
diff --git a/src/machine/usb.go b/src/machine/usb.go
index 1789e170a..354bc1b14 100644
--- a/src/machine/usb.go
+++ b/src/machine/usb.go
@@ -8,7 +8,7 @@ import (
"runtime/volatile"
)
-const deviceDescriptorSize = 18
+var usbDescriptor = descriptorCDC
var (
errUSBCDCBufferEmpty = errors.New("USB-CDC buffer empty")
@@ -17,397 +17,6 @@ var (
errUSBCDCBytesRead = errors.New("USB-CDC invalid number of bytes read")
)
-// DeviceDescriptor implements the USB standard device descriptor.
-//
-// Table 9-8. Standard Device Descriptor
-// bLength, bDescriptorType, bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, bMaxPacketSize0,
-// idVendor, idProduct, bcdDevice, iManufacturer, iProduct, iSerialNumber, bNumConfigurations */
-//
-type DeviceDescriptor struct {
- bLength uint8 // 18
- bDescriptorType uint8 // 1 USB_DEVICE_DESCRIPTOR_TYPE
- bcdUSB uint16 // 0x200
- bDeviceClass uint8
- bDeviceSubClass uint8
- bDeviceProtocol uint8
- bMaxPacketSize0 uint8 // Packet 0
- idVendor uint16
- idProduct uint16
- bcdDevice uint16 // 0x100
- iManufacturer uint8
- iProduct uint8
- iSerialNumber uint8
- bNumConfigurations uint8
-}
-
-// NewDeviceDescriptor returns a USB DeviceDescriptor.
-func NewDeviceDescriptor(class, subClass, proto, packetSize0 uint8, vid, pid, version uint16, im, ip, is, configs uint8) DeviceDescriptor {
- return DeviceDescriptor{deviceDescriptorSize, 1, 0x200, class, subClass, proto, packetSize0, vid, pid, version, im, ip, is, configs}
-}
-
-// Bytes returns DeviceDescriptor data
-func (d DeviceDescriptor) Bytes() [deviceDescriptorSize]byte {
- var b [deviceDescriptorSize]byte
- b[0] = byte(d.bLength)
- b[1] = byte(d.bDescriptorType)
- b[2] = byte(d.bcdUSB)
- b[3] = byte(d.bcdUSB >> 8)
- b[4] = byte(d.bDeviceClass)
- b[5] = byte(d.bDeviceSubClass)
- b[6] = byte(d.bDeviceProtocol)
- b[7] = byte(d.bMaxPacketSize0)
- b[8] = byte(d.idVendor)
- b[9] = byte(d.idVendor >> 8)
- b[10] = byte(d.idProduct)
- b[11] = byte(d.idProduct >> 8)
- b[12] = byte(d.bcdDevice)
- b[13] = byte(d.bcdDevice >> 8)
- b[14] = byte(d.iManufacturer)
- b[15] = byte(d.iProduct)
- b[16] = byte(d.iSerialNumber)
- b[17] = byte(d.bNumConfigurations)
- return b
-}
-
-const configDescriptorSize = 9
-
-// ConfigDescriptor implements the standard USB configuration descriptor.
-//
-// Table 9-10. Standard Configuration Descriptor
-// bLength, bDescriptorType, wTotalLength, bNumInterfaces, bConfigurationValue, iConfiguration
-// bmAttributes, bMaxPower
-//
-type ConfigDescriptor struct {
- bLength uint8 // 9
- bDescriptorType uint8 // 2
- wTotalLength uint16 // total length
- bNumInterfaces uint8
- bConfigurationValue uint8
- iConfiguration uint8
- bmAttributes uint8
- bMaxPower uint8
-}
-
-// NewConfigDescriptor returns a new USB ConfigDescriptor.
-func NewConfigDescriptor(totalLength uint16, interfaces uint8) ConfigDescriptor {
- return ConfigDescriptor{configDescriptorSize, 2, totalLength, interfaces, 1, 0, usb_CONFIG_BUS_POWERED | usb_CONFIG_REMOTE_WAKEUP, 50}
-}
-
-// Bytes returns ConfigDescriptor data.
-func (d ConfigDescriptor) Bytes() [configDescriptorSize]byte {
- var b [configDescriptorSize]byte
- b[0] = byte(d.bLength)
- b[1] = byte(d.bDescriptorType)
- b[2] = byte(d.wTotalLength)
- b[3] = byte(d.wTotalLength >> 8)
- b[4] = byte(d.bNumInterfaces)
- b[5] = byte(d.bConfigurationValue)
- b[6] = byte(d.iConfiguration)
- b[7] = byte(d.bmAttributes)
- b[8] = byte(d.bMaxPower)
- return b
-}
-
-const interfaceDescriptorSize = 9
-
-// InterfaceDescriptor implements the standard USB interface descriptor.
-//
-// Table 9-12. Standard Interface Descriptor
-// bLength, bDescriptorType, bInterfaceNumber, bAlternateSetting, bNumEndpoints, bInterfaceClass,
-// bInterfaceSubClass, bInterfaceProtocol, iInterface
-//
-type InterfaceDescriptor struct {
- bLength uint8 // 9
- bDescriptorType uint8 // 4
- bInterfaceNumber uint8
- bAlternateSetting uint8
- bNumEndpoints uint8
- bInterfaceClass uint8
- bInterfaceSubClass uint8
- bInterfaceProtocol uint8
- iInterface uint8
-}
-
-// NewInterfaceDescriptor returns a new USB InterfaceDescriptor.
-func NewInterfaceDescriptor(n, numEndpoints, class, subClass, protocol uint8) InterfaceDescriptor {
- return InterfaceDescriptor{interfaceDescriptorSize, 4, n, 0, numEndpoints, class, subClass, protocol, 0}
-}
-
-// Bytes returns InterfaceDescriptor data.
-func (d InterfaceDescriptor) Bytes() [interfaceDescriptorSize]byte {
- var b [interfaceDescriptorSize]byte
- b[0] = byte(d.bLength)
- b[1] = byte(d.bDescriptorType)
- b[2] = byte(d.bInterfaceNumber)
- b[3] = byte(d.bAlternateSetting)
- b[4] = byte(d.bNumEndpoints)
- b[5] = byte(d.bInterfaceClass)
- b[6] = byte(d.bInterfaceSubClass)
- b[7] = byte(d.bInterfaceProtocol)
- b[8] = byte(d.iInterface)
- return b
-}
-
-const endpointDescriptorSize = 7
-
-// EndpointDescriptor implements the standard USB endpoint descriptor.
-//
-// Table 9-13. Standard Endpoint Descriptor
-// bLength, bDescriptorType, bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval
-//
-type EndpointDescriptor struct {
- bLength uint8 // 7
- bDescriptorType uint8 // 5
- bEndpointAddress uint8
- bmAttributes uint8
- wMaxPacketSize uint16
- bInterval uint8
-}
-
-// NewEndpointDescriptor returns a new USB EndpointDescriptor.
-func NewEndpointDescriptor(addr, attr uint8, packetSize uint16, interval uint8) EndpointDescriptor {
- return EndpointDescriptor{endpointDescriptorSize, 5, addr, attr, packetSize, interval}
-}
-
-// Bytes returns EndpointDescriptor data.
-func (d EndpointDescriptor) Bytes() [endpointDescriptorSize]byte {
- var b [endpointDescriptorSize]byte
- b[0] = byte(d.bLength)
- b[1] = byte(d.bDescriptorType)
- b[2] = byte(d.bEndpointAddress)
- b[3] = byte(d.bmAttributes)
- b[4] = byte(d.wMaxPacketSize)
- b[5] = byte(d.wMaxPacketSize >> 8)
- b[6] = byte(d.bInterval)
- return b
-}
-
-const iadDescriptorSize = 8
-
-// IADDescriptor is an Interface Association Descriptor, which is used
-// to bind 2 interfaces together in CDC composite device.
-//
-// Standard Interface Association Descriptor:
-// bLength, bDescriptorType, bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass,
-// bFunctionProtocol, iFunction
-//
-type IADDescriptor struct {
- bLength uint8 // 8
- bDescriptorType uint8 // 11
- bFirstInterface uint8
- bInterfaceCount uint8
- bFunctionClass uint8
- bFunctionSubClass uint8
- bFunctionProtocol uint8
- iFunction uint8
-}
-
-// NewIADDescriptor returns a new USB IADDescriptor.
-func NewIADDescriptor(firstInterface, count, class, subClass, protocol uint8) IADDescriptor {
- return IADDescriptor{iadDescriptorSize, 11, firstInterface, count, class, subClass, protocol, 0}
-}
-
-// Bytes returns IADDescriptor data.
-func (d IADDescriptor) Bytes() [iadDescriptorSize]byte {
- var b [iadDescriptorSize]byte
- b[0] = byte(d.bLength)
- b[1] = byte(d.bDescriptorType)
- b[2] = byte(d.bFirstInterface)
- b[3] = byte(d.bInterfaceCount)
- b[4] = byte(d.bFunctionClass)
- b[5] = byte(d.bFunctionSubClass)
- b[6] = byte(d.bFunctionProtocol)
- b[7] = byte(d.iFunction)
- return b
-}
-
-const cdcCSInterfaceDescriptorSize = 5
-
-// CDCCSInterfaceDescriptor is a CDC CS interface descriptor.
-type CDCCSInterfaceDescriptor struct {
- len uint8 // 5
- dtype uint8 // 0x24
- subtype uint8
- d0 uint8
- d1 uint8
-}
-
-// NewCDCCSInterfaceDescriptor returns a new USB CDCCSInterfaceDescriptor.
-func NewCDCCSInterfaceDescriptor(subtype, d0, d1 uint8) CDCCSInterfaceDescriptor {
- return CDCCSInterfaceDescriptor{cdcCSInterfaceDescriptorSize, 0x24, subtype, d0, d1}
-}
-
-// Bytes returns CDCCSInterfaceDescriptor data.
-func (d CDCCSInterfaceDescriptor) Bytes() [cdcCSInterfaceDescriptorSize]byte {
- var b [cdcCSInterfaceDescriptorSize]byte
- b[0] = byte(d.len)
- b[1] = byte(d.dtype)
- b[2] = byte(d.subtype)
- b[3] = byte(d.d0)
- b[4] = byte(d.d1)
- return b
-}
-
-const cmFunctionalDescriptorSize = 5
-
-// CMFunctionalDescriptor is the functional descriptor general format.
-type CMFunctionalDescriptor struct {
- bFunctionLength uint8
- bDescriptorType uint8 // 0x24
- bDescriptorSubtype uint8 // 1
- bmCapabilities uint8
- bDataInterface uint8
-}
-
-// NewCMFunctionalDescriptor returns a new USB CMFunctionalDescriptor.
-func NewCMFunctionalDescriptor(subtype, d0, d1 uint8) CMFunctionalDescriptor {
- return CMFunctionalDescriptor{5, 0x24, subtype, d0, d1}
-}
-
-// Bytes returns the CMFunctionalDescriptor data.
-func (d CMFunctionalDescriptor) Bytes() [cmFunctionalDescriptorSize]byte {
- var b [cmFunctionalDescriptorSize]byte
- b[0] = byte(d.bFunctionLength)
- b[1] = byte(d.bDescriptorType)
- b[2] = byte(d.bDescriptorSubtype)
- b[3] = byte(d.bmCapabilities)
- b[4] = byte(d.bDescriptorSubtype)
- return b
-}
-
-const acmFunctionalDescriptorSize = 4
-
-// ACMFunctionalDescriptor is a Abstract Control Model (ACM) USB descriptor.
-type ACMFunctionalDescriptor struct {
- len uint8
- dtype uint8 // 0x24
- subtype uint8 // 1
- bmCapabilities uint8
-}
-
-// NewACMFunctionalDescriptor returns a new USB ACMFunctionalDescriptor.
-func NewACMFunctionalDescriptor(subtype, d0 uint8) ACMFunctionalDescriptor {
- return ACMFunctionalDescriptor{4, 0x24, subtype, d0}
-}
-
-// Bytes returns the ACMFunctionalDescriptor data.
-func (d ACMFunctionalDescriptor) Bytes() [acmFunctionalDescriptorSize]byte {
- var b [acmFunctionalDescriptorSize]byte
- b[0] = byte(d.len)
- b[1] = byte(d.dtype)
- b[2] = byte(d.subtype)
- b[3] = byte(d.bmCapabilities)
- return b
-}
-
-// CDCDescriptor is the Communication Device Class (CDC) descriptor.
-type CDCDescriptor struct {
- // IAD
- iad IADDescriptor // Only needed on compound device
-
- // Control
- cif InterfaceDescriptor
- header CDCCSInterfaceDescriptor
-
- // CDC control
- controlManagement ACMFunctionalDescriptor // ACM
- functionalDescriptor CDCCSInterfaceDescriptor // CDC_UNION
- callManagement CMFunctionalDescriptor // Call Management
- cifin EndpointDescriptor
-
- // CDC Data
- dif InterfaceDescriptor
- in EndpointDescriptor
- out EndpointDescriptor
-}
-
-func NewCDCDescriptor(i IADDescriptor, c InterfaceDescriptor,
- h CDCCSInterfaceDescriptor,
- cm ACMFunctionalDescriptor,
- fd CDCCSInterfaceDescriptor,
- callm CMFunctionalDescriptor,
- ci EndpointDescriptor,
- di InterfaceDescriptor,
- outp EndpointDescriptor,
- inp EndpointDescriptor) CDCDescriptor {
- return CDCDescriptor{iad: i,
- cif: c,
- header: h,
- controlManagement: cm,
- functionalDescriptor: fd,
- callManagement: callm,
- cifin: ci,
- dif: di,
- in: inp,
- out: outp}
-}
-
-const cdcSize = iadDescriptorSize +
- interfaceDescriptorSize +
- cdcCSInterfaceDescriptorSize +
- acmFunctionalDescriptorSize +
- cdcCSInterfaceDescriptorSize +
- cmFunctionalDescriptorSize +
- endpointDescriptorSize +
- interfaceDescriptorSize +
- endpointDescriptorSize +
- endpointDescriptorSize
-
-// Bytes returns CDCDescriptor data.
-func (d CDCDescriptor) Bytes() [cdcSize]byte {
- var b [cdcSize]byte
- offset := 0
-
- iad := d.iad.Bytes()
- copy(b[offset:], iad[:])
- offset += len(iad)
-
- cif := d.cif.Bytes()
- copy(b[offset:], cif[:])
- offset += len(cif)
-
- header := d.header.Bytes()
- copy(b[offset:], header[:])
- offset += len(header)
-
- controlManagement := d.controlManagement.Bytes()
- copy(b[offset:], controlManagement[:])
- offset += len(controlManagement)
-
- functionalDescriptor := d.functionalDescriptor.Bytes()
- copy(b[offset:], functionalDescriptor[:])
- offset += len(functionalDescriptor)
-
- callManagement := d.callManagement.Bytes()
- copy(b[offset:], callManagement[:])
- offset += len(callManagement)
-
- cifin := d.cifin.Bytes()
- copy(b[offset:], cifin[:])
- offset += len(cifin)
-
- dif := d.dif.Bytes()
- copy(b[offset:], dif[:])
- offset += len(dif)
-
- out := d.out.Bytes()
- copy(b[offset:], out[:])
- offset += len(out)
-
- in := d.in.Bytes()
- copy(b[offset:], in[:])
- offset += len(in)
-
- return b
-}
-
-// MSCDescriptor is not used yet.
-type MSCDescriptor struct {
- msc InterfaceDescriptor
- in EndpointDescriptor
- out EndpointDescriptor
-}
-
const cdcLineInfoSize = 7
type cdcLineInfo struct {
@@ -455,6 +64,8 @@ const (
usb_ENDPOINT_DESCRIPTOR_TYPE = 5
usb_DEVICE_QUALIFIER = 6
usb_OTHER_SPEED_CONFIGURATION = 7
+ usb_SET_REPORT_TYPE = 33
+ usb_HID_REPORT_TYPE = 34
usbEndpointOut = 0x00
usbEndpointIn = 0x80
@@ -474,6 +85,9 @@ const (
usb_GET_INTERFACE = 10
usb_SET_INTERFACE = 11
+ // non standard requests
+ usb_SET_IDLE = 10
+
usb_DEVICE_CLASS_COMMUNICATIONS = 0x02
usb_DEVICE_CLASS_HUMAN_INTERFACE = 0x03
usb_DEVICE_CLASS_STORAGE = 0x08
@@ -488,9 +102,12 @@ const (
usb_CDC_ACM_INTERFACE = 0 // CDC ACM
usb_CDC_DATA_INTERFACE = 1 // CDC Data
usb_CDC_FIRST_ENDPOINT = 1
- usb_CDC_ENDPOINT_ACM = 1
- usb_CDC_ENDPOINT_OUT = 2
- usb_CDC_ENDPOINT_IN = 3
+
+ // Endpoint
+ usb_CDC_ENDPOINT_ACM = 1
+ usb_CDC_ENDPOINT_OUT = 2
+ usb_CDC_ENDPOINT_IN = 3
+ usb_HID_ENDPOINT_IN = 4
// bmRequestType
usb_REQUEST_HOSTTODEVICE = 0x00
@@ -661,40 +278,43 @@ func (usbcdc *USBCDC) Receive(data byte) {
func sendDescriptor(setup usbSetup) {
switch setup.wValueH {
case usb_CONFIGURATION_DESCRIPTOR_TYPE:
- sendConfiguration(setup)
+ sendUSBPacket(0, usbDescriptor.Configuration, setup.wLength)
return
case usb_DEVICE_DESCRIPTOR_TYPE:
// composite descriptor
- dd := NewDeviceDescriptor(0xef, 0x02, 0x01, 64, usb_VID, usb_PID, 0x100, usb_IMANUFACTURER, usb_IPRODUCT, usb_ISERIAL, 1)
- l := deviceDescriptorSize
- if setup.wLength < deviceDescriptorSize {
- l = int(setup.wLength)
- }
- buf := dd.Bytes()
- sendUSBPacket(0, buf[:l])
+ usbDescriptor.Configure(usb_VID, usb_PID)
+ sendUSBPacket(0, usbDescriptor.Device, setup.wLength)
return
case usb_STRING_DESCRIPTOR_TYPE:
switch setup.wValueL {
case 0:
b := []byte{0x04, 0x03, 0x09, 0x04}
- sendUSBPacket(0, b)
+ sendUSBPacket(0, b, setup.wLength)
case usb_IPRODUCT:
b := make([]byte, (len(usb_STRING_PRODUCT)<<1)+2)
strToUTF16LEDescriptor(usb_STRING_PRODUCT, b)
- sendUSBPacket(0, b)
+ sendUSBPacket(0, b, setup.wLength)
case usb_IMANUFACTURER:
b := make([]byte, (len(usb_STRING_MANUFACTURER)<<1)+2)
strToUTF16LEDescriptor(usb_STRING_MANUFACTURER, b)
- sendUSBPacket(0, b)
+ sendUSBPacket(0, b, setup.wLength)
case usb_ISERIAL:
// TODO: allow returning a product serial number
sendZlp()
}
return
+ case usb_HID_REPORT_TYPE:
+ if h, ok := usbDescriptor.HID[setup.wIndex]; ok {
+ sendUSBPacket(0, h, setup.wLength)
+ return
+ }
+ case usb_DEVICE_QUALIFIER:
+ // skip
+ default:
}
// do not know how to handle this message, so return zero
@@ -702,54 +322,17 @@ func sendDescriptor(setup usbSetup) {
return
}
-// sendConfiguration creates and sends the configuration packet to the host.
-func sendConfiguration(setup usbSetup) {
- if setup.wLength == 9 {
- sz := uint16(configDescriptorSize + cdcSize)
- config := NewConfigDescriptor(sz, 2)
- configBuf := config.Bytes()
- sendUSBPacket(0, configBuf[:])
- } else {
- iad := NewIADDescriptor(0, 2, usb_CDC_COMMUNICATION_INTERFACE_CLASS, usb_CDC_ABSTRACT_CONTROL_MODEL, 0)
-
- cif := NewInterfaceDescriptor(usb_CDC_ACM_INTERFACE, 1, usb_CDC_COMMUNICATION_INTERFACE_CLASS, usb_CDC_ABSTRACT_CONTROL_MODEL, 0)
-
- header := NewCDCCSInterfaceDescriptor(usb_CDC_HEADER, usb_CDC_V1_10&0xFF, (usb_CDC_V1_10>>8)&0x0FF)
-
- controlManagement := NewACMFunctionalDescriptor(usb_CDC_ABSTRACT_CONTROL_MANAGEMENT, 6)
+// EnableHID enables HID. This function must be executed from the init().
+func EnableHID(callback func()) {
+ usbDescriptor = descriptorCDCHID
+ endPoints = []uint32{usb_ENDPOINT_TYPE_CONTROL,
+ (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn),
+ (usb_ENDPOINT_TYPE_BULK | usbEndpointOut),
+ (usb_ENDPOINT_TYPE_BULK | usbEndpointIn),
+ (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn)}
- functionalDescriptor := NewCDCCSInterfaceDescriptor(usb_CDC_UNION, usb_CDC_ACM_INTERFACE, usb_CDC_DATA_INTERFACE)
-
- callManagement := NewCMFunctionalDescriptor(usb_CDC_CALL_MANAGEMENT, 1, 1)
-
- cifin := NewEndpointDescriptor((usb_CDC_ENDPOINT_ACM | usbEndpointIn), usb_ENDPOINT_TYPE_INTERRUPT, 0x10, 0x10)
-
- dif := NewInterfaceDescriptor(usb_CDC_DATA_INTERFACE, 2, usb_CDC_DATA_INTERFACE_CLASS, 0, 0)
-
- out := NewEndpointDescriptor((usb_CDC_ENDPOINT_OUT | usbEndpointOut), usb_ENDPOINT_TYPE_BULK, usbEndpointPacketSize, 0)
-
- in := NewEndpointDescriptor((usb_CDC_ENDPOINT_IN | usbEndpointIn), usb_ENDPOINT_TYPE_BULK, usbEndpointPacketSize, 0)
-
- cdc := NewCDCDescriptor(iad,
- cif,
- header,
- controlManagement,
- functionalDescriptor,
- callManagement,
- cifin,
- dif,
- out,
- in)
-
- sz := uint16(configDescriptorSize + cdcSize)
- config := NewConfigDescriptor(sz, 2)
-
- configBuf := config.Bytes()
- cdcBuf := cdc.Bytes()
- var buf [configDescriptorSize + cdcSize]byte
- copy(buf[0:], configBuf[:])
- copy(buf[configDescriptorSize:], cdcBuf[:])
-
- sendUSBPacket(0, buf[:])
- }
+ hidCallback = callback
}
+
+// hidCallback is a variable that holds the callback when using HID.
+var hidCallback func()
diff --git a/src/machine/usb/hid/buffer.go b/src/machine/usb/hid/buffer.go
new file mode 100644
index 000000000..2674bbde9
--- /dev/null
+++ b/src/machine/usb/hid/buffer.go
@@ -0,0 +1,52 @@
+package hid
+
+import (
+ "runtime/volatile"
+)
+
+const bufferSize = 128
+
+// RingBuffer is ring buffer implementation inspired by post at
+// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php
+type RingBuffer struct {
+ rxbuffer [bufferSize][9]byte
+ head volatile.Register8
+ tail volatile.Register8
+}
+
+// NewRingBuffer returns a new ring buffer.
+func NewRingBuffer() *RingBuffer {
+ return &RingBuffer{}
+}
+
+// Used returns how many bytes in buffer have been used.
+func (rb *RingBuffer) Used() uint8 {
+ return uint8(rb.head.Get() - rb.tail.Get())
+}
+
+// Put stores a byte in the buffer. If the buffer is already
+// full, the method will return false.
+func (rb *RingBuffer) Put(val []byte) bool {
+ if rb.Used() != bufferSize {
+ rb.head.Set(rb.head.Get() + 1)
+ copy(rb.rxbuffer[rb.head.Get()%bufferSize][:], val)
+ return true
+ }
+ return false
+}
+
+// Get returns a byte from the buffer. If the buffer is empty,
+// the method will return a false as the second value.
+func (rb *RingBuffer) Get() ([]byte, bool) {
+ if rb.Used() != 0 {
+ rb.tail.Set(rb.tail.Get() + 1)
+ return rb.rxbuffer[rb.tail.Get()%bufferSize][:], true
+ }
+ return nil, false
+}
+
+// Clear resets the head and tail pointer to zero.
+func (rb *RingBuffer) Clear() {
+ rb.head.Set(0)
+ rb.tail.Set(0)
+}
diff --git a/src/machine/usb/hid/hid.go b/src/machine/usb/hid/hid.go
new file mode 100644
index 000000000..fd9317511
--- /dev/null
+++ b/src/machine/usb/hid/hid.go
@@ -0,0 +1,51 @@
+package hid
+
+import (
+ "errors"
+ "machine"
+)
+
+// from usb-hid.go
+var (
+ ErrHIDInvalidPort = errors.New("invalid USB port")
+ ErrHIDInvalidCore = errors.New("invalid USB core")
+ ErrHIDReportTransfer = errors.New("failed to transfer HID report")
+)
+
+const (
+ hidEndpoint = 4
+)
+
+type hidDevicer interface {
+ Callback() bool
+}
+
+var devices [5]hidDevicer
+var size int
+
+// SetCallbackHandler sets the callback. Only the first time it is called, it
+// calls machine.EnableHID for USB configuration
+func SetCallbackHandler(d hidDevicer) {
+ if size == 0 {
+ machine.EnableHID(callback)
+ }
+
+ devices[size] = d
+ size++
+}
+
+func callback() {
+ for _, d := range devices {
+ if d == nil {
+ continue
+ }
+ if done := d.Callback(); done {
+ return
+ }
+ }
+}
+
+// SendUSBPacket sends a HIDPacket.
+func SendUSBPacket(b []byte) {
+ machine.SendUSBHIDPacket(hidEndpoint, b)
+}
diff --git a/src/machine/usb/hid/keyboard/keyboard.go b/src/machine/usb/hid/keyboard/keyboard.go
new file mode 100644
index 000000000..1f5643385
--- /dev/null
+++ b/src/machine/usb/hid/keyboard/keyboard.go
@@ -0,0 +1,478 @@
+package keyboard
+
+import (
+ "errors"
+ "machine/usb/hid"
+)
+
+// from usb-hid-keyboard.go
+var (
+ ErrInvalidCodepoint = errors.New("invalid Unicode codepoint")
+ ErrInvalidKeycode = errors.New("invalid keyboard keycode")
+ ErrInvalidUTF8 = errors.New("invalid UTF-8 encoding")
+ ErrKeypressMaximum = errors.New("maximum keypresses exceeded")
+)
+
+var Keyboard *keyboard
+
+// Keyboard represents a USB HID keyboard device with support for international
+// layouts and various control, system, multimedia, and consumer keycodes.
+//
+// Keyboard implements the io.Writer interface that translates UTF-8 encoded
+// byte strings into sequences of keypress events.
+type keyboard struct {
+ // led holds the current state of all keyboard LEDs:
+ // 1=NumLock 2=CapsLock 4=ScrollLock 8=Compose 16=Kana
+ led uint8
+
+ // mod holds the current state of all keyboard modifier keys:
+ // 1=LeftCtrl 2=LeftShift 4=LeftAlt 8=LeftGUI
+ // 16=RightCtrl 32=RightShift 64=RightAlt 128=RightGUI
+ mod uint8
+
+ // key holds a list of all keyboard keys currently pressed.
+ key [hidKeyboardKeyCount]uint8
+ con [hidKeyboardConCount]uint16
+ sys [hidKeyboardSysCount]uint8
+
+ // decode holds the current state of the UTF-8 decoder.
+ decode decodeState
+
+ // wideChar holds high bits for the UTF-8 decoder.
+ wideChar uint16
+
+ buf *hid.RingBuffer
+}
+
+// decodeState represents a state in the UTF-8 decode state machine.
+type decodeState uint8
+
+// Constant enumerated values of type decodeState.
+const (
+ decodeReset decodeState = iota
+ decodeByte1
+ decodeByte2
+ decodeByte3
+)
+
+func init() {
+ if Keyboard == nil {
+ Keyboard = newKeyboard()
+ hid.SetCallbackHandler(Keyboard)
+ }
+}
+
+// New returns hid-keybord.
+func New() *keyboard {
+ return Keyboard
+}
+
+func newKeyboard() *keyboard {
+ return &keyboard{
+ buf: hid.NewRingBuffer(),
+ }
+}
+
+func (kb *keyboard) Callback() bool {
+ if b, ok := kb.buf.Get(); ok {
+ hid.SendUSBPacket(b)
+ return true
+ }
+ return false
+}
+
+func (kb *keyboard) ready() bool {
+ return true
+}
+
+// Write transmits press-and-release key sequences for each Keycode translated
+// from the given UTF-8 byte string. Write implements the io.Writer interface
+// and conforms to all documented conventions for arguments and return values.
+func (kb *keyboard) Write(b []byte) (n int, err error) {
+ for _, c := range b {
+ if err = kb.WriteByte(c); nil != err {
+ break
+ }
+ n += 1
+ }
+ return
+}
+
+// WriteByte processes a single byte from a UTF-8 byte string. This method is a
+// stateful method with respect to the receiver Keyboard, meaning that its exact
+// behavior will depend on the current state of its UTF-8 decode state machine:
+//
+// (a) If the given byte is a valid ASCII encoding (0-127), then a keypress
+// sequence is immediately transmitted for the respective Keycode.
+//
+// (b) If the given byte represents the final byte in a multi-byte codepoint,
+// then a keypress sequence is immediately transmitted by translating the
+// multi-byte codepoint to its respective Keycode.
+//
+// (c) If the given byte appears to represent high bits for a multi-byte
+// codepoint, then the bits are copied to the receiver's internal state
+// machine buffer for use by a subsequent call to WriteByte() (or Write())
+// that completes the codepoint.
+//
+// (d) If the given byte is out of range, or contains illegal bits for the
+// current state of the UTF-8 decoder, then the UTF-8 decode state machine
+// is reset to its initial state.
+//
+// In cases (c) and (d), a keypress sequence is not generated and no data is
+// transmitted. In case (c), additional bytes must be received via WriteByte()
+// (or Write()) to complete or discard the current codepoint.
+func (kb *keyboard) WriteByte(b byte) error {
+ switch {
+ case b < 0x80:
+ // 1-byte encoding (0x00-0x7F)
+ kb.decode = decodeByte1
+ return kb.write(uint16(b))
+
+ case b < 0xC0:
+ // 2nd, 3rd, or 4th byte (0x80-0xBF)
+ b = Keycode(b).key()
+ switch kb.decode {
+ case decodeByte2:
+ kb.decode = decodeByte1
+ return kb.write(kb.wideChar | uint16(b))
+ case decodeByte3:
+ kb.decode = decodeByte2
+ kb.wideChar |= uint16(b) << 6
+ }
+
+ case b < 0xE0:
+ // 2-byte encoding (0xC2-0xDF), or illegal byte 2 (0xC0-0xC1)
+ kb.decode = decodeByte2
+ kb.wideChar = uint16(b&0x1F) << 6
+
+ case b < 0xF0:
+ // 3-byte encoding (0xE0-0xEF)
+ kb.decode = decodeByte3
+ kb.wideChar = uint16(b&0x0F) << 12
+
+ default:
+ // 4-byte encoding unsupported (0xF0-0xF4), or illegal byte 4 (0xF5-0xFF)
+ kb.decode = decodeReset
+ return ErrInvalidUTF8
+ }
+ return nil
+}
+
+func (kb *keyboard) write(p uint16) error {
+ c := keycode(p)
+ if 0 == c {
+ return ErrInvalidCodepoint
+ }
+ if d := deadkey(c); 0 != d {
+ if err := kb.writeKeycode(d); nil != err {
+ return err
+ }
+ }
+ return kb.writeKeycode(c)
+}
+
+func (kb *keyboard) writeKeycode(c Keycode) error {
+ var b [9]byte
+ b[0] = 0x02
+ b[1] = c.mod()
+ b[2] = 0
+ b[3] = c.key()
+ b[4] = 0
+ b[5] = 0
+ b[6] = 0
+ b[7] = 0
+ b[8] = 0
+ if !kb.sendKey(false, b[:]) {
+ return hid.ErrHIDReportTransfer
+ }
+
+ b[1] = 0
+ b[3] = 0
+ if !kb.sendKey(false, b[:]) {
+ return hid.ErrHIDReportTransfer
+ }
+ return nil
+}
+
+// Press transmits a press-and-release sequence for the given Keycode, which
+// simulates a discrete keypress event.
+//
+// The following values of Keycode are supported:
+//
+// 0x0020 - 0x007F ASCII (U+0020 to U+007F) [USES LAYOUT]
+// 0x0080 - 0xC1FF Unicode (U+0080 to U+C1FF) [USES LAYOUT]
+// 0xC200 - 0xDFFF UTF-8 packed (U+0080 to U+07FF) [USES LAYOUT]
+// 0xE000 - 0xE0FF Modifier key (bitmap, 8 keys, Shift/Ctrl/Alt/GUI)
+// 0xE200 - 0xE2FF System key (HID usage code, page 1)
+// 0xE400 - 0xE7FF Media/Consumer key (HID usage code, page 12)
+// 0xF000 - 0xFFFF Normal key (HID usage code, page 7)
+func (kb *keyboard) Press(c Keycode) error {
+ if err := kb.Down(c); nil != err {
+ return err
+ }
+ return kb.Up(c)
+}
+
+func (kb *keyboard) sendKey(consumer bool, b []byte) bool {
+ kb.buf.Put(b)
+ return true
+}
+
+func (kb *keyboard) keyboardSendKeys(consumer bool) bool {
+ var b [9]byte
+ b[0] = 0x02
+ b[1] = kb.mod
+ b[2] = 0x02
+ b[3] = kb.key[0]
+ b[4] = kb.key[1]
+ b[5] = kb.key[2]
+ b[6] = kb.key[3]
+ b[7] = kb.key[4]
+ b[8] = kb.key[5]
+ return kb.sendKey(consumer, b[:])
+}
+
+// Down transmits a key-down event for the given Keycode.
+//
+// The host will interpret the key as being held down continuously until a
+// corresponding key-up event is transmitted, e.g., via method Up().
+//
+// See godoc comment on method Press() for details on what input is accepted and
+// how it is interpreted.
+func (kb *keyboard) Down(c Keycode) error {
+ var res uint8
+ msb := c >> 8
+ if msb >= 0xC2 {
+ if msb < 0xE0 {
+ c = ((msb & 0x1F) << 6) | Keycode(c.key())
+ } else {
+ switch msb {
+ case 0xF0:
+ return kb.down(uint8(c), 0)
+
+ case 0xE0:
+ return kb.down(0, uint8(c))
+
+ case 0xE2:
+ return kb.downSys(uint8(c))
+
+ default:
+ if 0xE4 <= msb && msb <= 0xE7 {
+ return kb.downCon(uint16(c & 0x03FF))
+ }
+ return ErrInvalidKeycode
+ }
+ }
+ }
+ c = keycode(uint16(c))
+ if 0 == c {
+ return ErrInvalidCodepoint
+ }
+ if d := deadkey(c); 0 != d {
+ res = kb.mod
+ if 0 != res {
+ kb.mod = 0
+ kb.keyboardSendKeys(false)
+ }
+ kb.down(d.key(), d.mod())
+ kb.up(d.key(), d.mod())
+ }
+ return kb.down(c.key(), c.mod()|res)
+}
+
+func (kb *keyboard) down(key uint8, mod uint8) error {
+ send := false
+ if 0 != mod {
+ if kb.mod&mod != mod {
+ kb.mod |= mod
+ send = true
+ }
+ }
+ if 0 != key {
+ for _, k := range kb.key {
+ if k == key {
+ goto end
+ }
+ }
+ for i, k := range kb.key {
+ if 0 == k {
+ kb.key[i] = key
+ send = true
+ goto end
+ }
+ }
+ return ErrKeypressMaximum
+ }
+end:
+ if send {
+ if !kb.keyboardSendKeys(false) {
+ return hid.ErrHIDReportTransfer
+ }
+ }
+ return nil
+}
+
+func (kb *keyboard) downCon(key uint16) error {
+ if 0 == key {
+ return ErrInvalidKeycode
+ }
+ for _, k := range kb.con {
+ if key == k {
+ return nil // already pressed
+ }
+ }
+ for i, k := range kb.con {
+ if 0 == k {
+ kb.con[i] = key
+ if !kb.keyboardSendKeys(true) {
+ return hid.ErrHIDReportTransfer
+ }
+ return nil
+ }
+ }
+ return ErrKeypressMaximum
+}
+
+func (kb *keyboard) downSys(key uint8) error {
+ if 0 == key {
+ return ErrInvalidKeycode
+ }
+ for _, k := range kb.sys {
+ if key == k {
+ return nil // already pressed
+ }
+ }
+ for i, k := range kb.sys {
+ if 0 == k {
+ kb.sys[i] = key
+ if !kb.keyboardSendKeys(true) {
+ return hid.ErrHIDReportTransfer
+ }
+ return nil
+ }
+ }
+ return ErrKeypressMaximum
+}
+
+// Up transmits a key-up event for the given Keycode.
+//
+// See godoc comment on method Press() for details on what input is accepted and
+// how it is interpreted.
+func (kb *keyboard) Up(c Keycode) error {
+ msb := c >> 8
+ if msb >= 0xC2 {
+ if msb < 0xE0 {
+ c = ((msb & 0x1F) << 6) | Keycode(c.key())
+ } else {
+ switch msb {
+ case 0xF0:
+ return kb.up(uint8(c), 0)
+
+ case 0xE0:
+ return kb.up(0, uint8(c))
+
+ case 0xE2:
+ return kb.upSys(uint8(c))
+
+ default:
+ if 0xE4 <= msb && msb <= 0xE7 {
+ return kb.upCon(uint16(c & 0x03FF))
+ }
+ return ErrInvalidKeycode
+ }
+ }
+ }
+ c = keycode(uint16(c))
+ if 0 == c {
+ return ErrInvalidCodepoint
+ }
+ return kb.up(c.key(), c.mod())
+}
+
+// Release transmits a key-up event for all keyboard keys currently pressed as
+// if the user removed his/her hands from the keyboard entirely.
+func (kb *keyboard) Release() error {
+
+ bits := uint16(kb.mod)
+ kb.mod = 0
+ for i, k := range kb.key {
+ bits |= uint16(k)
+ kb.key[i] = 0
+ }
+ if 0 != bits {
+ if !kb.keyboardSendKeys(false) {
+ return hid.ErrHIDReportTransfer
+ }
+ }
+ bits = 0
+ for i, k := range kb.con {
+ bits |= k
+ kb.con[i] = 0
+ }
+ for i, k := range kb.sys {
+ bits |= uint16(k)
+ kb.sys[i] = 0
+ }
+ if 0 != bits {
+ if !kb.keyboardSendKeys(true) {
+ return hid.ErrHIDReportTransfer
+ }
+ }
+ return nil
+}
+
+func (kb *keyboard) up(key uint8, mod uint8) error {
+ send := false
+ if 0 != mod {
+ if kb.mod&mod != 0 {
+ kb.mod &^= mod
+ send = true
+ }
+ }
+ if 0 != key {
+ for i, k := range kb.key {
+ if key == k {
+ kb.key[i] = 0
+ send = true
+ }
+ }
+ }
+ if send {
+ if !kb.keyboardSendKeys(false) {
+ return hid.ErrHIDReportTransfer
+ }
+ }
+ return nil
+}
+
+func (kb *keyboard) upCon(key uint16) error {
+ if 0 == key {
+ return ErrInvalidKeycode
+ }
+ for i, k := range kb.con {
+ if key == k {
+ kb.con[i] = 0
+ if !kb.keyboardSendKeys(true) {
+ return hid.ErrHIDReportTransfer
+ }
+ return nil
+ }
+ }
+ return nil
+}
+
+func (kb *keyboard) upSys(key uint8) error {
+ if 0 == key {
+ return ErrInvalidKeycode
+ }
+ for i, k := range kb.sys {
+ if key == k {
+ kb.sys[i] = 0
+ if !kb.keyboardSendKeys(true) {
+ return hid.ErrHIDReportTransfer
+ }
+ return nil
+ }
+ }
+ return nil
+}
diff --git a/src/machine/usb/hid/keyboard/keycode.go b/src/machine/usb/hid/keyboard/keycode.go
new file mode 100644
index 000000000..c9e3b9350
--- /dev/null
+++ b/src/machine/usb/hid/keyboard/keycode.go
@@ -0,0 +1,532 @@
+package keyboard
+
+// Keycode is a package-defined bitmap used to encode the value of a given key.
+type Keycode uint16
+
+// keycode returns the given Unicode codepoint translated to a Keycode sequence.
+// Unicode codepoints greater than U+FFFF are unsupported.
+//go:inline
+func keycode(p uint16) Keycode {
+ if p < 0x80 {
+ return ascii[p]
+ } else if p >= 0xA0 && p < 0x0100 {
+ return iso88591[p-0xA0]
+ } else if uint16(UNICODE20AC) == p {
+ return UNICODE20AC.mask()
+ }
+ return 0
+}
+
+//go:inline
+func deadkey(c Keycode) Keycode {
+ switch c & deadkeysMask {
+ case acuteAccentBits:
+ return deadkeyAcuteAccent
+ case circumflexBits:
+ return deadkeyCircumflex
+ case diaeresisBits:
+ return deadkeyDiaeresis
+ case graveAccentBits:
+ return deadkeyGraveAccent
+ case tildeBits:
+ return deadkeyTilde
+ }
+ return 0
+}
+
+//go:inline
+func (c Keycode) mask() Keycode { return c & keycodeMask }
+
+//go:inline
+func (c Keycode) key() uint8 { return uint8(c & keyMask) }
+
+//go:inline
+func (c Keycode) mod() uint8 {
+ var m Keycode
+ if 0 != c&shiftMask {
+ m |= KeyModifierShift
+ }
+ if 0 != c&altgrMask {
+ m |= KeyModifierRightAlt
+ }
+ return uint8(m)
+}
+
+//go:inline
+func (c Keycode) Shift() Keycode { return c | KeyModifierShift }
+
+const (
+ hidKeyboardKeyCount = 6 // Max number of simultaneous keypresses
+ hidKeyboardSysCount = 3
+ hidKeyboardConCount = 4
+)
+
+// Keycodes common to all Keyboard layouts
+const (
+ KeyModifierCtrl Keycode = 0x01 | 0xE000
+ KeyModifierShift Keycode = 0x02 | 0xE000
+ KeyModifierAlt Keycode = 0x04 | 0xE000
+ KeyModifierGUI Keycode = 0x08 | 0xE000
+ KeyModifierLeftCtrl Keycode = 0x01 | 0xE000
+ KeyModifierLeftShift Keycode = 0x02 | 0xE000
+ KeyModifierLeftAlt Keycode = 0x04 | 0xE000
+ KeyModifierLeftGUI Keycode = 0x08 | 0xE000
+ KeyModifierRightCtrl Keycode = 0x10 | 0xE000
+ KeyModifierRightShift Keycode = 0x20 | 0xE000
+ KeyModifierRightAlt Keycode = 0x40 | 0xE000
+ KeyModifierRightGUI Keycode = 0x80 | 0xE000
+
+ KeySystemPowerDown Keycode = 0x81 | 0xE200
+ KeySystemSleep Keycode = 0x82 | 0xE200
+ KeySystemWakeUp Keycode = 0x83 | 0xE200
+
+ KeyMediaPlay Keycode = 0xB0 | 0xE400
+ KeyMediaPause Keycode = 0xB1 | 0xE400
+ KeyMediaRecord Keycode = 0xB2 | 0xE400
+ KeyMediaFastForward Keycode = 0xB3 | 0xE400
+ KeyMediaRewind Keycode = 0xB4 | 0xE400
+ KeyMediaNextTrack Keycode = 0xB5 | 0xE400
+ KeyMediaPrevTrack Keycode = 0xB6 | 0xE400
+ KeyMediaStop Keycode = 0xB7 | 0xE400
+ KeyMediaEject Keycode = 0xB8 | 0xE400
+ KeyMediaRandomPlay Keycode = 0xB9 | 0xE400
+ KeyMediaPlayPause Keycode = 0xCD | 0xE400
+ KeyMediaPlaySkip Keycode = 0xCE | 0xE400
+ KeyMediaMute Keycode = 0xE2 | 0xE400
+ KeyMediaVolumeInc Keycode = 0xE9 | 0xE400
+ KeyMediaVolumeDec Keycode = 0xEA | 0xE400
+
+ KeyA Keycode = 4 | 0xF000
+ KeyB Keycode = 5 | 0xF000
+ KeyC Keycode = 6 | 0xF000
+ KeyD Keycode = 7 | 0xF000
+ KeyE Keycode = 8 | 0xF000
+ KeyF Keycode = 9 | 0xF000
+ KeyG Keycode = 10 | 0xF000
+ KeyH Keycode = 11 | 0xF000
+ KeyI Keycode = 12 | 0xF000
+ KeyJ Keycode = 13 | 0xF000
+ KeyK Keycode = 14 | 0xF000
+ KeyL Keycode = 15 | 0xF000
+ KeyM Keycode = 16 | 0xF000
+ KeyN Keycode = 17 | 0xF000
+ KeyO Keycode = 18 | 0xF000
+ KeyP Keycode = 19 | 0xF000
+ KeyQ Keycode = 20 | 0xF000
+ KeyR Keycode = 21 | 0xF000
+ KeyS Keycode = 22 | 0xF000
+ KeyT Keycode = 23 | 0xF000
+ KeyU Keycode = 24 | 0xF000
+ KeyV Keycode = 25 | 0xF000
+ KeyW Keycode = 26 | 0xF000
+ KeyX Keycode = 27 | 0xF000
+ KeyY Keycode = 28 | 0xF000
+ KeyZ Keycode = 29 | 0xF000
+ Key1 Keycode = 30 | 0xF000
+ Key2 Keycode = 31 | 0xF000
+ Key3 Keycode = 32 | 0xF000
+ Key4 Keycode = 33 | 0xF000
+ Key5 Keycode = 34 | 0xF000
+ Key6 Keycode = 35 | 0xF000
+ Key7 Keycode = 36 | 0xF000
+ Key8 Keycode = 37 | 0xF000
+ Key9 Keycode = 38 | 0xF000
+ Key0 Keycode = 39 | 0xF000
+ KeyEnter Keycode = 40 | 0xF000
+ KeyEsc Keycode = 41 | 0xF000
+ KeyBackspace Keycode = 42 | 0xF000
+ KeyTab Keycode = 43 | 0xF000
+ KeySpace Keycode = 44 | 0xF000
+ KeyMinus Keycode = 45 | 0xF000
+ KeyEqual Keycode = 46 | 0xF000
+ KeyLeftBrace Keycode = 47 | 0xF000
+ KeyRightBrace Keycode = 48 | 0xF000
+ KeyBackslash Keycode = 49 | 0xF000
+ KeyNonUsNum Keycode = 50 | 0xF000
+ KeySemicolon Keycode = 51 | 0xF000
+ KeyQuote Keycode = 52 | 0xF000
+ KeyTilde Keycode = 53 | 0xF000
+ KeyComma Keycode = 54 | 0xF000
+ KeyPeriod Keycode = 55 | 0xF000
+ KeySlash Keycode = 56 | 0xF000
+ KeyCapsLock Keycode = 57 | 0xF000
+ KeyF1 Keycode = 58 | 0xF000
+ KeyF2 Keycode = 59 | 0xF000
+ KeyF3 Keycode = 60 | 0xF000
+ KeyF4 Keycode = 61 | 0xF000
+ KeyF5 Keycode = 62 | 0xF000
+ KeyF6 Keycode = 63 | 0xF000
+ KeyF7 Keycode = 64 | 0xF000
+ KeyF8 Keycode = 65 | 0xF000
+ KeyF9 Keycode = 66 | 0xF000
+ KeyF10 Keycode = 67 | 0xF000
+ KeyF11 Keycode = 68 | 0xF000
+ KeyF12 Keycode = 69 | 0xF000
+ KeyPrintscreen Keycode = 70 | 0xF000
+ KeyScrollLock Keycode = 71 | 0xF000
+ KeyPause Keycode = 72 | 0xF000
+ KeyInsert Keycode = 73 | 0xF000
+ KeyHome Keycode = 74 | 0xF000
+ KeyPageUp Keycode = 75 | 0xF000
+ KeyDelete Keycode = 76 | 0xF000
+ KeyEnd Keycode = 77 | 0xF000
+ KeyPageDown Keycode = 78 | 0xF000
+ KeyRight Keycode = 79 | 0xF000
+ KeyLeft Keycode = 80 | 0xF000
+ KeyDown Keycode = 81 | 0xF000
+ KeyUp Keycode = 82 | 0xF000
+ KeyNumLock Keycode = 83 | 0xF000
+ KeypadSlash Keycode = 84 | 0xF000
+ KeypadAsterisk Keycode = 85 | 0xF000
+ KeypadMinus Keycode = 86 | 0xF000
+ KeypadPlus Keycode = 87 | 0xF000
+ KeypadEnter Keycode = 88 | 0xF000
+ Keypad1 Keycode = 89 | 0xF000
+ Keypad2 Keycode = 90 | 0xF000
+ Keypad3 Keycode = 91 | 0xF000
+ Keypad4 Keycode = 92 | 0xF000
+ Keypad5 Keycode = 93 | 0xF000
+ Keypad6 Keycode = 94 | 0xF000
+ Keypad7 Keycode = 95 | 0xF000
+ Keypad8 Keycode = 96 | 0xF000
+ Keypad9 Keycode = 97 | 0xF000
+ Keypad0 Keycode = 98 | 0xF000
+ KeypadPeriod Keycode = 99 | 0xF000
+ KeyNonUSBS Keycode = 100 | 0xF000
+ KeyMenu Keycode = 101 | 0xF000
+ KeyF13 Keycode = 104 | 0xF000
+ KeyF14 Keycode = 105 | 0xF000
+ KeyF15 Keycode = 106 | 0xF000
+ KeyF16 Keycode = 107 | 0xF000
+ KeyF17 Keycode = 108 | 0xF000
+ KeyF18 Keycode = 109 | 0xF000
+ KeyF19 Keycode = 110 | 0xF000
+ KeyF20 Keycode = 111 | 0xF000
+ KeyF21 Keycode = 112 | 0xF000
+ KeyF22 Keycode = 113 | 0xF000
+ KeyF23 Keycode = 114 | 0xF000
+ KeyF24 Keycode = 115 | 0xF000
+
+ KeyUpArrow Keycode = KeyUp
+ KeyDownArrow Keycode = KeyDown
+ KeyLeftArrow Keycode = KeyLeft
+ KeyRightArrow Keycode = KeyRight
+ KeyReturn Keycode = KeyEnter
+ KeyLeftCtrl Keycode = KeyModifierLeftCtrl
+ KeyLeftShift Keycode = KeyModifierLeftShift
+ KeyLeftAlt Keycode = KeyModifierLeftAlt
+ KeyLeftGUI Keycode = KeyModifierLeftGUI
+ KeyRightCtrl Keycode = KeyModifierRightCtrl
+ KeyRightShift Keycode = KeyModifierRightShift
+ KeyRightAlt Keycode = KeyModifierRightAlt
+ KeyRightGUI Keycode = KeyModifierRightGUI
+)
+
+// Keycodes for layout US English (0x0904)
+const (
+ keycodeMask Keycode = 0x07FF
+ keyMask Keycode = 0x003F
+
+ shiftMask Keycode = 0x0040
+ altgrMask Keycode = 0x0080
+ deadkeysMask Keycode = 0x0700
+ circumflexBits Keycode = 0x0100
+ acuteAccentBits Keycode = 0x0200
+ graveAccentBits Keycode = 0x0300
+ tildeBits Keycode = 0x0400
+ diaeresisBits Keycode = 0x0500
+ deadkeyCircumflex Keycode = Key6 | shiftMask
+ deadkeyAcuteAccent Keycode = KeyQuote
+ deadkeyGraveAccent Keycode = KeyTilde
+ deadkeyTilde Keycode = KeyTilde | shiftMask
+ deadkeyDiaeresis Keycode = KeyQuote | shiftMask
+
+ ASCII00 Keycode = 0 // 0 NUL
+ ASCII01 Keycode = 0 // 1 SOH
+ ASCII02 Keycode = 0 // 2 STX
+ ASCII03 Keycode = 0 // 3 ETX
+ ASCII04 Keycode = 0 // 4 EOT
+ ASCII05 Keycode = 0 // 5 ENQ
+ ASCII06 Keycode = 0 // 6 ACK
+ ASCII07 Keycode = 0 // 7 BEL
+ ASCII08 Keycode = KeyBackspace // 8 BS
+ ASCII09 Keycode = KeyTab // 9 TAB
+ ASCII0A Keycode = KeyEnter // 10 LF
+ ASCII0B Keycode = 0 // 11 VT
+ ASCII0C Keycode = 0 // 12 FF
+ ASCII0D Keycode = 0 // 13 CR
+ ASCII0E Keycode = 0 // 14 SO
+ ASCII0F Keycode = 0 // 15 SI
+ ASCII10 Keycode = 0 // 16 DEL
+ ASCII11 Keycode = 0 // 17 DC1
+ ASCII12 Keycode = 0 // 18 DC2
+ ASCII13 Keycode = 0 // 19 DC3
+ ASCII14 Keycode = 0 // 20 DC4
+ ASCII15 Keycode = 0 // 21 NAK
+ ASCII16 Keycode = 0 // 22 SYN
+ ASCII17 Keycode = 0 // 23 ETB
+ ASCII18 Keycode = 0 // 24 CAN
+ ASCII19 Keycode = 0 // 25 EM
+ ASCII1A Keycode = 0 // 26 SUB
+ ASCII1B Keycode = 0 // 27 ESC
+ ASCII1C Keycode = 0 // 28 FS
+ ASCII1D Keycode = 0 // 29 GS
+ ASCII1E Keycode = 0 // 30 RS
+ ASCII1F Keycode = 0 // 31 US
+
+ ASCII20 Keycode = KeySpace // 32 SPACE
+ ASCII21 Keycode = Key1 | shiftMask // 33 !
+ ASCII22 Keycode = diaeresisBits | KeySpace // 34 "
+ ASCII23 Keycode = Key3 | shiftMask // 35 #
+ ASCII24 Keycode = Key4 | shiftMask // 36 $
+ ASCII25 Keycode = Key5 | shiftMask // 37 %
+ ASCII26 Keycode = Key7 | shiftMask // 38 &
+ ASCII27 Keycode = acuteAccentBits | KeySpace // 39 '
+ ASCII28 Keycode = Key9 | shiftMask // 40 (
+ ASCII29 Keycode = Key0 | shiftMask // 41 )
+ ASCII2A Keycode = Key8 | shiftMask // 42 *
+ ASCII2B Keycode = KeyEqual | shiftMask // 43 +
+ ASCII2C Keycode = KeyComma // 44 ,
+ ASCII2D Keycode = KeyMinus // 45 -
+ ASCII2E Keycode = KeyPeriod // 46 .
+ ASCII2F Keycode = KeySlash // 47 /
+ ASCII30 Keycode = Key0 // 48 0
+ ASCII31 Keycode = Key1 // 49 1
+ ASCII32 Keycode = Key2 // 50 2
+ ASCII33 Keycode = Key3 // 51 3
+ ASCII34 Keycode = Key4 // 52 4
+ ASCII35 Keycode = Key5 // 53 5
+ ASCII36 Keycode = Key6 // 54 6
+ ASCII37 Keycode = Key7 // 55 7
+ ASCII38 Keycode = Key8 // 55 8
+ ASCII39 Keycode = Key9 // 57 9
+ ASCII3A Keycode = KeySemicolon | shiftMask // 58 :
+ ASCII3B Keycode = KeySemicolon // 59 ;
+ ASCII3C Keycode = KeyComma | shiftMask // 60 <
+ ASCII3D Keycode = KeyEqual // 61 =
+ ASCII3E Keycode = KeyPeriod | shiftMask // 62 >
+ ASCII3F Keycode = KeySlash | shiftMask // 63 ?
+ ASCII40 Keycode = Key2 | shiftMask // 64 @
+ ASCII41 Keycode = KeyA | shiftMask // 65 A
+ ASCII42 Keycode = KeyB | shiftMask // 66 B
+ ASCII43 Keycode = KeyC | shiftMask // 67 C
+ ASCII44 Keycode = KeyD | shiftMask // 68 D
+ ASCII45 Keycode = KeyE | shiftMask // 69 E
+ ASCII46 Keycode = KeyF | shiftMask // 70 F
+ ASCII47 Keycode = KeyG | shiftMask // 71 G
+ ASCII48 Keycode = KeyH | shiftMask // 72 H
+ ASCII49 Keycode = KeyI | shiftMask // 73 I
+ ASCII4A Keycode = KeyJ | shiftMask // 74 J
+ ASCII4B Keycode = KeyK | shiftMask // 75 K
+ ASCII4C Keycode = KeyL | shiftMask // 76 L
+ ASCII4D Keycode = KeyM | shiftMask // 77 M
+ ASCII4E Keycode = KeyN | shiftMask // 78 N
+ ASCII4F Keycode = KeyO | shiftMask // 79 O
+ ASCII50 Keycode = KeyP | shiftMask // 80 P
+ ASCII51 Keycode = KeyQ | shiftMask // 81 Q
+ ASCII52 Keycode = KeyR | shiftMask // 82 R
+ ASCII53 Keycode = KeyS | shiftMask // 83 S
+ ASCII54 Keycode = KeyT | shiftMask // 84 T
+ ASCII55 Keycode = KeyU | shiftMask // 85 U
+ ASCII56 Keycode = KeyV | shiftMask // 86 V
+ ASCII57 Keycode = KeyW | shiftMask // 87 W
+ ASCII58 Keycode = KeyX | shiftMask // 88 X
+ ASCII59 Keycode = KeyY | shiftMask // 89 Y
+ ASCII5A Keycode = KeyZ | shiftMask // 90 Z
+ ASCII5B Keycode = KeyLeftBrace // 91 [
+ ASCII5C Keycode = KeyBackslash // 92 \
+ ASCII5D Keycode = KeyRightBrace // 93 ]
+ ASCII5E Keycode = circumflexBits | KeySpace // 94 ^
+ ASCII5F Keycode = KeyMinus | shiftMask // 95
+ ASCII60 Keycode = graveAccentBits | KeySpace // 96 `
+ ASCII61 Keycode = KeyA // 97 a
+ ASCII62 Keycode = KeyB // 98 b
+ ASCII63 Keycode = KeyC // 99 c
+ ASCII64 Keycode = KeyD // 100 d
+ ASCII65 Keycode = KeyE // 101 e
+ ASCII66 Keycode = KeyF // 102 f
+ ASCII67 Keycode = KeyG // 103 g
+ ASCII68 Keycode = KeyH // 104 h
+ ASCII69 Keycode = KeyI // 105 i
+ ASCII6A Keycode = KeyJ // 106 j
+ ASCII6B Keycode = KeyK // 107 k
+ ASCII6C Keycode = KeyL // 108 l
+ ASCII6D Keycode = KeyM // 109 m
+ ASCII6E Keycode = KeyN // 110 n
+ ASCII6F Keycode = KeyO // 111 o
+ ASCII70 Keycode = KeyP // 112 p
+ ASCII71 Keycode = KeyQ // 113 q
+ ASCII72 Keycode = KeyR // 114 r
+ ASCII73 Keycode = KeyS // 115 s
+ ASCII74 Keycode = KeyT // 116 t
+ ASCII75 Keycode = KeyU // 117 u
+ ASCII76 Keycode = KeyV // 118 v
+ ASCII77 Keycode = KeyW // 119 w
+ ASCII78 Keycode = KeyX // 120 x
+ ASCII79 Keycode = KeyY // 121 y
+ ASCII7A Keycode = KeyZ // 122 z
+ ASCII7B Keycode = KeyLeftBrace | shiftMask // 123 {
+ ASCII7C Keycode = KeyBackslash | shiftMask // 124 |
+ ASCII7D Keycode = KeyRightBrace | shiftMask // 125 }
+ ASCII7E Keycode = tildeBits | KeySpace // 126 ~
+ ASCII7F Keycode = KeyBackspace // 127 DEL
+ ISO88591A0 Keycode = KeySpace // 160 Nonbreakng Space
+ ISO88591A1 Keycode = Key1 | altgrMask // 161 ¡ Inverted Exclamation
+ ISO88591A2 Keycode = KeyC | altgrMask | shiftMask // 162 ¢ Cent SIGN
+ ISO88591A3 Keycode = Key4 | altgrMask | shiftMask // 163 £ Pound Sign
+ ISO88591A4 Keycode = Key4 | altgrMask // 164 ¤ Currency or Euro Sign
+ ISO88591A5 Keycode = KeyMinus | altgrMask // 165 ¥ YEN SIGN
+ ISO88591A6 Keycode = KeyBackslash | altgrMask | shiftMask // 166 ¦ BROKEN BAR ??
+ ISO88591A7 Keycode = KeyS | altgrMask | shiftMask // 167 § SECTION SIGN
+ ISO88591A8 Keycode = KeyQuote | altgrMask | shiftMask // 168 ¨ DIAERESIS
+ ISO88591A9 Keycode = KeyC | altgrMask // 169 © COPYRIGHT SIGN
+ ISO88591AA Keycode = 0 // 170 ª FEMININE ORDINAL
+ ISO88591AB Keycode = KeyLeftBrace | altgrMask // 171 « LEFT DOUBLE ANGLE QUOTE
+ ISO88591AC Keycode = KeyBackslash | altgrMask // 172 ¬ NOT SIGN ??
+ ISO88591AD Keycode = 0 // 173 SOFT HYPHEN
+ ISO88591AE Keycode = KeyR | altgrMask // 174 ® REGISTERED SIGN
+ ISO88591AF Keycode = 0 // 175 ¯ MACRON
+ ISO88591B0 Keycode = KeySemicolon | altgrMask | shiftMask // 176 ° DEGREE SIGN
+ ISO88591B1 Keycode = 0 // 177 ± PLUS-MINUS SIGN
+ ISO88591B2 Keycode = Key2 | altgrMask // 178 ² SUPERSCRIPT TWO
+ ISO88591B3 Keycode = Key3 | altgrMask // 179 ³ SUPERSCRIPT THREE
+ ISO88591B4 Keycode = KeyQuote | altgrMask // 180 ´ ACUTE ACCENT
+ ISO88591B5 Keycode = KeyM | altgrMask // 181 µ MICRO SIGN
+ ISO88591B6 Keycode = KeySemicolon | altgrMask // 182 ¶ PILCROW SIGN
+ ISO88591B7 Keycode = 0 // 183 · MIDDLE DOT
+ ISO88591B8 Keycode = 0 // 184 ¸ CEDILLA
+ ISO88591B9 Keycode = Key1 | altgrMask | shiftMask // 185 ¹ SUPERSCRIPT ONE
+ ISO88591BA Keycode = 0 // 186 º MASCULINE ORDINAL
+ ISO88591BB Keycode = KeyRightBrace | altgrMask // 187 » RIGHT DOUBLE ANGLE QUOTE
+ ISO88591BC Keycode = Key6 | altgrMask // 188 ¼ FRACTION ONE QUARTER
+ ISO88591BD Keycode = Key7 | altgrMask // 189 ½ FRACTION ONE HALF
+ ISO88591BE Keycode = Key8 | altgrMask // 190 ¾ FRACTION THREE QUARTERS
+ ISO88591BF Keycode = KeySlash | altgrMask // 191 ¿ INVERTED QUESTION MARK
+ ISO88591C0 Keycode = graveAccentBits | KeyA | shiftMask // 192 À A GRAVE
+ ISO88591C1 Keycode = KeyA | altgrMask | shiftMask // 193 Á A ACUTE
+ ISO88591C2 Keycode = circumflexBits | KeyA | shiftMask // 194 Â A CIRCUMFLEX
+ ISO88591C3 Keycode = tildeBits | KeyA | shiftMask // 195 Ã A TILDE
+ ISO88591C4 Keycode = KeyQ | altgrMask | shiftMask // 196 Ä A DIAERESIS
+ ISO88591C5 Keycode = KeyW | altgrMask | shiftMask // 197 Å A RING ABOVE
+ ISO88591C6 Keycode = KeyZ | altgrMask | shiftMask // 198 Æ AE
+ ISO88591C7 Keycode = KeyComma | altgrMask | shiftMask // 199 Ç C CEDILLA
+ ISO88591C8 Keycode = graveAccentBits | KeyE | shiftMask // 200 È E GRAVE
+ ISO88591C9 Keycode = KeyE | altgrMask | shiftMask // 201 É E ACUTE
+ ISO88591CA Keycode = circumflexBits | KeyE | shiftMask // 202 Ê E CIRCUMFLEX
+ ISO88591CB Keycode = diaeresisBits | KeyE | shiftMask // 203 Ë E DIAERESIS
+ ISO88591CC Keycode = graveAccentBits | KeyI | shiftMask // 204 Ì I GRAVE
+ ISO88591CD Keycode = KeyI | altgrMask | shiftMask // 205 Í I ACUTE
+ ISO88591CE Keycode = circumflexBits | KeyI | shiftMask // 206 Î I CIRCUMFLEX
+ ISO88591CF Keycode = diaeresisBits | KeyI | shiftMask // 207 Ï I DIAERESIS
+ ISO88591D0 Keycode = KeyD | altgrMask | shiftMask // 208 Ð ETH
+ ISO88591D1 Keycode = KeyN | altgrMask | shiftMask // 209 Ñ N TILDE
+ ISO88591D2 Keycode = graveAccentBits | KeyO | shiftMask // 210 Ò O GRAVE
+ ISO88591D3 Keycode = KeyO | altgrMask | shiftMask // 211 Ó O ACUTE
+ ISO88591D4 Keycode = circumflexBits | KeyO | shiftMask // 212 Ô O CIRCUMFLEX
+ ISO88591D5 Keycode = tildeBits | KeyO | shiftMask // 213 Õ O TILDE
+ ISO88591D6 Keycode = KeyP | altgrMask | shiftMask // 214 Ö O DIAERESIS
+ ISO88591D7 Keycode = KeyEqual | altgrMask // 215 × MULTIPLICATION
+ ISO88591D8 Keycode = KeyL | altgrMask | shiftMask // 216 Ø O STROKE
+ ISO88591D9 Keycode = graveAccentBits | KeyU | shiftMask // 217 Ù U GRAVE
+ ISO88591DA Keycode = KeyU | altgrMask | shiftMask // 218 Ú U ACUTE
+ ISO88591DB Keycode = circumflexBits | KeyU | shiftMask // 219 Û U CIRCUMFLEX
+ ISO88591DC Keycode = KeyY | altgrMask | shiftMask // 220 Ü U DIAERESIS
+ ISO88591DD Keycode = acuteAccentBits | KeyY | shiftMask // 221 Ý Y ACUTE
+ ISO88591DE Keycode = KeyT | altgrMask | shiftMask // 222 Þ THORN
+ ISO88591DF Keycode = KeyS | altgrMask // 223 ß SHARP S
+ ISO88591E0 Keycode = graveAccentBits | KeyA // 224 à a GRAVE
+ ISO88591E1 Keycode = KeyA | altgrMask // 225 á a ACUTE
+ ISO88591E2 Keycode = circumflexBits | KeyA // 226 â a CIRCUMFLEX
+ ISO88591E3 Keycode = tildeBits | KeyA // 227 ã a TILDE
+ ISO88591E4 Keycode = diaeresisBits | KeyA // 228 ä a DIAERESIS
+ ISO88591E5 Keycode = KeyW | altgrMask // 229 å a RING ABOVE
+ ISO88591E6 Keycode = KeyZ | altgrMask // 230 æ ae
+ ISO88591E7 Keycode = KeyComma | altgrMask // 231 ç c CEDILLA
+ ISO88591E8 Keycode = graveAccentBits | KeyE // 232 è e GRAVE
+ ISO88591E9 Keycode = acuteAccentBits | KeyE // 233 é e ACUTE
+ ISO88591EA Keycode = circumflexBits | KeyE // 234 ê e CIRCUMFLEX
+ ISO88591EB Keycode = diaeresisBits | KeyE // 235 ë e DIAERESIS
+ ISO88591EC Keycode = graveAccentBits | KeyI // 236 ì i GRAVE
+ ISO88591ED Keycode = KeyI | altgrMask // 237 í i ACUTE
+ ISO88591EE Keycode = circumflexBits | KeyI // 238 î i CIRCUMFLEX
+ ISO88591EF Keycode = diaeresisBits | KeyI // 239 ï i DIAERESIS
+ ISO88591F0 Keycode = KeyD | altgrMask // 240 ð ETH
+ ISO88591F1 Keycode = KeyN | altgrMask // 241 ñ n TILDE
+ ISO88591F2 Keycode = graveAccentBits | KeyO // 242 ò o GRAVE
+ ISO88591F3 Keycode = KeyO | altgrMask // 243 ó o ACUTE
+ ISO88591F4 Keycode = circumflexBits | KeyO // 244 ô o CIRCUMFLEX
+ ISO88591F5 Keycode = tildeBits | KeyO // 245 õ o TILDE
+ ISO88591F6 Keycode = KeyP | altgrMask // 246 ö o DIAERESIS
+ ISO88591F7 Keycode = KeyEqual | altgrMask | shiftMask // 247 ÷ DIVISION
+ ISO88591F8 Keycode = KeyL | altgrMask // 248 ø o STROKE
+ ISO88591F9 Keycode = graveAccentBits | KeyU // 249 ù u GRAVE
+ ISO88591FA Keycode = KeyU | altgrMask // 250 ú u ACUTE
+ ISO88591FB Keycode = circumflexBits | KeyU // 251 û u CIRCUMFLEX
+ ISO88591FC Keycode = KeyY | altgrMask // 252 ü u DIAERESIS
+ ISO88591FD Keycode = acuteAccentBits | KeyY // 253 ý y ACUTE
+ ISO88591FE Keycode = KeyT | altgrMask // 254 þ THORN
+ ISO88591FF Keycode = diaeresisBits | KeyY // 255 ÿ y DIAERESIS
+ UNICODE20AC Keycode = Key5 | altgrMask // 20AC € Euro Sign
+)
+
+var ascii = [...]Keycode{
+ ASCII00.mask(), ASCII01.mask(), ASCII02.mask(), ASCII03.mask(),
+ ASCII04.mask(), ASCII05.mask(), ASCII06.mask(), ASCII07.mask(),
+ ASCII08.mask(), ASCII09.mask(), ASCII0A.mask(), ASCII0B.mask(),
+ ASCII0C.mask(), ASCII0D.mask(), ASCII0E.mask(), ASCII0F.mask(),
+ ASCII10.mask(), ASCII11.mask(), ASCII12.mask(), ASCII13.mask(),
+ ASCII14.mask(), ASCII15.mask(), ASCII16.mask(), ASCII17.mask(),
+ ASCII18.mask(), ASCII19.mask(), ASCII1A.mask(), ASCII1B.mask(),
+ ASCII1C.mask(), ASCII1D.mask(), ASCII1E.mask(), ASCII1F.mask(),
+ ASCII20.mask(), ASCII21.mask(), ASCII22.mask(), ASCII23.mask(),
+ ASCII24.mask(), ASCII25.mask(), ASCII26.mask(), ASCII27.mask(),
+ ASCII28.mask(), ASCII29.mask(), ASCII2A.mask(), ASCII2B.mask(),
+ ASCII2C.mask(), ASCII2D.mask(), ASCII2E.mask(), ASCII2F.mask(),
+ ASCII30.mask(), ASCII31.mask(), ASCII32.mask(), ASCII33.mask(),
+ ASCII34.mask(), ASCII35.mask(), ASCII36.mask(), ASCII37.mask(),
+ ASCII38.mask(), ASCII39.mask(), ASCII3A.mask(), ASCII3B.mask(),
+ ASCII3C.mask(), ASCII3D.mask(), ASCII3E.mask(), ASCII3F.mask(),
+ ASCII40.mask(), ASCII41.mask(), ASCII42.mask(), ASCII43.mask(),
+ ASCII44.mask(), ASCII45.mask(), ASCII46.mask(), ASCII47.mask(),
+ ASCII48.mask(), ASCII49.mask(), ASCII4A.mask(), ASCII4B.mask(),
+ ASCII4C.mask(), ASCII4D.mask(), ASCII4E.mask(), ASCII4F.mask(),
+ ASCII50.mask(), ASCII51.mask(), ASCII52.mask(), ASCII53.mask(),
+ ASCII54.mask(), ASCII55.mask(), ASCII56.mask(), ASCII57.mask(),
+ ASCII58.mask(), ASCII59.mask(), ASCII5A.mask(), ASCII5B.mask(),
+ ASCII5C.mask(), ASCII5D.mask(), ASCII5E.mask(), ASCII5F.mask(),
+ ASCII60.mask(), ASCII61.mask(), ASCII62.mask(), ASCII63.mask(),
+ ASCII64.mask(), ASCII65.mask(), ASCII66.mask(), ASCII67.mask(),
+ ASCII68.mask(), ASCII69.mask(), ASCII6A.mask(), ASCII6B.mask(),
+ ASCII6C.mask(), ASCII6D.mask(), ASCII6E.mask(), ASCII6F.mask(),
+ ASCII70.mask(), ASCII71.mask(), ASCII72.mask(), ASCII73.mask(),
+ ASCII74.mask(), ASCII75.mask(), ASCII76.mask(), ASCII77.mask(),
+ ASCII78.mask(), ASCII79.mask(), ASCII7A.mask(), ASCII7B.mask(),
+ ASCII7C.mask(), ASCII7D.mask(), ASCII7E.mask(), ASCII7F.mask(),
+}
+
+var iso88591 = [...]Keycode{
+ ISO88591A0.mask(), ISO88591A1.mask(), ISO88591A2.mask(), ISO88591A3.mask(),
+ ISO88591A4.mask(), ISO88591A5.mask(), ISO88591A6.mask(), ISO88591A7.mask(),
+ ISO88591A8.mask(), ISO88591A9.mask(), ISO88591AA.mask(), ISO88591AB.mask(),
+ ISO88591AC.mask(), ISO88591AD.mask(), ISO88591AE.mask(), ISO88591AF.mask(),
+ ISO88591B0.mask(), ISO88591B1.mask(), ISO88591B2.mask(), ISO88591B3.mask(),
+ ISO88591B4.mask(), ISO88591B5.mask(), ISO88591B6.mask(), ISO88591B7.mask(),
+ ISO88591B8.mask(), ISO88591B9.mask(), ISO88591BA.mask(), ISO88591BB.mask(),
+ ISO88591BC.mask(), ISO88591BD.mask(), ISO88591BE.mask(), ISO88591BF.mask(),
+ ISO88591C0.mask(), ISO88591C1.mask(), ISO88591C2.mask(), ISO88591C3.mask(),
+ ISO88591C4.mask(), ISO88591C5.mask(), ISO88591C6.mask(), ISO88591C7.mask(),
+ ISO88591C8.mask(), ISO88591C9.mask(), ISO88591CA.mask(), ISO88591CB.mask(),
+ ISO88591CC.mask(), ISO88591CD.mask(), ISO88591CE.mask(), ISO88591CF.mask(),
+ ISO88591D0.mask(), ISO88591D1.mask(), ISO88591D2.mask(), ISO88591D3.mask(),
+ ISO88591D4.mask(), ISO88591D5.mask(), ISO88591D6.mask(), ISO88591D7.mask(),
+ ISO88591D8.mask(), ISO88591D9.mask(), ISO88591DA.mask(), ISO88591DB.mask(),
+ ISO88591DC.mask(), ISO88591DD.mask(), ISO88591DE.mask(), ISO88591DF.mask(),
+ ISO88591E0.mask(), ISO88591E1.mask(), ISO88591E2.mask(), ISO88591E3.mask(),
+ ISO88591E4.mask(), ISO88591E5.mask(), ISO88591E6.mask(), ISO88591E7.mask(),
+ ISO88591E8.mask(), ISO88591E9.mask(), ISO88591EA.mask(), ISO88591EB.mask(),
+ ISO88591EC.mask(), ISO88591ED.mask(), ISO88591EE.mask(), ISO88591EF.mask(),
+ ISO88591F0.mask(), ISO88591F1.mask(), ISO88591F2.mask(), ISO88591F3.mask(),
+ ISO88591F4.mask(), ISO88591F5.mask(), ISO88591F6.mask(), ISO88591F7.mask(),
+ ISO88591F8.mask(), ISO88591F9.mask(), ISO88591FA.mask(), ISO88591FB.mask(),
+ ISO88591FC.mask(), ISO88591FD.mask(), ISO88591FE.mask(), ISO88591FF.mask(),
+}
diff --git a/src/machine/usb/hid/mouse/mouse.go b/src/machine/usb/hid/mouse/mouse.go
new file mode 100644
index 000000000..c412f51e0
--- /dev/null
+++ b/src/machine/usb/hid/mouse/mouse.go
@@ -0,0 +1,90 @@
+package mouse
+
+import (
+ "machine/usb/hid"
+)
+
+var Mouse *mouse
+
+type mouse struct {
+ buf *hid.RingBuffer
+}
+
+func init() {
+ if Mouse == nil {
+ Mouse = newMouse()
+ hid.SetCallbackHandler(Mouse)
+ }
+}
+
+// New returns hid-mouse.
+func New() *mouse {
+ return Mouse
+}
+
+func newMouse() *mouse {
+ return &mouse{
+ buf: hid.NewRingBuffer(),
+ }
+}
+
+func (m *mouse) Callback() bool {
+ if b, ok := m.buf.Get(); ok {
+ hid.SendUSBPacket(b[:5])
+ return true
+ }
+ return false
+}
+
+// Move is a function that moves the mouse cursor.
+func (m *mouse) Move(vx, vy int) {
+ if vx == 0 && vy == 0 {
+ return
+ }
+
+ if vx < -128 {
+ vx = -128
+ }
+ if vx > 127 {
+ vx = 127
+ }
+
+ if vy < -128 {
+ vy = -128
+ }
+ if vy > 127 {
+ vy = 127
+ }
+
+ m.buf.Put([]byte{
+ 0x01, 0x00, byte(vx), byte(vy), 0x00,
+ })
+}
+
+// WHEEL controls the mouse wheel.
+func (m *mouse) Wheel(v int) {
+ if v == 0 {
+ return
+ }
+
+ if v < -128 {
+ v = -128
+ }
+ if v > 127 {
+ v = 127
+ }
+
+ m.buf.Put([]byte{
+ 0x01, 0x00, 0x00, 0x00, byte(v),
+ })
+}
+
+// WheelDown turns the mouse wheel down.
+func (m *mouse) WheelDown() {
+ m.Wheel(-1)
+}
+
+// WheelUp turns the mouse wheel up.
+func (m *mouse) WheelUp() {
+ m.Wheel(1)
+}
diff --git a/src/machine/usb_descriptor.go b/src/machine/usb_descriptor.go
new file mode 100644
index 000000000..9a1220c42
--- /dev/null
+++ b/src/machine/usb_descriptor.go
@@ -0,0 +1,70 @@
+//go:build sam || nrf52840
+// +build sam nrf52840
+
+package machine
+
+type USBDescriptor struct {
+ Device []byte
+ Configuration []byte
+ HID map[uint16][]byte
+}
+
+func (d *USBDescriptor) Configure(idVendor, idProduct uint16) {
+ d.Device[8] = byte(idVendor)
+ d.Device[9] = byte(idVendor >> 8)
+ d.Device[10] = byte(idProduct)
+ d.Device[11] = byte(idProduct >> 8)
+}
+
+var descriptorCDC = USBDescriptor{
+ Device: []byte{
+ 0x12, 0x01, 0x00, 0x02, 0xef, 0x02, 0x01, 0x40, 0x86, 0x28, 0x2d, 0x80, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01,
+ },
+ Configuration: []byte{
+ 0x09, 0x02, 0x4b, 0x00, 0x02, 0x01, 0x00, 0xa0, 0x32,
+ 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,
+ 0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00,
+ 0x05, 0x24, 0x00, 0x10, 0x01,
+ 0x04, 0x24, 0x02, 0x06,
+ 0x05, 0x24, 0x06, 0x00, 0x01,
+ 0x05, 0x24, 0x01, 0x01, 0x01,
+ 0x07, 0x05, 0x81, 0x03, 0x10, 0x00, 0x10,
+ 0x09, 0x04, 0x01, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00,
+ 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
+ 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
+ },
+}
+
+var descriptorCDCHID = USBDescriptor{
+ Device: []byte{
+ 0x12, 0x01, 0x00, 0x02, 0xef, 0x02, 0x01, 0x40, 0x86, 0x28, 0x2d, 0x80, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01,
+ },
+ Configuration: []byte{
+ 0x09, 0x02, 0x64, 0x00, 0x03, 0x01, 0x00, 0xa0, 0x32,
+ 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,
+ 0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00,
+ 0x05, 0x24, 0x00, 0x10, 0x01,
+ 0x04, 0x24, 0x02, 0x06,
+ 0x05, 0x24, 0x06, 0x00, 0x01,
+ 0x05, 0x24, 0x01, 0x01, 0x01,
+ 0x07, 0x05, 0x81, 0x03, 0x10, 0x00, 0x10,
+ 0x09, 0x04, 0x01, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00,
+ 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
+ 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
+ 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x09, 0x21, 0x01, 0x01, 0x00, 0x01, 0x22, 0x65, 0x00,
+ 0x07, 0x05, 0x84, 0x03, 0x40, 0x00, 0x01,
+ },
+ HID: map[uint16][]byte{
+ 2: []byte{
+ // keyboard and mouse
+ 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x85, 0x02, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00,
+ 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x03, 0x95, 0x06,
+ 0x75, 0x08, 0x15, 0x00, 0x25, 0x73, 0x05, 0x07, 0x19, 0x00, 0x29, 0x73, 0x81, 0x00, 0xc0, 0x05,
+ 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x85, 0x01, 0x05, 0x09, 0x19, 0x01, 0x29,
+ 0x03, 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81,
+ 0x03, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 0x15, 0x81, 0x25, 0x7f, 0x75, 0x08, 0x95,
+ 0x03, 0x81, 0x06, 0xc0, 0xc0,
+ },
+ },
+}