2014-03-23 07:21:22 +05:30
// Host detection.
2014-03-03 00:51:23 +05:30
package embd
2014-02-27 04:24:53 +05:30
import (
"fmt"
2014-09-09 15:57:27 +01:00
"io/ioutil"
2014-02-27 04:24:53 +05:30
"os/exec"
"strconv"
"strings"
)
2014-03-23 07:21:22 +05:30
// The Host type represents all the supported host types.
2014-03-24 03:04:58 +05:30
type Host string
2014-02-27 04:24:53 +05:30
const (
2014-03-23 07:21:22 +05:30
// HostNull reprents a null host.
2014-03-24 03:04:58 +05:30
HostNull Host = ""
2014-03-23 07:21:22 +05:30
// HostRPi represents the RaspberryPi.
2014-03-24 03:04:58 +05:30
HostRPi = "Raspberry Pi"
2014-03-23 07:21:22 +05:30
// HostBBB represents the BeagleBone Black.
2014-03-24 03:04:58 +05:30
HostBBB = "BeagleBone Black"
// HostGalileo represents the Intel Galileo board.
HostGalileo = "Intel Galileo"
2014-03-23 07:21:22 +05:30
// HostCubieTruck represents the Cubie Truck.
2014-03-24 03:04:58 +05:30
HostCubieTruck = "CubieTruck"
2014-03-23 07:21:22 +05:30
2014-05-22 02:56:50 +05:30
// HostRadxa represents the Radxa board.
2014-03-24 03:04:58 +05:30
HostRadxa = "Radxa"
2016-08-26 23:00:39 -07:00
// HostCHIP represents the NextThing C.H.I.P.
HostCHIP = "CHIP"
2014-02-27 04:24:53 +05:30
)
func execOutput ( name string , arg ... string ) ( output string , err error ) {
var out [ ] byte
if out , err = exec . Command ( name , arg ... ) . Output ( ) ; err != nil {
return
}
2014-03-02 19:39:04 +05:30
output = strings . TrimSpace ( string ( out ) )
2014-02-27 04:24:53 +05:30
return
}
2014-03-02 01:54:01 +05:30
func parseVersion ( str string ) ( major , minor , patch int , err error ) {
2014-05-15 23:48:53 -07:00
versionNumber := strings . Split ( str , "-" )
parts := strings . Split ( versionNumber [ 0 ] , "." )
2014-03-02 01:54:01 +05:30
len := len ( parts )
2014-02-27 04:24:53 +05:30
if major , err = strconv . Atoi ( parts [ 0 ] ) ; err != nil {
2014-03-02 01:54:01 +05:30
return 0 , 0 , 0 , err
2014-02-27 04:24:53 +05:30
}
if minor , err = strconv . Atoi ( parts [ 1 ] ) ; err != nil {
2014-03-02 01:54:01 +05:30
return 0 , 0 , 0 , err
2014-02-27 04:24:53 +05:30
}
2014-03-02 01:54:01 +05:30
if len > 2 {
part := parts [ 2 ]
part = strings . TrimSuffix ( part , "+" )
if patch , err = strconv . Atoi ( part ) ; err != nil {
return 0 , 0 , 0 , err
}
2014-02-27 04:24:53 +05:30
}
2014-03-02 01:54:01 +05:30
return major , minor , patch , err
}
func kernelVersion ( ) ( major , minor , patch int , err error ) {
output , err := execOutput ( "uname" , "-r" )
if err != nil {
return 0 , 0 , 0 , err
}
return parseVersion ( output )
2014-02-27 04:24:53 +05:30
}
2015-01-13 14:15:25 -08:00
func cpuInfo ( ) ( model , hardware string , revision int , err error ) {
output , err := ioutil . ReadFile ( "/proc/cpuinfo" )
2014-09-09 15:57:27 +01:00
if err != nil {
2015-01-13 14:15:25 -08:00
return "" , "" , 0 , err
2014-09-09 15:57:27 +01:00
}
2015-01-13 14:15:25 -08:00
for _ , line := range strings . Split ( string ( output ) , "\n" ) {
fields := strings . Split ( line , ":" )
if len ( fields ) < 1 {
continue
}
2015-01-15 06:36:01 +05:30
switch {
case strings . HasPrefix ( fields [ 0 ] , "Revision" ) :
revs := strings . TrimSpace ( fields [ 1 ] )
2015-02-17 17:04:09 +05:30
rev , err := strconv . ParseInt ( revs , 16 , 32 )
2015-01-13 14:15:25 -08:00
if err != nil {
continue
}
revision = int ( rev )
2015-01-15 06:36:01 +05:30
case strings . HasPrefix ( fields [ 0 ] , "Hardware" ) :
2016-08-26 23:00:39 -07:00
hardware = strings . TrimSpace ( fields [ 1 ] )
2015-01-15 06:36:01 +05:30
case strings . HasPrefix ( fields [ 0 ] , "model name" ) :
2015-01-13 14:15:25 -08:00
model = fields [ 1 ]
2014-09-09 15:57:27 +01:00
}
}
2015-01-13 14:15:25 -08:00
return model , hardware , revision , nil
2014-09-09 15:57:27 +01:00
}
2014-03-23 07:21:22 +05:30
// DetectHost returns the detected host and its revision number.
2015-01-13 14:15:25 -08:00
func DetectHost ( ) ( host Host , rev int , err error ) {
2014-02-27 04:24:53 +05:30
major , minor , patch , err := kernelVersion ( )
if err != nil {
2014-03-03 00:51:23 +05:30
return HostNull , 0 , err
2014-02-27 04:24:53 +05:30
}
if major < 3 || ( major == 3 && minor < 8 ) {
2016-08-26 23:00:39 -07:00
return HostNull , 0 , fmt . Errorf (
"embd: linux kernel versions lower than 3.8 are not supported, " +
"you have %v.%v.%v" , major , minor , patch )
2014-02-27 04:24:53 +05:30
}
2015-01-13 14:15:25 -08:00
model , hardware , rev , err := cpuInfo ( )
2014-02-27 04:24:53 +05:30
if err != nil {
2014-03-03 00:51:23 +05:30
return HostNull , 0 , err
2014-02-27 04:24:53 +05:30
}
2015-01-13 14:15:25 -08:00
switch {
case strings . Contains ( model , "ARMv7" ) && ( strings . Contains ( hardware , "AM33XX" ) || strings . Contains ( hardware , "AM335X" ) ) :
return HostBBB , rev , nil
2015-02-17 17:04:09 +05:30
case strings . Contains ( hardware , "BCM2708" ) || strings . Contains ( hardware , "BCM2709" ) :
2015-01-13 14:15:25 -08:00
return HostRPi , rev , nil
2016-08-26 23:00:39 -07:00
case hardware == "Allwinner sun4i/sun5i Families" :
if major < 4 || ( major == 4 && minor < 4 ) {
return HostNull , 0 , fmt . Errorf (
"embd: linux kernel version 4.4+ required, you have %v.%v" ,
major , minor )
}
return HostCHIP , rev , nil
2014-02-27 04:24:53 +05:30
default :
2015-02-17 17:04:09 +05:30
return HostNull , 0 , fmt . Errorf ( ` embd: your host "%v:%v" is not supported at this moment. request support at https://github.com/kidoman/embd/issues ` , host , model )
2014-02-27 04:24:53 +05:30
}
}