@@ -97,6 +97,11 @@ func (i *I2C) Tx(addr uint16, w, r []byte) error {
9797 return nil
9898 }
9999
100+ // If I2C is not supported, fallback to SMBus
101+ if i .fn & funcI2C == 0 {
102+ return i .smbusTx (addr , w , r )
103+ }
104+
100105 // Convert the messages to the internal format.
101106 var buf [2 ]i2cMsg
102107 msgs := buf [0 :0 ]
@@ -197,6 +202,65 @@ func (i *I2C) initPins() {
197202 i .mu .Unlock ()
198203}
199204
205+ func (i * I2C ) smbusTx (addr uint16 , w , r []byte ) error {
206+ switch {
207+ case len (w ) == 1 && len (r ) == 1 :
208+ // SMBus Read Byte Data
209+ return i .smbusCmd (addr , true , w [0 ], protocolByteData , r )
210+ case len (w ) == 2 && len (r ) == 0 :
211+ // SMBus Write Byte Data
212+ return i .smbusCmd (addr , false , w [0 ], protocolByteData , w [1 :])
213+ default :
214+ return errors .New ("sysfs-i2c: unsupported SMBus transaction" )
215+ }
216+ }
217+
218+ // SMBus IOCTL calls this size but it's not actually a size field.
219+ type smbusProtocol uint32
220+
221+ const (
222+ protocolByteData smbusProtocol = 2
223+ )
224+
225+ func (i * I2C ) smbusCmd (addr uint16 , read bool , reg byte , protocol smbusProtocol , data []byte ) error {
226+ rw := byte (0 ) // write
227+ if read {
228+ rw = byte (1 ) // read
229+ }
230+
231+ // Make a contiguous copy of data to avoid issues with slices.
232+ buf := make ([]byte , len (data ))
233+ copy (buf , data )
234+ defer copy (data , buf )
235+
236+ // Prepare the I2C_SMBUS ioctl command.
237+ cmd := struct {
238+ rw byte
239+ command byte
240+ size uint32
241+ data unsafe.Pointer
242+ }{
243+ rw ,
244+ reg ,
245+ uint32 (protocol ),
246+ unsafe .Pointer (& buf [0 ]),
247+ }
248+
249+ i .mu .Lock ()
250+ defer i .mu .Unlock ()
251+
252+ // Set the slave address.
253+ if err := i .f .Ioctl (ioctlSlave , uintptr (addr )); err != nil {
254+ return fmt .Errorf ("sysfs-smbus: %v" , err )
255+ }
256+
257+ // Perform the transaction.
258+ if err := i .f .Ioctl (ioctlSmbus , uintptr (unsafe .Pointer (& cmd ))); err != nil {
259+ return fmt .Errorf ("sysfs-smbus: %v" , err )
260+ }
261+ return nil
262+ }
263+
200264// i2cdev driver IOCTL control codes.
201265//
202266// Constants and structure definition can be found at
@@ -208,6 +272,7 @@ const (
208272 ioctlTenBits = 0x704 // TODO(maruel): Expose this but the header says it's broken (!?)
209273 ioctlFuncs = 0x705
210274 ioctlRdwr = 0x707
275+ ioctlSmbus = 0x720
211276)
212277
213278// flags
0 commit comments