0,0 → 1,845 |
/* |
* Copyright (C) 1998 Itai Nahshon, Michael Schimek |
* |
* The original code was derived from and inspired by |
* the I2C driver from the Linux kernel. |
* (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> |
*/ |
|
/* $XFree86: xc/programs/Xserver/hw/xfree86/i2c/xf86i2c.c,v 1.14 2003/05/05 21:18:41 tsi Exp $ */ |
|
#include "common.h" |
#include "rhd.h" |
#include "xf86i2c.h" |
|
#define I2C_TIMEOUT(x) /*(x)*/ /* Report timeouts */ |
#define I2C_TRACE(x) /*(x)*/ /* Report progress */ |
|
/* Set which OSs have bad gettimeofday resolution. */ |
#if defined(SVR4) && !defined(sun) |
#define BAD_GETTIMEOFDAY_RESOLUTION |
#endif |
|
|
/* This is the default I2CUDelay function if not supplied by the driver. |
* High level I2C interfaces implementing the bus protocol in hardware |
* should supply this function too. |
* |
* Delay execution at least usec microseconds. |
* All values 0 to 1e6 inclusive must be expected. |
*/ |
|
static int bogo_usec = 500; |
|
static void |
I2CUDelay(I2CBusPtr b, int usec) |
{ |
volatile long i; |
|
if (usec > 0) |
for (i = usec * bogo_usec; i > 0; i--) |
/* (perhaps hw delay action) */; |
} |
|
/* Most drivers will register just with GetBits/PutBits functions. |
* The following functions implement a software I2C protocol |
* by using the promitive functions given by the driver. |
* ================================================================ |
* |
* It is assumed that there is just one master on the I2C bus, therefore |
* there is no explicit test for conflits. |
*/ |
|
#define RISEFALLTIME 2 /* usec, actually 300 to 1000 ns according to the i2c specs */ |
|
/* Some devices will hold SCL low to slow down the bus or until |
* ready for transmission. |
* |
* This condition will be noticed when the master tries to raise |
* the SCL line. You can set the timeout to zero if the slave device |
* does not support this clock synchronization. |
*/ |
|
static Bool |
I2CRaiseSCL(I2CBusPtr b, int sda, int timeout) |
{ |
int i, scl; |
|
b->I2CPutBits(b, 1, sda); |
b->I2CUDelay(b, b->RiseFallTime); |
|
for (i = timeout; i > 0; i -= b->RiseFallTime) { |
b->I2CGetBits(b, &scl, &sda); |
if (scl) break; |
b->I2CUDelay(b, b->RiseFallTime); |
} |
|
if (i <= 0) { |
// I2C_TIMEOUT(ErrorF("[I2CRaiseSCL(<%s>, %d, %d) timeout]", b->BusName, sda, timeout)); |
return FALSE; |
} |
|
return TRUE; |
} |
|
/* Send a start signal on the I2C bus. The start signal notifies |
* devices that a new transaction is initiated by the bus master. |
* |
* The start signal is always followed by a slave address. |
* Slave addresses are 8+ bits. The first 7 bits identify the |
* device and the last bit signals if this is a read (1) or |
* write (0) operation. |
* |
* There may be more than one start signal on one transaction. |
* This happens for example on some devices that allow reading |
* of registers. First send a start bit followed by the device |
* address (with the last bit 0) and the register number. Then send |
* a new start bit with the device address (with the last bit 1) |
* and then read the value from the device. |
* |
* Note this is function does not implement a multiple master |
* arbitration procedure. |
*/ |
|
static Bool |
I2CStart(I2CBusPtr b, int timeout) |
{ |
if (!I2CRaiseSCL(b, 1, timeout)) |
return FALSE; |
|
b->I2CPutBits(b, 1, 0); |
b->I2CUDelay(b, b->HoldTime); |
b->I2CPutBits(b, 0, 0); |
b->I2CUDelay(b, b->HoldTime); |
|
// I2C_TRACE(ErrorF("\ni2c: <")); |
|
return TRUE; |
} |
|
/* This is the default I2CStop function if not supplied by the driver. |
* |
* Signal devices on the I2C bus that a transaction on the |
* bus has finished. There may be more than one start signal |
* on a transaction but only one stop signal. |
*/ |
|
static void |
I2CStop(I2CDevPtr d) |
{ |
I2CBusPtr b = d->pI2CBus; |
|
b->I2CPutBits(b, 0, 0); |
b->I2CUDelay(b, b->RiseFallTime); |
|
b->I2CPutBits(b, 1, 0); |
b->I2CUDelay(b, b->HoldTime); |
b->I2CPutBits(b, 1, 1); |
b->I2CUDelay(b, b->HoldTime); |
|
I2C_TRACE(ErrorF(">\n")); |
} |
|
/* Write/Read a single bit to/from a device. |
* Return FALSE if a timeout occurs. |
*/ |
|
static Bool |
I2CWriteBit(I2CBusPtr b, int sda, int timeout) |
{ |
Bool r; |
|
b->I2CPutBits(b, 0, sda); |
b->I2CUDelay(b, b->RiseFallTime); |
|
r = I2CRaiseSCL(b, sda, timeout); |
b->I2CUDelay(b, b->HoldTime); |
|
b->I2CPutBits(b, 0, sda); |
b->I2CUDelay(b, b->HoldTime); |
|
return r; |
} |
|
static Bool |
I2CReadBit(I2CBusPtr b, int *psda, int timeout) |
{ |
Bool r; |
int scl; |
|
r = I2CRaiseSCL(b, 1, timeout); |
b->I2CUDelay(b, b->HoldTime); |
|
b->I2CGetBits(b, &scl, psda); |
|
b->I2CPutBits(b, 0, 1); |
b->I2CUDelay(b, b->HoldTime); |
|
return r; |
} |
|
/* This is the default I2CPutByte function if not supplied by the driver. |
* |
* A single byte is sent to the device. |
* The function returns FALSE if a timeout occurs, you should send |
* a stop condition afterwards to reset the bus. |
* |
* A timeout occurs, |
* if the slave pulls SCL to slow down the bus more than ByteTimeout usecs, |
* or slows down the bus for more than BitTimeout usecs for each bit, |
* or does not send an ACK bit (0) to acknowledge the transmission within |
* AcknTimeout usecs, but a NACK (1) bit. |
* |
* AcknTimeout must be at least b->HoldTime, the other timeouts can be |
* zero according to the comment on I2CRaiseSCL. |
*/ |
|
static Bool |
I2CPutByte(I2CDevPtr d, I2CByte data) |
{ |
Bool r; |
int i, scl, sda; |
I2CBusPtr b = d->pI2CBus; |
|
if (!I2CWriteBit(b, (data >> 7) & 1, d->ByteTimeout)) |
return FALSE; |
|
for (i = 6; i >= 0; i--) |
if (!I2CWriteBit(b, (data >> i) & 1, d->BitTimeout)) |
return FALSE; |
|
b->I2CPutBits(b, 0, 1); |
b->I2CUDelay(b, b->RiseFallTime); |
|
r = I2CRaiseSCL(b, 1, b->HoldTime); |
|
if (r) |
{ |
for (i = d->AcknTimeout; i > 0; i -= b->HoldTime) |
{ |
b->I2CUDelay(b, b->HoldTime); |
b->I2CGetBits(b, &scl, &sda); |
if (sda == 0) break; |
} |
if (i <= 0) |
{ |
// I2C_TIMEOUT(ErrorF("[I2CPutByte(<%s>, 0x%02x, %d, %d, %d) timeout]", |
// b->BusName, data, d->BitTimeout, |
// d->ByteTimeout, d->AcknTimeout)); |
r = FALSE; |
} |
|
// I2C_TRACE(ErrorF("W%02x%c ", (int) data, sda ? '-' : '+')); |
} |
|
b->I2CPutBits(b, 0, 1); |
b->I2CUDelay(b, b->HoldTime); |
|
return r; |
} |
|
/* This is the default I2CGetByte function if not supplied by the driver. |
* |
* A single byte is read from the device. |
* The function returns FALSE if a timeout occurs, you should send |
* a stop condition afterwards to reset the bus. |
* |
* A timeout occurs, |
* if the slave pulls SCL to slow down the bus more than ByteTimeout usecs, |
* or slows down the bus for more than b->BitTimeout usecs for each bit. |
* |
* ByteTimeout must be at least b->HoldTime, the other timeouts can be |
* zero according to the comment on I2CRaiseSCL. |
* |
* For the <last> byte in a sequence the acknowledge bit NACK (1), |
* otherwise ACK (0) will be sent. |
*/ |
|
static Bool |
I2CGetByte(I2CDevPtr d, I2CByte *data, Bool last) |
{ |
int i, sda; |
I2CBusPtr b = d->pI2CBus; |
|
b->I2CPutBits(b, 0, 1); |
b->I2CUDelay(b, b->RiseFallTime); |
|
if (!I2CReadBit(b, &sda, d->ByteTimeout)) |
return FALSE; |
|
*data = (sda > 0) << 7; |
|
for (i = 6; i >= 0; i--) |
if (!I2CReadBit(b, &sda, d->BitTimeout)) |
return FALSE; |
else |
*data |= (sda > 0) << i; |
|
if (!I2CWriteBit(b, last ? 1 : 0, d->BitTimeout)) |
return FALSE; |
|
// I2C_TRACE(ErrorF("R%02x%c ", (int) *data, last ? '+' : '-')); |
|
return TRUE; |
} |
|
/* This is the default I2CAddress function if not supplied by the driver. |
* |
* It creates the start condition, followed by the d->SlaveAddr. |
* Higher level functions must call this routine rather than |
* I2CStart/PutByte because a hardware I2C master may not be able |
* to send a slave address without a start condition. |
* |
* The same timeouts apply as with I2CPutByte and additional a |
* StartTimeout, similar to the ByteTimeout but for the start |
* condition. |
* |
* In case of a timeout, the bus is left in a clean idle condition. |
* I. e. you *must not* send a Stop. If this function succeeds, you *must*. |
* |
* The slave address format is 16 bit, with the legacy _8_bit_ slave address |
* in the least significant byte. This is, the slave address must include the |
* R/_W flag as least significant bit. |
* |
* The most significant byte of the address will be sent _after_ the LSB, |
* but only if the LSB indicates: |
* a) an 11 bit address, this is LSB = 1111 0xxx. |
* b) a 'general call address', this is LSB = 0000 000x - see the I2C specs |
* for more. |
*/ |
|
static Bool |
I2CAddress(I2CDevPtr d, I2CSlaveAddr addr) |
{ |
if (I2CStart(d->pI2CBus, d->StartTimeout)) { |
if (I2CPutByte(d, addr & 0xFF)) { |
if ((addr & 0xF8) != 0xF0 && |
(addr & 0xFE) != 0x00) |
return TRUE; |
|
if (I2CPutByte(d, (addr >> 8) & 0xFF)) |
return TRUE; |
} |
|
I2CStop(d); |
} |
|
return FALSE; |
} |
|
/* These are the hardware independent I2C helper functions. |
* ======================================================== |
*/ |
|
/* Function for probing. Just send the slave address |
* and return true if the device responds. The slave address |
* must have the lsb set to reflect a read (1) or write (0) access. |
* Don't expect a read- or write-only device will respond otherwise. |
*/ |
|
Bool |
xf86I2CProbeAddress(I2CBusPtr b, I2CSlaveAddr addr) |
{ |
int r; |
I2CDevRec d; |
|
d.DevName = "Probing"; |
d.BitTimeout = b->BitTimeout; |
d.ByteTimeout = b->ByteTimeout; |
d.AcknTimeout = b->AcknTimeout; |
d.StartTimeout = b->StartTimeout; |
d.SlaveAddr = addr; |
d.pI2CBus = b; |
d.NextDev = NULL; |
|
r = b->I2CAddress(&d, addr); |
|
if (r) b->I2CStop(&d); |
|
return r; |
} |
|
/* All functions below are related to devices and take the |
* slave address and timeout values from an I2CDevRec. They |
* return FALSE in case of an error (presumably a timeout). |
*/ |
|
/* General purpose read and write function. |
* |
* 1st, if nWrite > 0 |
* Send a start condition |
* Send the slave address (1 or 2 bytes) with write flag |
* Write n bytes from WriteBuffer |
* 2nd, if nRead > 0 |
* Send a start condition [again] |
* Send the slave address (1 or 2 bytes) with read flag |
* Read n bytes to ReadBuffer |
* 3rd, if a Start condition has been successfully sent, |
* Send a Stop condition. |
* |
* The functions exits immediately when an error occures, |
* not proceeding any data left. However, step 3 will |
* be executed anyway to leave the bus in clean idle state. |
*/ |
|
static Bool |
I2CWriteRead(I2CDevPtr d, |
I2CByte *WriteBuffer, int nWrite, |
I2CByte *ReadBuffer, int nRead) |
{ |
Bool r = TRUE; |
I2CBusPtr b = d->pI2CBus; |
int s = 0; |
|
if (r && nWrite > 0) { |
r = b->I2CAddress(d, d->SlaveAddr & ~1); |
if (r) { |
for (; nWrite > 0; WriteBuffer++, nWrite--) |
if (!(r = b->I2CPutByte(d, *WriteBuffer))) |
break; |
s++; |
} |
} |
|
if (r && nRead > 0) { |
r = b->I2CAddress(d, d->SlaveAddr | 1); |
if (r) { |
for (; nRead > 0; ReadBuffer++, nRead--) |
if (!(r = b->I2CGetByte(d, ReadBuffer, nRead == 1))) |
break; |
s++; |
} |
} |
|
if (s) b->I2CStop(d); |
|
return r; |
} |
|
/* wrapper - for compatibility and convinience */ |
|
Bool |
xf86I2CWriteRead(I2CDevPtr d, |
I2CByte *WriteBuffer, int nWrite, |
I2CByte *ReadBuffer, int nRead) |
{ |
RHDFUNC(d); |
|
I2CBusPtr b = d->pI2CBus; |
return b->I2CWriteRead(d,WriteBuffer,nWrite,ReadBuffer,nRead); |
} |
|
/* Read a byte, the only readable register of a device. |
*/ |
|
Bool |
xf86I2CReadStatus(I2CDevPtr d, I2CByte *pbyte) |
{ |
return xf86I2CWriteRead(d, NULL, 0, pbyte, 1); |
} |
|
/* Read a byte from one of the registers determined by its sub-address. |
*/ |
|
Bool |
xf86I2CReadByte(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte) |
{ |
return xf86I2CWriteRead(d, &subaddr, 1, pbyte, 1); |
} |
|
/* Read bytes from subsequent registers determined by the |
* sub-address of the first register. |
*/ |
|
Bool |
xf86I2CReadBytes(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte, int n) |
{ |
return xf86I2CWriteRead(d, &subaddr, 1, pbyte, n); |
} |
|
/* Read a word (high byte, then low byte) from one of the registers |
* determined by its sub-address. |
*/ |
|
Bool |
xf86I2CReadWord(I2CDevPtr d, I2CByte subaddr, unsigned short *pword) |
{ |
I2CByte rb[2]; |
|
if (!xf86I2CWriteRead(d, &subaddr, 1, rb, 2)) return FALSE; |
|
*pword = (rb[0] << 8) | rb[1]; |
|
return TRUE; |
} |
|
/* Write a byte to one of the registers determined by its sub-address. |
*/ |
|
Bool |
xf86I2CWriteByte(I2CDevPtr d, I2CByte subaddr, I2CByte byte) |
{ |
I2CByte wb[2]; |
|
wb[0] = subaddr; |
wb[1] = byte; |
|
return xf86I2CWriteRead(d, wb, 2, NULL, 0); |
} |
|
/* Write bytes to subsequent registers determined by the |
* sub-address of the first register. |
*/ |
|
Bool |
xf86I2CWriteBytes(I2CDevPtr d, I2CByte subaddr, |
I2CByte *WriteBuffer, int nWrite) |
{ |
I2CBusPtr b = d->pI2CBus; |
Bool r = TRUE; |
|
if (nWrite > 0) { |
r = b->I2CAddress(d, d->SlaveAddr & ~1); |
if (r){ |
if ((r = b->I2CPutByte(d, subaddr))) |
for (; nWrite > 0; WriteBuffer++, nWrite--) |
if (!(r = b->I2CPutByte(d, *WriteBuffer))) |
break; |
|
b->I2CStop(d); |
} |
} |
|
return r; |
} |
|
/* Write a word (high byte, then low byte) to one of the registers |
* determined by its sub-address. |
*/ |
|
Bool |
xf86I2CWriteWord(I2CDevPtr d, I2CByte subaddr, unsigned short word) |
{ |
I2CByte wb[3]; |
|
wb[0] = subaddr; |
wb[1] = word >> 8; |
wb[2] = word & 0xFF; |
|
return xf86I2CWriteRead(d, wb, 3, NULL, 0); |
} |
|
/* Write a vector of bytes to not adjacent registers. This vector is, |
* 1st byte sub-address, 2nd byte value, 3rd byte sub-address asf. |
* This function is intended to initialize devices. Note this function |
* exits immediately when an error occurs, some registers may |
* remain uninitialized. |
*/ |
|
Bool |
xf86I2CWriteVec(I2CDevPtr d, I2CByte *vec, int nValues) |
{ |
I2CBusPtr b = d->pI2CBus; |
Bool r = TRUE; |
int s = 0; |
|
if (nValues > 0) { |
for (; nValues > 0; nValues--, vec += 2) { |
if (!(r = b->I2CAddress(d, d->SlaveAddr & ~1))) |
break; |
|
s++; |
|
if (!(r = b->I2CPutByte(d, vec[0]))) |
break; |
|
if (!(r = b->I2CPutByte(d, vec[1]))) |
break; |
} |
|
if (s > 0) b->I2CStop(d); |
} |
|
return r; |
} |
|
/* Administrative functions. |
* ========================= |
*/ |
|
/* Allocates an I2CDevRec for you and initializes with propper defaults |
* you may modify before calling xf86I2CDevInit. Your I2CDevRec must |
* contain at least a SlaveAddr, and a pI2CBus pointer to the bus this |
* device shall be linked to. |
* |
* See function I2CAddress for the slave address format. Always set |
* the least significant bit, indicating a read or write access, to zero. |
*/ |
|
I2CDevPtr |
xf86CreateI2CDevRec(void) |
{ |
return calloc(1, sizeof(I2CDevRec)); |
} |
|
/* Unlink an I2C device. If you got the I2CDevRec from xf86CreateI2CDevRec |
* you should set <unalloc> to free it. |
*/ |
|
void |
xf86DestroyI2CDevRec(I2CDevPtr d, Bool unalloc) |
{ |
if (d) { |
I2CDevPtr *p; |
|
/* Remove this from the list of active I2C devices. */ |
|
for (p = &d->pI2CBus->FirstDev; *p != NULL; p = &(*p)->NextDev) |
if (*p == d) { |
*p = (*p)->NextDev; |
break; |
} |
|
dbgprintf("I2C device \"%s:%s\" removed.\n", |
d->pI2CBus->BusName, d->DevName); |
|
if (unalloc) free(d); |
} |
} |
|
/* I2C transmissions are related to an I2CDevRec you must link to a |
* previously registered bus (see xf86I2CBusInit) before attempting |
* to read and write data. You may call xf86I2CProbeAddress first to |
* see if the device in question is present on this bus. |
* |
* xf86I2CDevInit will not allocate an I2CBusRec for you, instead you |
* may enter a pointer to a statically allocated I2CDevRec or the (modified) |
* result of xf86CreateI2CDevRec. |
* |
* If you don't specify timeouts for the device (n <= 0), it will inherit |
* the bus-wide defaults. The function returns TRUE on success. |
*/ |
|
Bool |
xf86I2CDevInit(I2CDevPtr d) |
{ |
I2CBusPtr b; |
RHDFUNC(d); |
|
if (d == NULL || (b = d->pI2CBus) == NULL || |
(d->SlaveAddr & 1) || xf86I2CFindDev(b, d->SlaveAddr) != NULL) |
return FALSE; |
|
if (d->BitTimeout <= 0) d->BitTimeout = b->BitTimeout; |
if (d->ByteTimeout <= 0) d->ByteTimeout = b->ByteTimeout; |
if (d->AcknTimeout <= 0) d->AcknTimeout = b->AcknTimeout; |
if (d->StartTimeout <= 0) d->StartTimeout = b->StartTimeout; |
|
d->NextDev = b->FirstDev; |
b->FirstDev = d; |
|
dbgprintf("I2C device \"%s:%s\" registered at address 0x%x.\n", |
b->BusName, d->DevName, d->SlaveAddr); |
|
return TRUE; |
} |
|
I2CDevPtr |
xf86I2CFindDev(I2CBusPtr b, I2CSlaveAddr addr) |
{ |
I2CDevPtr d; |
|
if (b) { |
for (d = b->FirstDev; d != NULL; d = d->NextDev) |
if (d->SlaveAddr == addr) |
return d; |
} |
|
return NULL; |
} |
|
static I2CBusPtr I2CBusList; |
|
/* Allocates an I2CBusRec for you and initializes with propper defaults |
* you may modify before calling xf86I2CBusInit. Your I2CBusRec must |
* contain at least a BusName, a scrnIndex (or -1), and a complete set |
* of either high or low level I2C function pointers. You may pass |
* bus-wide timeouts, otherwise inplausible values will be replaced |
* with safe defaults. |
*/ |
|
I2CBusPtr xf86CreateI2CBusRec(void) |
{ |
I2CBusPtr b; |
|
b = (I2CBusPtr) calloc(1, sizeof(I2CBusRec)); |
|
if (b != NULL) |
{ |
b->scrnIndex = -1; |
b->HoldTime = 5; /* 100 kHz bus */ |
b->BitTimeout = 5; |
b->ByteTimeout = 5; |
b->AcknTimeout = 5; |
b->StartTimeout = 5; |
b->RiseFallTime = RISEFALLTIME; |
} |
return b; |
} |
|
/* Unregister an I2C bus. If you got the I2CBusRec from xf86CreateI2CBusRec |
* you should set <unalloc> to free it. If you set <devs_too>, the function |
* xf86DestroyI2CDevRec will be called for all devices linked to the bus |
* first, passing down the <unalloc> option. |
*/ |
|
void |
xf86DestroyI2CBusRec(I2CBusPtr b, Bool unalloc, Bool devs_too) |
{ |
if (b) { |
I2CBusPtr *p; |
|
/* Remove this from the list of active I2C buses */ |
|
for (p = &I2CBusList; *p != NULL; p = &(*p)->NextBus) |
if (*p == b) { |
*p = (*p)->NextBus; |
break; |
} |
|
if (b->FirstDev != NULL) { |
if (devs_too) { |
I2CDevPtr d; |
|
while ((d = b->FirstDev) != NULL) { |
b->FirstDev = d->NextDev; |
xf86DestroyI2CDevRec(d, unalloc); |
} |
} else { |
if (unalloc) { |
dbgprintf("i2c bug: Attempt to remove I2C bus \"%s\", " |
"but device list is not empty.\n", |
b->BusName); |
return; |
} |
} |
} |
|
dbgprintf("I2C bus \"%s\" removed.\n", b->BusName); |
|
if (unalloc) free(b); |
} |
} |
|
/* I2C masters have to register themselves using this function. |
* It will not allocate an I2CBusRec for you, instead you may enter |
* a pointer to a statically allocated I2CBusRec or the (modified) |
* result of xf86CreateI2CBusRec. Returns TRUE on success. |
* |
* At this point there won't be any traffic on the I2C bus. |
*/ |
|
Bool xf86I2CBusInit(I2CBusPtr b) |
{ |
/* I2C buses must be identified by a unique scrnIndex |
* and name. If scrnIndex is unspecified (a negative value), |
* then the name must be unique throughout the server. |
*/ |
|
if (b->BusName == NULL || |
xf86I2CFindBus(b->scrnIndex, b->BusName) != NULL) |
return FALSE; |
|
/* If the high level functions are not |
* supplied, use the generic functions. |
* In this case we need the low-level |
* function. |
*/ |
if (b->I2CWriteRead == NULL) |
{ |
b->I2CWriteRead=I2CWriteRead; |
|
if (b->I2CPutBits == NULL || |
b->I2CGetBits == NULL) |
{ |
if (b->I2CPutByte == NULL || |
b->I2CGetByte == NULL || |
b->I2CAddress == NULL || |
b->I2CStart == NULL || |
b->I2CStop == NULL) |
return FALSE; |
} |
else |
{ |
b->I2CPutByte = I2CPutByte; |
b->I2CGetByte = I2CGetByte; |
b->I2CAddress = I2CAddress; |
b->I2CStop = I2CStop; |
b->I2CStart = I2CStart; |
} |
} |
|
if (b->I2CUDelay == NULL) |
b->I2CUDelay = I2CUDelay; |
|
if (b->HoldTime < 2) b->HoldTime = 5; |
if (b->BitTimeout <= 0) b->BitTimeout = b->HoldTime; |
if (b->ByteTimeout <= 0) b->ByteTimeout = b->HoldTime; |
if (b->AcknTimeout <= 0) b->AcknTimeout = b->HoldTime; |
if (b->StartTimeout <= 0) b->StartTimeout = b->HoldTime; |
|
/* Put new bus on list. */ |
|
b->NextBus = I2CBusList; |
I2CBusList = b; |
|
dbgprintf("I2C bus \"%s\" initialized.\n",b->BusName); |
|
return TRUE; |
} |
|
I2CBusPtr |
xf86I2CFindBus(RHDPtr rhdPtr, char *name) |
{ |
I2CBusPtr p; |
|
if (name != NULL) |
for (p = I2CBusList; p != NULL; p = p->NextBus) |
if ((rhdPtr==(RHDPtr)-1) ||(p->scrnIndex == (int)rhdPtr)) |
if (!strcmp(p->BusName, name)) |
return p; |
|
return NULL; |
} |
/* |
* Return an array of I2CBusPtr's related to a screen. The caller is |
* responsible for freeing the array. |
*/ |
|
/* |
int |
xf86I2CGetScreenBuses(RHDPtr rhdPtr, I2CBusPtr **pppI2CBus) |
{ |
I2CBusPtr pI2CBus; |
int n = 0; |
|
if (pppI2CBus) |
*pppI2CBus = NULL; |
|
for (pI2CBus = I2CBusList; pI2CBus; pI2CBus = pI2CBus->NextBus) |
{ |
if ((pI2CBus->rhdPtr >= 0) && (pI2CBus->rhdPtr != rhdPtr)) |
continue; |
|
n++; |
|
if (!pppI2CBus) |
continue; |
|
*pppI2CBus = xnfrealloc(*pppI2CBus, n * sizeof(I2CBusPtr)); |
*pppI2CBus[n - 1] = pI2CBus; |
} |
return n; |
} |
|
*/ |