2016-07-15 7 views
2

Ich habe einen i2c-Adapter für den Benutzer als /dev/i2c-0 exponiert. Wenn ich i2cdetect aus dem i2c-tools-Paket auf diesem Adapter verwende, sehe ich mein Gerät auf diesem Adapter aufgelistet und bin in der Lage, Get, Set und Dump-Operationen über die Befehlszeile auszuführen.Was bedeutet ENXIO für ein i2c ioctl?

Ich habe einige C-Code, der versucht, einen Schreibvorgang mit der ioctl I2C_RDWR Operation durchzuführen.

Hier ist der abgespeckte Code, mit dem ich arbeite (nur für den Kontext, und es ist nicht wichtig, die Fragen zu beantworten).

fd = open ("/dev/i2c-0", O_RDWR | O_NONBLOCK); 

/* other stuff happens here */ 

if (ioctl (fd, I2C_FUNCS, &funcs) != 0) 
    return -1; 
if (!(funcs & I2C_FUNC_I2C)) 
    return -1; 

/* i added this bit of debug just to be sure fd didn't 
* get inadvertently closed along the way. 
*/ 
if (fcntl (fd, F_GETFD) != 0) { 
    return -1; 
} 

/* build the ioctl message payload */ 

ret = ioctl (fd, I2C_RDWR, &payload) 
if (ret) { 
    fprintf (stderr, "ioctl returned %d. Reason: %s (errno=%d).", 
      ret, strerror(errno), errno); 
    return -1; 
} 

return 0; 

Ich habe auch versucht, die smbus ioctl Funktionen zu verwenden, die so aussahen.

fd = open ("/dev/i2c-0", O_RDWR | O_NONBLOCK); 

/* other stuff happens here */ 

if (ioctl (fd, I2C_FUNCS, &funcs) != 0) 
    return -1; 
if (!(funcs & I2C_FUNC_SMBUS_WORD_DATA)) 
    return -1; 

/* i added this bit of debug just to be sure fd didn't 
* get inadvertently closed along the way. 
*/ 
if (fcntl (fd, F_GETFD) != 0) { 
    return -1; 
} 

/* build the ioctl smbus message payload */ 

if (ioctl (fd, I2C_SLAVE_FORCE, dev) != 0) 
    return -1; 

ret = ioctl (fd, I2C_SMBUS, &payload); 
if (ret) { 
    fprintf (stderr, "ioctl returned %d. Reason: %s (errno=%d).", 
      ret, strerror(errno), errno); 
    return -1; 
} 

return 0; 

In allen Fällen trifft das Programm immer die fprintf und dies ist die Ausgabe:

ioctl zurück -1. Grund: Kein solches Gerät oder Adresse (errno = 6).

Nach man 3 ioctl, der "generic" Grund für einen ENXIO Fehler ist:

ENXIO Die Anfrage und arg Argumente gelten für diese Gerätetreiber sind, aber der Service angefordert kann auf diesem bestimmten Untergerät nicht ausgeführt werden.

Als Ian in den Kommentaren darauf hingewiesen, die Informationen in Bezug auf STREAMS in der obigen Manpage jedoch auf Linux nicht relevant und ich soll man 2 ioctl verwenden - was leider meist nur sagt, dass ioctls don‘ t wirklich zu irgendeinem Standard entsprechen, und alles geht.

Dies wirft drei Fragen auf.

  1. Was bedeutet dies für einen i2c-Adapter? Unterstützt der Treiber für dieses Gerät das Lesen und Schreiben mit dieser Methode nicht?
  2. Die man-Seite enthält spezifische Beschreibungen von Rückkehrcodes für die mit I_ vorangestellten Operationen, jedoch nicht für andere Operationen. Kann ich woanders nach Informationen suchen, die spezifisch für I2C ioctl-Operationen sind?
  3. Wo finde ich die Quelle für die ioc ioctl Funktionen?
+1

Der Verweis auf STREAMS-Geräte ist für Linux ein wenig irrelevant, da es [STREAMS] (https://en.wikipedia.org/wiki/STREAMS) nicht unterstützt. Du solltest wirklich ['man 2 ioctl'] anschauen (http://linux.die.net/man/2/ioctl). –

+0

@IanAbbott hmmm, dass ENXIO nicht einmal erwähnt wird. :( –

+0

Siehe den Abschnitt "CONFORMING TO" :) –

Antwort

0

Normalerweise bedeutet dies, dass das Gerät nicht reagiert hat. Die Einzelheiten hängen von Ihrer Hardware ab.

Der gemeinsame I2C-ioctl-Code ist Teil des i2c-dev-Pakets, das Teil des lm-sensors-Projekts ist. Diese ioctls haben keine eigene man-Seite, aber haben documentation in the kernel source tree. Im Kernel wird die Implementierung in drivers/i2c/i2c-dev.c und drivers/i2c/i2c-core.c gespeichert. Der Einstiegspunkt ist i2cdev_ioctl(). Nichts von diesem allgemeinen Code gibt ENXIO zurück.

Schließlich muss dieser allgemeine Code auf Hardware-Level-Treiberfunktionen auf dem i2c-Bus aufgerufen werden. Die Hardwaretreiber für i2c-Busse sind in drivers/i2c/busses/ gespeichert. Jeder dieser Treiber kann eine oder beide der Funktionen master_xfer (verwendet für I2C_RDWR ioctls) oder smbus_xfer (für I2C_SMBUS) Funktionen implementieren.

In meinem Fall hatte das Gerät tatsächlich keine dedizierte i2c-Hardware und verwendete eine scheinbar bittende Softwareemulation, die in der Funktion bit_xfer of drivers/i2c/algos/i2c-algo-bit.c implementiert wurde. Das ENXIO kam von der Funktion bit_doAddress.

+0

Tipp: Verwenden Sie 'dmesg', um die Kernel-Protokolle zu lesen. Normalerweise hat es einen Grund, warum etwas fehlgeschlagen ist (zB ein I2C-Timeout-Fehler, wenn das Gerät nicht reagiert hat). –