summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Didron <0x6664@hey.com>2022-03-30 16:06:10 +0900
committerFlorian Didron <0x6664@hey.com>2022-03-30 16:06:10 +0900
commit53d9020158a10ad0ffb6bc89136476f5f3a8e72b (patch)
treed04593ddfdef2cf1ca46b4fb547d90301b82a62d
parent6d65e2fac8c0b0ce6b582d4b5f3e572d2b531d16 (diff)
fix: kernel detach auth error on OSX Big Sur / Monterey2.0.1-osx
-rw-r--r--dfu.go385
-rw-r--r--teensy.go216
2 files changed, 303 insertions, 298 deletions
diff --git a/dfu.go b/dfu.go
index bfa1c81..47068c5 100644
--- a/dfu.go
+++ b/dfu.go
@@ -1,224 +1,227 @@
package main
import (
- "errors"
- "fmt"
- "github.com/google/gousb"
- "io/ioutil"
- "log"
- "time"
-)
+ "errors"
+ "fmt"
+ "github.com/google/gousb"
+ "io/ioutil"
+ "runtime"
+ "log"
+ "time"
+ )
type status struct {
- bStatus string
- bwPollTimeout int
- bState string
- iString string
+ bStatus string
+ bwPollTimeout int
+ bState string
+ iString string
}
func dfuCommand(dev *gousb.Device, addr int, command int, status *status) (err error) {
- var buf []byte
- if command == setAddress {
- buf = make([]byte, 5)
- buf[0] = 0x21
- buf[1] = byte(addr & 0xff)
- buf[2] = byte((addr >> 8) & 0xff)
- buf[3] = byte((addr >> 16) & 0xff)
- buf[4] = byte((addr >> 24) & 0xff)
- }
- if command == eraseAddress {
- buf = make([]byte, 5)
- buf[0] = 0x41
- buf[1] = byte(addr & 0xff)
- buf[2] = byte((addr >> 8) & 0xff)
- buf[3] = byte((addr >> 16) & 0xff)
- buf[4] = byte((addr >> 24) & 0xff)
- }
- if command == eraseFlash {
- buf = make([]byte, 1)
- buf[0] = 0x41
- }
-
- _, err = dev.Control(33, 1, 0, 0, buf)
-
- err = dfuPollTimeout(dev, status)
-
- if err != nil {
- return err
- }
-
- return nil
+ var buf []byte
+ if command == setAddress {
+ buf = make([]byte, 5)
+ buf[0] = 0x21
+ buf[1] = byte(addr & 0xff)
+ buf[2] = byte((addr >> 8) & 0xff)
+ buf[3] = byte((addr >> 16) & 0xff)
+ buf[4] = byte((addr >> 24) & 0xff)
+ }
+ if command == eraseAddress {
+ buf = make([]byte, 5)
+ buf[0] = 0x41
+ buf[1] = byte(addr & 0xff)
+ buf[2] = byte((addr >> 8) & 0xff)
+ buf[3] = byte((addr >> 16) & 0xff)
+ buf[4] = byte((addr >> 24) & 0xff)
+ }
+ if command == eraseFlash {
+ buf = make([]byte, 1)
+ buf[0] = 0x41
+ }
+
+ _, err = dev.Control(33, 1, 0, 0, buf)
+
+ err = dfuPollTimeout(dev, status)
+
+ if err != nil {
+ return err
+ }
+
+ return nil
}
func dfuPollTimeout(dev *gousb.Device, status *status) (err error) {
- for i := 0; i < 3; i++ {
- err = dfuGetStatus(dev, status)
- time.Sleep(time.Duration(status.bwPollTimeout) * time.Millisecond)
- }
- return err
+ for i := 0; i < 3; i++ {
+ err = dfuGetStatus(dev, status)
+ time.Sleep(time.Duration(status.bwPollTimeout) * time.Millisecond)
+ }
+ return err
}
func dfuGetStatus(dev *gousb.Device, status *status) (err error) {
- buf := make([]byte, 6)
- stat, err := dev.Control(161, 3, 0, 0, buf)
- if err != nil {
- return err
- }
- if stat == 6 {
- status.bStatus = string(buf[0])
- status.bwPollTimeout = int((0xff & buf[3] << 16) | (0xff & buf[2]) | 0xff&buf[1])
- status.bState = string(buf[4])
- status.iString = string(buf[5])
- }
- return err
+ buf := make([]byte, 6)
+ stat, err := dev.Control(161, 3, 0, 0, buf)
+ if err != nil {
+ return err
+ }
+ if stat == 6 {
+ status.bStatus = string(buf[0])
+ status.bwPollTimeout = int((0xff & buf[3] << 16) | (0xff & buf[2]) | 0xff&buf[1])
+ status.bState = string(buf[4])
+ status.iString = string(buf[5])
+ }
+return err
}
func dfuClearStatus(dev *gousb.Device) (err error) {
- _, err = dev.Control(33, 4, 2, 0, nil)
- return err
+ _, err = dev.Control(33, 4, 2, 0, nil)
+return err
}
func dfuReboot(dev *gousb.Device, status *status) (err error) {
- err = dfuPollTimeout(dev, status)
- _, err = dev.Control(33, 1, 2, 0, nil)
- time.Sleep(1000 * time.Millisecond)
- err = dfuGetStatus(dev, status)
- return err
+ err = dfuPollTimeout(dev, status)
+_, err = dev.Control(33, 1, 2, 0, nil)
+time.Sleep(1000 * time.Millisecond)
+err = dfuGetStatus(dev, status)
+ return err
}
func extractSuffix(fileData []byte) (hasSuffix bool, data []byte, err error) {
- fileSize := len(fileData)
+ fileSize := len(fileData)
- suffix := fileData[fileSize-dfuSuffixLength : fileSize]
- d := string(suffix[10])
- f := string(suffix[9])
- u := string(suffix[8])
+ suffix := fileData[fileSize-dfuSuffixLength : fileSize]
+ d := string(suffix[10])
+ f := string(suffix[9])
+ u := string(suffix[8])
- if d == "D" && f == "F" && u == "U" {
- vid := int((suffix[5] << 8) + suffix[4])
- pid := int((suffix[3] << 8) + suffix[2])
- if vid != dfuSuffixVendorID || pid != dfuSuffixProductID {
- message := fmt.Sprintf("Invalid vendor or product id, expected %#x:%#x got %#x:%#x", dfuSuffixVendorID, dfuSuffixProductID, vid, pid)
- err = errors.New(message)
- return true, fileData, err
+if d == "D" && f == "F" && u == "U" {
+vid := int((suffix[5] << 8) + suffix[4])
+ pid := int((suffix[3] << 8) + suffix[2])
+ if vid != dfuSuffixVendorID || pid != dfuSuffixProductID {
+ message := fmt.Sprintf("Invalid vendor or product id, expected %#x:%#x got %#x:%#x", dfuSuffixVendorID, dfuSuffixProductID, vid, pid)
+ err = errors.New(message)
+ return true, fileData, err
- }
+ }
- return true, fileData[0 : fileSize-dfuSuffixLength], nil
- }
+ return true, fileData[0 : fileSize-dfuSuffixLength], nil
+ }
- return false, fileData, nil
+ return false, fileData, nil
}
func dfuFlash(firmwarePath string, s *state) {
- dfuStatus := status{}
- fileData, err := ioutil.ReadFile(firmwarePath)
- if err != nil {
- message := fmt.Sprintf("Error while opening firmware: %s", err)
- log.Fatal(message)
- return
- }
-
- _, firmwareData, err := extractSuffix(fileData)
- if err != nil {
- message := fmt.Sprintf("Error while extracting DFU Suffix: %s", err)
- log.Fatal(message)
- return
- }
-
- ctx := gousb.NewContext()
- ctx.Debug(0)
- defer ctx.Close()
- var dev *gousb.Device
-
- // Get the list of device that match TMK's vendor id
- for {
- devs, _ := ctx.OpenDevices(func(desc *gousb.DeviceDesc) bool {
- if desc.Vendor == gousb.ID(dfuVendorID) && desc.Product == gousb.ID(dfuProductID) {
- return true
- }
- return false
- })
-
- defer func() {
- for _, d := range devs {
- d.Close()
- }
- }()
-
- if len(devs) > 0 {
- dev = devs[0]
- break
- }
- time.Sleep(1 * time.Second)
- }
-
- dev.SetAutoDetach(true)
-
- dev.ControlTimeout = 5 * time.Second
-
- cfg, err := dev.Config(1)
- if err != nil {
- message := fmt.Sprintf("Error while claiming the usb interface: %s", err)
- log.Fatal(message)
- }
- defer cfg.Close()
-
- fileSize := len(firmwareData)
- s.total = fileSize
-
- err = dfuClearStatus(dev)
- if err != nil {
- message := fmt.Sprintf("Error while clearing the device status: %s", err)
- log.Fatal(message)
- }
-
- s.step = 1
-
- err = dfuCommand(dev, 0, eraseFlash, &dfuStatus)
- if err != nil {
- message := fmt.Sprintf("Error while erasing flash: %s", err)
- log.Fatal(message)
- return
- }
-
- for page := 0; page < fileSize; page += planckBlockSize {
- addr := planckStartAddress + page
- chunckSize := planckBlockSize
-
- if page+chunckSize > fileSize {
- chunckSize = fileSize - page
- }
-
- err = dfuCommand(dev, addr, eraseAddress, &dfuStatus)
- if err != nil {
- message := fmt.Sprintf("Error while sending the erase address command: %s", err)
- log.Fatal(message)
- }
- err = dfuCommand(dev, addr, setAddress, &dfuStatus)
- if err != nil {
- message := fmt.Sprintf("Error while sending the set address command: %s", err)
- log.Fatal(message)
- }
-
- buf := firmwareData[page : page+chunckSize]
- bytes, err := dev.Control(33, 1, 2, 0, buf)
-
- if err != nil {
- message := fmt.Sprintf("Error while sending firmware bytes: %s", err)
- log.Fatal(message)
- }
-
- s.sent += bytes
- }
-
- err = dfuReboot(dev, &dfuStatus)
- if err != nil {
- message := fmt.Sprintf("Error while rebooting device: %s", err)
- log.Fatal(message)
- return
- }
-
- s.step = 2
+ dfuStatus := status{}
+ fileData, err := ioutil.ReadFile(firmwarePath)
+ if err != nil {
+ message := fmt.Sprintf("Error while opening firmware: %s", err)
+ log.Fatal(message)
+ return
+ }
+
+ _, firmwareData, err := extractSuffix(fileData)
+ if err != nil {
+ message := fmt.Sprintf("Error while extracting DFU Suffix: %s", err)
+ log.Fatal(message)
+ return
+ }
+
+ ctx := gousb.NewContext()
+ ctx.Debug(0)
+ defer ctx.Close()
+ var dev *gousb.Device
+
+ // Get the list of device that match TMK's vendor id
+ for {
+ devs, _ := ctx.OpenDevices(func(desc *gousb.DeviceDesc) bool {
+ if desc.Vendor == gousb.ID(dfuVendorID) && desc.Product == gousb.ID(dfuProductID) {
+ return true
+ }
+ return false
+ })
+
+ defer func() {
+ for _, d := range devs {
+ d.Close()
+ }
+ }()
+
+ if len(devs) > 0 {
+ dev = devs[0]
+ break
+ }
+ time.Sleep(1 * time.Second)
+ }
+
+ if runtime.GOOS != "darwin" {
+ dev.SetAutoDetach(true)
+ }
+
+ dev.ControlTimeout = 5 * time.Second
+
+ cfg, err := dev.Config(1)
+ if err != nil {
+ message := fmt.Sprintf("Error while claiming the usb interface: %s", err)
+ log.Fatal(message)
+ }
+ defer cfg.Close()
+
+ fileSize := len(firmwareData)
+ s.total = fileSize
+
+ err = dfuClearStatus(dev)
+ if err != nil {
+ message := fmt.Sprintf("Error while clearing the device status: %s", err)
+ log.Fatal(message)
+ }
+
+ s.step = 1
+
+ err = dfuCommand(dev, 0, eraseFlash, &dfuStatus)
+ if err != nil {
+ message := fmt.Sprintf("Error while erasing flash: %s", err)
+ log.Fatal(message)
+ return
+ }
+
+ for page := 0; page < fileSize; page += planckBlockSize {
+ addr := planckStartAddress + page
+ chunckSize := planckBlockSize
+
+ if page+chunckSize > fileSize {
+ chunckSize = fileSize - page
+ }
+
+ err = dfuCommand(dev, addr, eraseAddress, &dfuStatus)
+ if err != nil {
+ message := fmt.Sprintf("Error while sending the erase address command: %s", err)
+ log.Fatal(message)
+ }
+ err = dfuCommand(dev, addr, setAddress, &dfuStatus)
+ if err != nil {
+ message := fmt.Sprintf("Error while sending the set address command: %s", err)
+ log.Fatal(message)
+ }
+
+ buf := firmwareData[page : page+chunckSize]
+ bytes, err := dev.Control(33, 1, 2, 0, buf)
+
+ if err != nil {
+ message := fmt.Sprintf("Error while sending firmware bytes: %s", err)
+ log.Fatal(message)
+ }
+
+ s.sent += bytes
+ }
+
+ err = dfuReboot(dev, &dfuStatus)
+ if err != nil {
+ message := fmt.Sprintf("Error while rebooting device: %s", err)
+ log.Fatal(message)
+ return
+ }
+
+ s.step = 2
}
diff --git a/teensy.go b/teensy.go
index 7b5854c..7e84076 100644
--- a/teensy.go
+++ b/teensy.go
@@ -1,115 +1,117 @@
package main
import (
- "fmt"
- "github.com/google/gousb"
- "github.com/marcinbor85/gohex"
- "log"
- "os"
- "time"
-)
+ "fmt"
+ "github.com/google/gousb"
+ "github.com/marcinbor85/gohex"
+ "runtime"
+ "log"
+ "os"
+ "time"
+ )
// TeensyFlash: Flashes Teensy boards.
// It opens the firmware file at the provided path, checks it's integrity, wait for the keyboard to be in Flash mode, flashes it and reboots the board.
func teensyFlash(firmwarePath string, s *state) {
- file, err := os.Open(firmwarePath)
- if err != nil {
- message := fmt.Sprintf("Error while opening firmware: %s", err)
- log.Fatal(message)
- return
- }
- defer file.Close()
-
- s.total = ergodoxCodeSize
-
- firmware := gohex.NewMemory()
- err = firmware.ParseIntelHex(file)
- if err != nil {
- message := fmt.Sprintf("Error while parsing firmware: %s", err)
- log.Fatal(message)
- return
- }
-
- ctx := gousb.NewContext()
- ctx.Debug(0)
- defer ctx.Close()
- var dev *gousb.Device
-
- // Loop until a keyboard is ready to flash
- for {
- devs, _ := ctx.OpenDevices(func(desc *gousb.DeviceDesc) bool {
- if desc.Vendor == gousb.ID(halfKayVendorID) && desc.Product == gousb.ID(halfKayProductID) {
- return true
- }
- return false
- })
-
- defer func() {
- for _, d := range devs {
- d.Close()
- }
- }()
-
- if len(devs) > 0 {
- dev = devs[0]
- break
- }
- time.Sleep(1 * time.Second)
- }
-
- // Detach keyboard from the kernel
- dev.SetAutoDetach(true)
-
- // Claim usb device
- cfg, err := dev.Config(1)
- defer cfg.Close()
- if err != nil {
- message := fmt.Sprintf("Error while claiming the usb interface: %s", err)
- log.Fatal(message)
- return
- }
-
- s.step = 1
-
- // Loop on the firmware data and program
- var addr uint32
- for addr = 0; addr < ergodoxCodeSize; addr += ergodoxBlockSize {
- // set a longer timeout when writing the first block
- if addr == 0 {
- dev.ControlTimeout = 5 * time.Second
- } else {
- dev.ControlTimeout = 500 * time.Millisecond
- }
- // Prepare and write a firmware block
- // https://www.pjrc.com/teensy/halfkay_protocol.html
- buf := make([]byte, ergodoxBlockSize+2)
- buf[0] = byte(addr & 255)
- buf[1] = byte((addr >> 8) & 255)
- block := firmware.ToBinary(addr, ergodoxBlockSize, 255)
- for index := range block {
- buf[index+2] = block[index]
- }
-
- bytes, err := dev.Control(0x21, 9, 0x0200, 0, buf)
- if err != nil {
- message := fmt.Sprintf("Error while sending firmware bytes: %s", err)
- log.Fatal(message)
- return
- }
-
- s.sent += bytes
- }
-
- buf := make([]byte, ergodoxBlockSize+2)
- buf[0] = byte(0xFF)
- buf[1] = byte(0xFF)
- buf[2] = byte(0xFF)
- _, err = dev.Control(0x21, 9, 0x0200, 0, buf)
-
- if err != nil {
- message := fmt.Sprintf("Error while rebooting device: %s", err)
- log.Fatal(message)
- return
- }
- s.step = 2
+ file, err := os.Open(firmwarePath)
+ if err != nil {
+ message := fmt.Sprintf("Error while opening firmware: %s", err)
+ log.Fatal(message)
+ return
+ }
+ defer file.Close()
+
+ s.total = ergodoxCodeSize
+
+ firmware := gohex.NewMemory()
+ err = firmware.ParseIntelHex(file)
+ if err != nil {
+ message := fmt.Sprintf("Error while parsing firmware: %s", err)
+ log.Fatal(message)
+ return
+ }
+
+ ctx := gousb.NewContext()
+ ctx.Debug(0)
+ defer ctx.Close()
+ var dev *gousb.Device
+
+ // Loop until a keyboard is ready to flash
+ for {
+ devs, _ := ctx.OpenDevices(func(desc *gousb.DeviceDesc) bool {
+ if desc.Vendor == gousb.ID(halfKayVendorID) && desc.Product == gousb.ID(halfKayProductID) {
+ return true
+ }
+ return false
+ })
+
+ defer func() {
+ for _, d := range devs {
+ d.Close()
+ }
+ }()
+
+ if len(devs) > 0 {
+ dev = devs[0]
+ break
+ }
+ time.Sleep(1 * time.Second)
+ }
+
+ if runtime.GOOS != "darwin" {
+ dev.SetAutoDetach(true)
+ }
+
+ // Claim usb device
+ cfg, err := dev.Config(1)
+ defer cfg.Close()
+ if err != nil {
+ message := fmt.Sprintf("Error while claiming the usb interface: %s", err)
+ log.Fatal(message)
+ return
+ }
+
+ s.step = 1
+
+ // Loop on the firmware data and program
+ var addr uint32
+ for addr = 0; addr < ergodoxCodeSize; addr += ergodoxBlockSize {
+ // set a longer timeout when writing the first block
+ if addr == 0 {
+ dev.ControlTimeout = 5 * time.Second
+ } else {
+ dev.ControlTimeout = 500 * time.Millisecond
+ }
+ // Prepare and write a firmware block
+ // https://www.pjrc.com/teensy/halfkay_protocol.html
+ buf := make([]byte, ergodoxBlockSize+2)
+ buf[0] = byte(addr & 255)
+ buf[1] = byte((addr >> 8) & 255)
+ block := firmware.ToBinary(addr, ergodoxBlockSize, 255)
+ for index := range block {
+ buf[index+2] = block[index]
+ }
+
+ bytes, err := dev.Control(0x21, 9, 0x0200, 0, buf)
+ if err != nil {
+ message := fmt.Sprintf("Error while sending firmware bytes: %s", err)
+ log.Fatal(message)
+ return
+ }
+
+ s.sent += bytes
+ }
+
+ buf := make([]byte, ergodoxBlockSize+2)
+ buf[0] = byte(0xFF)
+ buf[1] = byte(0xFF)
+ buf[2] = byte(0xFF)
+ _, err = dev.Control(0x21, 9, 0x0200, 0, buf)
+
+ if err != nil {
+ message := fmt.Sprintf("Error while rebooting device: %s", err)
+ log.Fatal(message)
+ return
+ }
+ s.step = 2
}