Patch by Vasilis Kaoutsis - thanks!:

* Fixed some warnings.
* Style cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21774 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2007-07-31 17:20:34 +00:00
parent a898ee19d6
commit 7b48d975f5
5 changed files with 351 additions and 278 deletions
+72 -56
View File
@@ -1,89 +1,103 @@
/* /*
Copyright (c) 2003, Thomas Kurschel * Copyright 2003, Thomas Kurschel. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
Part of DDC driver /*!
Part of DDC driver
Main DDC communication Main DDC communication
*/ */
#include <OS.h>
#include <KernelExport.h>
#include <stdlib.h>
#include "ddc_int.h" #include "ddc_int.h"
#include "ddc.h" #include "ddc.h"
#include "i2c.h" #include "i2c.h"
// number of retries to read ddc data #include <KernelExport.h>
#define READ_RETRIES 4 #include <OS.h>
// verify checksum of ddc data #include <stdlib.h>
// (some monitors have a broken checksum - bad luck for them)
static status_t verify_checksum( const uint8 *data, size_t len )
#define READ_RETRIES 4
// number of retries to read ddc data
#if 0
/*! Verify checksum of ddc data
(some monitors have a broken checksum - bad luck for them)
*/
static status_t
verify_checksum(const uint8 *data, size_t len)
{ {
int i; uint32 index;
uint8 sum = 0; uint8 sum = 0;
uint8 all_or = 0; uint8 all_or = 0;
for( i = 0; i < len; ++i, ++data ) { for (index = 0; index < len; ++index, ++data) {
sum += *data; sum += *data;
all_or |= *data; all_or |= *data;
} }
if( all_or == 0 ) { if (all_or == 0) {
SHOW_ERROR0( 2, "DDC information contains zeros only" ); SHOW_ERROR0(2, "DDC information contains zeros only");
return B_ERROR; return B_ERROR;
} }
if( sum != 0 ) { if (sum != 0) {
SHOW_ERROR0( 2, "Checksum error of DDC information" ); SHOW_ERROR0(2, "Checksum error of DDC information");
return B_IO_ERROR; return B_IO_ERROR;
} }
return B_OK; return B_OK;
} }
#endif
// read ddc2 data from monitor
static status_t ddc2_read( const i2c_bus *bus, int start, uint8 *buffer, size_t len ) //! Read ddc2 data from monitor
static status_t
ddc2_read(const i2c_bus *bus, int start, uint8 *buffer, size_t len)
{ {
uint8 write_buffer[2]; uint8 write_buffer[2];
i2c_timing timing; i2c_timing timing;
int i; int i;
status_t res; status_t res = B_OK;
write_buffer[0] = start & 0xff; write_buffer[0] = start & 0xff;
write_buffer[1] = (start >> 8) & 0xff; write_buffer[1] = (start >> 8) & 0xff;
i2c_get100k_timing( &timing ); i2c_get100k_timing(&timing);
timing.start_timeout = 550; timing.start_timeout = 550;
timing.byte_timeout = 2200; timing.byte_timeout = 2200;
timing.bit_timeout = 40; timing.bit_timeout = 40;
timing.ack_start_timeout = 40; timing.ack_start_timeout = 40;
timing.ack_timeout = 40; timing.ack_timeout = 40;
for( i = 0; i < READ_RETRIES; ++i ) { for (i = 0; i < READ_RETRIES; ++i) {
res = i2c_send_receive( bus, &timing, res = i2c_send_receive(bus, &timing,
0xa0, write_buffer, start < 0x100 ? 1 : 2, 0xa0, write_buffer, start < 0x100 ? 1 : 2,
buffer, len ); buffer, len);
// don't verify checksum - it's often broken // don't verify checksum - it's often broken
if( res == B_OK /*&& verify_checksum( buffer, len ) == B_OK*/ ) if (res == B_OK /*&& verify_checksum( buffer, len ) == B_OK*/)
break; break;
res = B_ERROR; res = B_ERROR;
} }
return res; return res;
} }
// reading VDIF has not been tested. /*!
// it seems that almost noone supports VDIF which makes testing hard, Reading VDIF has not been tested.
// but what's the point anyway? it seems that almost noone supports VDIF which makes testing hard,
but what's the point anyway?
*/
#if 0 #if 0
static status_t ddc2_read_vdif( const i2c_bus *bus, int start, static status_t
void **vdif, size_t *vdif_len ) ddc2_read_vdif(const i2c_bus *bus, int start,
void **vdif, size_t *vdif_len)
{ {
status_t res; status_t res;
uint8 *data, *cur_data; uint8 *data, *cur_data;
@@ -93,21 +107,21 @@ static status_t ddc2_read_vdif( const i2c_bus *bus, int start,
*vdif = NULL; *vdif = NULL;
*vdif_len = 0; *vdif_len = 0;
res = ddc2_read( bus, start, buffer, 64 ); res = ddc2_read(bus, start, buffer, 64);
SHOW_INFO( 2, "%x", buffer[0] ); SHOW_INFO(2, "%x", buffer[0]);
if( res != B_OK || buffer[0] == 0 ) if (res != B_OK || buffer[0] == 0)
return B_OK; return B_OK;
// each block is 63 bytes plus 1 checksum long // each block is 63 bytes plus 1 checksum long
// we strip the checksum but store data directly into // we strip the checksum but store data directly into
// buffer, so we need an extra byte for checksum of the last block // buffer, so we need an extra byte for checksum of the last block
data = malloc( buffer[0] * 63 + 1 ); data = malloc(buffer[0] * 63 + 1);
if( data == NULL ) if (data == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
cur_data = data; cur_data = data;
for( i = 0; i < buffer[0]; ++i ) { for (i = 0; i < buffer[0]; ++i) {
ddc2_read( bus, start + i * 64, cur_data, 64 ); ddc2_read(bus, start + i * 64, cur_data, 64);
// strip checksum byte // strip checksum byte
cur_data += 63; cur_data += 63;
} }
@@ -118,29 +132,31 @@ static status_t ddc2_read_vdif( const i2c_bus *bus, int start,
} }
#endif #endif
// read EDID and VDIF from monitor via ddc2
status_t ddc2_read_edid1( const i2c_bus *bus, edid1_info *edid, //! Read EDID and VDIF from monitor via ddc2
void **vdif, size_t *vdif_len ) status_t
ddc2_read_edid1(const i2c_bus *bus, edid1_info *edid,
void **vdif, size_t *vdif_len)
{ {
status_t res; status_t res;
edid1_raw raw; edid1_raw raw;
res = ddc2_read( bus, 0, (uint8 *)&raw, sizeof( raw )); res = ddc2_read(bus, 0, (uint8 *)&raw, sizeof(raw));
if( res != B_OK ) if (res != B_OK)
return res; return res;
edid_decode( edid, &raw ); edid_decode(edid, &raw);
*vdif = NULL; *vdif = NULL;
*vdif_len = 0; *vdif_len = 0;
// skip vdif as long as it's not tested // skip vdif as long as it's not tested
#if 0 #if 0
res = ddc2_read_vdif( bus, sizeof( raw ) * (edid->num_sections + 1), res = ddc2_read_vdif(bus, sizeof(raw) * (edid->num_sections + 1),
vdif, vdif_len ); vdif, vdif_len);
if( res != B_OK ) if (res != B_OK)
return res; return res;
#endif #endif
return B_OK; return B_OK;
} }
+13 -5
View File
@@ -1,14 +1,20 @@
/* /*
Copyright (c) 2003, Thomas Kurschel * Copyright 2003, Thomas Kurschel. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef DDC_INT_H
#define DDC_INT_H
Part of DDC driver /*!
Part of DDC driver
Internal header Internal header
*/ */
// no dprintf in user space, but if you know the trick ;)
void _sPrintf(const char *format, ...); void _sPrintf(const char *format, ...);
// no dprintf in user space, but if you know the trick ;)
//bool set_dprintf_enabled(bool); /* returns old enable flag */ //bool set_dprintf_enabled(bool); /* returns old enable flag */
#define dprintf _sPrintf #define dprintf _sPrintf
@@ -21,3 +27,5 @@ void _sPrintf(const char *format, ...);
#define DEBUG_MSG_PREFIX "DDC " #define DEBUG_MSG_PREFIX "DDC "
#include "debug_ext.h" #include "debug_ext.h"
#endif // DDC_INT_H
+14 -4
View File
@@ -1,8 +1,9 @@
/* /*
* Copyright (c) 2003, Thomas Kurschel. All Rights Reserved. * Copyright 2003, Thomas Kurschel. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
/*! /*!
Part of DDC driver Part of DDC driver
@@ -16,6 +17,7 @@
#include "edid.h" #include "edid.h"
#include <KernelExport.h> #include <KernelExport.h>
#include <string.h> #include <string.h>
@@ -89,12 +91,15 @@ decode_std_timing(edid1_std_timing *timing, const edid1_std_timing_raw *raw)
case 0: case 0:
timing->v_size = timing->h_size; timing->v_size = timing->h_size;
break; break;
case 1: case 1:
timing->v_size = timing->h_size * 3 / 4; timing->v_size = timing->h_size * 3 / 4;
break; break;
case 2: case 2:
timing->v_size = timing->h_size * 4 / 5; timing->v_size = timing->h_size * 4 / 5;
break; break;
case 3: case 3:
timing->v_size = timing->h_size * 9 / 16; timing->v_size = timing->h_size * 9 / 16;
break; break;
@@ -120,7 +125,7 @@ decode_whitepoint(edid1_whitepoint *whitepoint, const edid1_whitepoint_raw *raw)
static void static void
decode_detailed_timing( edid1_detailed_timing *timing, decode_detailed_timing(edid1_detailed_timing *timing,
const edid1_detailed_timing_raw *raw) const edid1_detailed_timing_raw *raw)
{ {
timing->pixel_clock = raw->pixel_clock; timing->pixel_clock = raw->pixel_clock;
@@ -168,7 +173,7 @@ copy_str(char *dest, const uint8 *src, size_t len)
static void static void
decode_detailed_monitor( edid1_detailed_monitor *monitor, decode_detailed_monitor(edid1_detailed_monitor *monitor,
const edid1_detailed_monitor_raw *raw, bool enableExtra) const edid1_detailed_monitor_raw *raw, bool enableExtra)
{ {
int i, j; int i, j;
@@ -191,21 +196,26 @@ decode_detailed_monitor( edid1_detailed_monitor *monitor,
copy_str( monitor->data.serial_number, copy_str( monitor->data.serial_number,
raw->extra.data.serial_number, EDID1_EXTRA_STRING_LEN ); raw->extra.data.serial_number, EDID1_EXTRA_STRING_LEN );
break; break;
case edid1_ascii_data: case edid1_ascii_data:
copy_str( monitor->data.ascii_data, copy_str( monitor->data.ascii_data,
raw->extra.data.ascii_data, EDID1_EXTRA_STRING_LEN ); raw->extra.data.ascii_data, EDID1_EXTRA_STRING_LEN );
break; break;
case edid1_monitor_ranges: case edid1_monitor_ranges:
monitor->data.monitor_range = raw->extra.data.monitor_range; monitor->data.monitor_range = raw->extra.data.monitor_range;
break; break;
case edid1_monitor_name: case edid1_monitor_name:
copy_str( monitor->data.monitor_name, copy_str( monitor->data.monitor_name,
raw->extra.data.monitor_name, EDID1_EXTRA_STRING_LEN ); raw->extra.data.monitor_name, EDID1_EXTRA_STRING_LEN );
break; break;
case edid1_add_colour_pointer: case edid1_add_colour_pointer:
decode_whitepoint( monitor->data.whitepoint, decode_whitepoint( monitor->data.whitepoint,
&raw->extra.data.whitepoint ); &raw->extra.data.whitepoint );
break; break;
case edid1_add_std_timing: case edid1_add_std_timing:
for (j = 0; j < EDID1_NUM_EXTRA_STD_TIMING; ++j) { for (j = 0; j < EDID1_NUM_EXTRA_STD_TIMING; ++j) {
decode_std_timing(&monitor->data.std_timing[j], decode_std_timing(&monitor->data.std_timing[j],
@@ -224,7 +234,7 @@ decode_detailed_monitor( edid1_detailed_monitor *monitor,
// #pragma mark - // #pragma mark -
//! main function to decode edid data //! Main function to decode edid data
void void
edid_decode(edid1_info *edid, const edid1_raw *raw) edid_decode(edid1_info *edid, const edid1_raw *raw)
{ {
+17 -5
View File
@@ -3,11 +3,13 @@
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
/*! /*!
Part of DDC driver Part of DDC driver
Dumps EDID content Dumps EDID content
*/ */
#include "edid.h" #include "edid.h"
#if !defined(_KERNEL_MODE) && !defined(_BOOT_MODE) #if !defined(_KERNEL_MODE) && !defined(_BOOT_MODE)
# include "ddc_int.h" # include "ddc_int.h"
@@ -91,10 +93,13 @@ edid_dump(edid1_info *edid)
case edid1_serial_number: case edid1_serial_number:
dprintf("Serial Number: %s\n", monitor->data.serial_number); dprintf("Serial Number: %s\n", monitor->data.serial_number);
break; break;
case edid1_ascii_data: case edid1_ascii_data:
dprintf(" %s\n", monitor->data.serial_number); dprintf(" %s\n", monitor->data.serial_number);
break; break;
case edid1_monitor_ranges: {
case edid1_monitor_ranges:
{
edid1_monitor_range monitor_range = monitor->data.monitor_range; edid1_monitor_range monitor_range = monitor->data.monitor_range;
dprintf("Horizontal frequency range = %d..%d kHz\n", dprintf("Horizontal frequency range = %d..%d kHz\n",
@@ -104,10 +109,13 @@ edid_dump(edid1_info *edid)
dprintf("Maximum pixel clock = %d MHz\n", (uint16)monitor_range.max_clock * 10); dprintf("Maximum pixel clock = %d MHz\n", (uint16)monitor_range.max_clock * 10);
break; break;
} }
case edid1_monitor_name: case edid1_monitor_name:
dprintf("Monitor Name: %s\n", monitor->data.serial_number); dprintf("Monitor Name: %s\n", monitor->data.serial_number);
break; break;
case edid1_add_colour_pointer: {
case edid1_add_colour_pointer:
{
for (j = 0; j < EDID1_NUM_EXTRA_WHITEPOINTS; ++j) { for (j = 0; j < EDID1_NUM_EXTRA_WHITEPOINTS; ++j) {
edid1_whitepoint *whitepoint = &monitor->data.whitepoint[j]; edid1_whitepoint *whitepoint = &monitor->data.whitepoint[j];
@@ -122,7 +130,9 @@ edid_dump(edid1_info *edid)
} }
break; break;
} }
case edid1_add_std_timing: {
case edid1_add_std_timing:
{
for (j = 0; j < EDID1_NUM_EXTRA_STD_TIMING; ++j) { for (j = 0; j < EDID1_NUM_EXTRA_STD_TIMING; ++j) {
edid1_std_timing *timing = &monitor->data.std_timing[j]; edid1_std_timing *timing = &monitor->data.std_timing[j];
@@ -135,9 +145,11 @@ edid_dump(edid1_info *edid)
} }
break; break;
} }
case edid1_is_detailed_timing: {
case edid1_is_detailed_timing:
{
edid1_detailed_timing *timing = &monitor->data.detailed_timing; edid1_detailed_timing *timing = &monitor->data.detailed_timing;
dprintf("Additional Video Mode:\n"); dprintf("Additional Video Mode:\n");
dprintf("clock=%f MHz\n", timing->pixel_clock / 100.0); dprintf("clock=%f MHz\n", timing->pixel_clock / 100.0);
dprintf("h: (%d, %d, %d, %d)\n", dprintf("h: (%d, %d, %d, %d)\n",
+235 -208
View File
@@ -1,215 +1,227 @@
/* /*
Copyright (c) 2003, Thomas Kurschel * Copyright 2003, Thomas Kurschel. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
Part of DDC driver /*!
Part of DDC driver
I2C protocoll I2C protocoll
*/ */
#include <OS.h> #include "ddc_int.h"
#include <KernelExport.h>
#include "i2c.h" #include "i2c.h"
#include "ddc_int.h" #include <KernelExport.h>
#include <OS.h>
// there's no spin in user space, but we need it to wait a couple /*!
// of microseconds only There's no spin in user space, but we need it to wait a couple
// (in this case, snooze has much too much overhead) of microseconds only
void spin( bigtime_t delay ) (in this case, snooze has much too much overhead)
*/
void
spin(bigtime_t delay)
{ {
bigtime_t start_time = system_time(); bigtime_t start_time = system_time();
while( system_time() - start_time < delay ) while (system_time() - start_time < delay)
; ;
} }
// wait until slave releases clock signal ("clock stretching") //! Wait until slave releases clock signal ("clock stretching")
static status_t wait_for_clk( const i2c_bus *bus, const i2c_timing *timing, static status_t
bigtime_t timeout ) wait_for_clk(const i2c_bus *bus, const i2c_timing *timing,
bigtime_t timeout)
{ {
bigtime_t start_time; bigtime_t start_time;
// wait for clock signal to raise // wait for clock signal to raise
spin( timing->r ); spin(timing->r);
start_time = system_time(); start_time = system_time();
while( 1 ) { while (1) {
int clk, data; int clk, data;
bus->get_signals( bus->cookie, &clk, &data ); bus->get_signals(bus->cookie, &clk, &data);
if( clk != 0 ) if (clk != 0)
return B_OK; return B_OK;
if( system_time() - start_time > timeout ) if (system_time() - start_time > timeout)
return B_TIMEOUT; return B_TIMEOUT;
spin( timing->r ); spin(timing->r);
} }
} }
// send start or repeated start condition //! Send start or repeated start condition
static status_t send_start_condition( const i2c_bus *bus, const i2c_timing *timing ) static status_t
send_start_condition(const i2c_bus *bus, const i2c_timing *timing)
{ {
status_t res; status_t res;
bus->set_signals( bus->cookie, 1, 1 ); bus->set_signals(bus->cookie, 1, 1);
res = wait_for_clk( bus, timing, timing->start_timeout ); res = wait_for_clk(bus, timing, timing->start_timeout);
if( res != B_OK ) { if (res != B_OK) {
SHOW_FLOW0( 3, "Timeout sending start condition" ); SHOW_FLOW0(3, "Timeout sending start condition");
return res; return res;
} }
spin( timing->su_sta ); spin(timing->su_sta);
bus->set_signals( bus->cookie, 1, 0 ); bus->set_signals(bus->cookie, 1, 0);
spin( timing->hd_sta ); spin(timing->hd_sta);
bus->set_signals( bus->cookie, 0, 0 ); bus->set_signals(bus->cookie, 0, 0);
spin( timing->f ); spin(timing->f);
return B_OK; return B_OK;
} }
// send stop condition //! Send stop condition
static status_t send_stop_condition( const i2c_bus *bus, const i2c_timing *timing ) static status_t
send_stop_condition(const i2c_bus *bus, const i2c_timing *timing)
{ {
status_t res; status_t res;
bus->set_signals( bus->cookie, 0, 0 ); bus->set_signals(bus->cookie, 0, 0);
spin( timing->r ); spin(timing->r);
bus->set_signals( bus->cookie, 1, 0 ); bus->set_signals(bus->cookie, 1, 0);
// a slave may wait for us, so let elapse the acknowledge timeout // a slave may wait for us, so let elapse the acknowledge timeout
// to make the slave release bus control // to make the slave release bus control
res = wait_for_clk( bus, timing, timing->ack_timeout ); res = wait_for_clk(bus, timing, timing->ack_timeout);
if( res != B_OK ) { if (res != B_OK) {
SHOW_FLOW0( 3, "Timeout sending stop condition" ); SHOW_FLOW0(3, "Timeout sending stop condition");
return res; return res;
} }
spin( timing->su_sto ); spin(timing->su_sto);
bus->set_signals( bus->cookie, 1, 1 ); bus->set_signals(bus->cookie, 1, 1);
spin( timing->buf ); spin(timing->buf);
SHOW_FLOW0( 3, "" ); SHOW_FLOW0(3, "");
return B_OK; return B_OK;
} }
// send one bit //! Send one bit
static status_t send_bit( const i2c_bus *bus, const i2c_timing *timing, bool bit, int timeout ) static status_t
send_bit(const i2c_bus *bus, const i2c_timing *timing, bool bit, int timeout)
{ {
status_t res; status_t res;
//SHOW_FLOW( 3, "%d", bit & 1 ); //SHOW_FLOW( 3, "%d", bit & 1 );
bus->set_signals( bus->cookie, 0, bit & 1 ); bus->set_signals(bus->cookie, 0, bit & 1);
spin( timing->su_dat ); spin(timing->su_dat);
bus->set_signals( bus->cookie, 1, bit & 1 ); bus->set_signals(bus->cookie, 1, bit & 1);
res = wait_for_clk( bus, timing, timeout ); res = wait_for_clk(bus, timing, timeout);
if( res != B_OK ) { if (res != B_OK) {
SHOW_FLOW0( 3, "Timeout when sending next bit" ); SHOW_FLOW0(3, "Timeout when sending next bit");
return res; return res;
} }
spin( timing->high );
bus->set_signals( bus->cookie, 0, bit & 1 );
spin( timing->f + timing->low );
spin(timing->high);
bus->set_signals(bus->cookie, 0, bit & 1);
spin(timing->f + timing->low);
return B_OK; return B_OK;
} }
// send acknowledge and wait for reply //! Send acknowledge and wait for reply
static status_t send_acknowledge( const i2c_bus *bus, const i2c_timing *timing ) static status_t
send_acknowledge(const i2c_bus *bus, const i2c_timing *timing)
{ {
status_t res; status_t res;
bigtime_t start_time; bigtime_t start_time;
// release data so slave can modify it // release data so slave can modify it
bus->set_signals( bus->cookie, 0, 1 ); bus->set_signals(bus->cookie, 0, 1);
spin( timing->su_dat ); spin(timing->su_dat);
bus->set_signals( bus->cookie, 1, 1 ); bus->set_signals(bus->cookie, 1, 1);
res = wait_for_clk( bus, timing, timing->ack_start_timeout ); res = wait_for_clk(bus, timing, timing->ack_start_timeout);
if( res != B_OK ) { if (res != B_OK) {
SHOW_FLOW0( 3, "Timeout when sending acknowledge" ); SHOW_FLOW0(3, "Timeout when sending acknowledge");
return res; return res;
} }
// data and clock is high, now wait for slave to pull data low // data and clock is high, now wait for slave to pull data low
// (according to spec, this can happen any time once clock is high) // (according to spec, this can happen any time once clock is high)
start_time = system_time(); start_time = system_time();
while( 1 ) { while (1) {
int clk, data; int clk, data;
bus->get_signals( bus->cookie, &clk, &data ); bus->get_signals(bus->cookie, &clk, &data);
if( data == 0 ) if (data == 0)
break; break;
if( system_time() - start_time > timing->ack_timeout ) { if (system_time() - start_time > timing->ack_timeout) {
SHOW_FLOW0( 3, "Slave didn't acknowledge byte" ); SHOW_FLOW0(3, "Slave didn't acknowledge byte");
return B_TIMEOUT; return B_TIMEOUT;
} }
spin( timing->r ); spin(timing->r);
} }
SHOW_FLOW0( 4, "Success!" );
// make sure we've waited at least t_high
spin( timing->high );
bus->set_signals( bus->cookie, 0, 1 ); SHOW_FLOW0(4, "Success!");
spin( timing->f + timing->low );
// make sure we've waited at least t_high
spin(timing->high);
bus->set_signals(bus->cookie, 0, 1);
spin(timing->f + timing->low);
return B_OK; return B_OK;
} }
// send byte and wait for acknowledge if <ackowledge> is true //! Send byte and wait for acknowledge if <ackowledge> is true
static status_t send_byte( const i2c_bus *bus, const i2c_timing *timing, static status_t
uint8 byte, bool acknowledge ) send_byte(const i2c_bus *bus, const i2c_timing *timing,
uint8 byte, bool acknowledge)
{ {
int i; int i;
SHOW_FLOW( 3, "%x ", byte ); SHOW_FLOW( 3, "%x ", byte );
for( i = 7; i >= 0; --i ) { for (i = 7; i >= 0; --i) {
status_t res; status_t res;
res = send_bit( bus, timing, byte >> i, res = send_bit(bus, timing, byte >> i,
i == 7 ? timing->byte_timeout : timing->bit_timeout ); i == 7 ? timing->byte_timeout : timing->bit_timeout);
if( res != B_OK ) if (res != B_OK)
return res; return res;
} }
if( acknowledge ) if (acknowledge)
return send_acknowledge( bus, timing ); return send_acknowledge(bus, timing);
else else
return B_OK; return B_OK;
} }
// send slave address, obeying 10-bit addresses and general call addresses
static status_t send_slave_address( const i2c_bus *bus, //! Send slave address, obeying 10-bit addresses and general call addresses
const i2c_timing *timing, int slave_address, bool is_write ) static status_t
send_slave_address( const i2c_bus *bus, const i2c_timing *timing,
int slave_address, bool is_write )
{ {
status_t res; status_t res;
res = send_byte( bus, timing, (slave_address & 0xfe) | !is_write, true ); res = send_byte(bus, timing, (slave_address & 0xfe) | !is_write, true);
if( res != B_OK ) if (res != B_OK)
return res; return res;
// there are the following special cases if the first byte looks like: // there are the following special cases if the first byte looks like:
// - 0000 0000 - general call address (second byte with address follows) // - 0000 0000 - general call address (second byte with address follows)
// - 0000 0001 - start byte // - 0000 0001 - start byte
@@ -221,154 +233,166 @@ static status_t send_slave_address( const i2c_bus *bus,
// - 1111 0xxx - 10 bit address (second byte contains remaining 8 bits) // - 1111 0xxx - 10 bit address (second byte contains remaining 8 bits)
// the lsb is 0 for write and 1 for read (except for general call address) // the lsb is 0 for write and 1 for read (except for general call address)
if( (slave_address & 0xff) != 0 && if ((slave_address & 0xff) != 0 && (slave_address & 0xf8) != 0xf0)
(slave_address & 0xf8) != 0xf0 )
return B_OK; return B_OK;
// send second byte if required return send_byte(bus, timing, slave_address >> 8, true);
return send_byte( bus, timing, slave_address >> 8, true ); // send second byte if required
} }
// receive one bit //! Receive one bit
static status_t receive_bit( const i2c_bus *bus, const i2c_timing *timing, static status_t
bool *bit, int timeout ) receive_bit(const i2c_bus *bus, const i2c_timing *timing,
bool *bit, int timeout)
{ {
status_t res; status_t res;
int clk, data; int clk, data;
// release clock bus->set_signals(bus->cookie, 1, 1);
bus->set_signals( bus->cookie, 1, 1 ); // release clock
// wait for slave to raise clock // wait for slave to raise clock
res = wait_for_clk( bus, timing, timeout ); res = wait_for_clk(bus, timing, timeout);
if( res != B_OK ) { if (res != B_OK) {
SHOW_FLOW0( 3, "Timeout waiting for bit sent by slave" ); SHOW_FLOW0(3, "Timeout waiting for bit sent by slave");
return res; return res;
} }
// sample data bus->get_signals(bus->cookie, &clk, &data);
bus->get_signals( bus->cookie, &clk, &data ); // sample data
// leave clock high for minimal time
spin( timing->high ); spin(timing->high);
// pull clock low so slave waits for us before next bit // leave clock high for minimal time
bus->set_signals( bus->cookie, 0, 1 );
// let it settle and leave it low for minimal time bus->set_signals(bus->cookie, 0, 1);
// to make sure slave has finished bit transmission too // pull clock low so slave waits for us before next bit
spin( timing->f + timing->low);
spin(timing->f + timing->low);
// let it settle and leave it low for minimal time
// to make sure slave has finished bit transmission too
*bit = data; *bit = data;
return B_OK; return B_OK;
} }
// receive byte
// send positive acknowledge afterwards if <acknowledge> is true, else send negative one /*! receive byte
static status_t receive_byte( const i2c_bus *bus, const i2c_timing *timing, Send positive acknowledge afterwards if <acknowledge> is true,
uint8 *res_byte, bool acknowledge ) else send negative one
*/
static status_t
receive_byte(const i2c_bus *bus, const i2c_timing *timing,
uint8 *res_byte, bool acknowledge)
{ {
uint8 byte = 0; uint8 byte = 0;
int i; int i;
// pull clock low to let slave wait for us
bus->set_signals( bus->cookie, 0, 1 );
for( i = 7; i >= 0; --i ) { // pull clock low to let slave wait for us
bus->set_signals(bus->cookie, 0, 1);
for (i = 7; i >= 0; --i) {
status_t res; status_t res;
bool bit; bool bit;
res = receive_bit( bus, timing, &bit, res = receive_bit(bus, timing, &bit,
i == 7 ? timing->byte_timeout : timing->bit_timeout ); i == 7 ? timing->byte_timeout : timing->bit_timeout);
if( res != B_OK ) if (res != B_OK)
return res; return res;
byte = (byte << 1) | bit; byte = (byte << 1) | bit;
} }
//SHOW_FLOW( 3, "%x ", byte ); //SHOW_FLOW( 3, "%x ", byte );
*res_byte = byte; *res_byte = byte;
return send_bit( bus, timing, acknowledge ? 0 : 1, timing->bit_timeout ); return send_bit(bus, timing, acknowledge ? 0 : 1, timing->bit_timeout);
} }
// send multiple bytes
static status_t send_bytes( const i2c_bus *bus, const i2c_timing *timing, //! Send multiple bytes
const uint8 *write_buffer, ssize_t write_len ) static status_t
send_bytes(const i2c_bus *bus, const i2c_timing *timing,
const uint8 *write_buffer, ssize_t write_len)
{ {
SHOW_FLOW( 3, "len=%ld", write_len ); SHOW_FLOW( 3, "len=%ld", write_len );
for( ; write_len > 0; --write_len, ++write_buffer ) { for (; write_len > 0; --write_len, ++write_buffer) {
status_t res; status_t res;
res = send_byte( bus, timing, *write_buffer, true ); res = send_byte(bus, timing, *write_buffer, true);
if( res != B_OK ) if (res != B_OK)
return res; return res;
} }
return B_OK; return B_OK;
} }
// receive multiple bytes
static status_t receive_bytes( const i2c_bus *bus, const i2c_timing *timing, //! Receive multiple bytes
uint8 *read_buffer, ssize_t read_len ) static status_t
receive_bytes(const i2c_bus *bus, const i2c_timing *timing,
uint8 *read_buffer, ssize_t read_len)
{ {
SHOW_FLOW( 3, "len=%ld", read_len ); SHOW_FLOW(3, "len=%ld", read_len);
for( ; read_len > 0; --read_len, ++read_buffer ) { for (; read_len > 0; --read_len, ++read_buffer) {
status_t res; status_t res;
res = receive_byte( bus, timing, read_buffer, read_len > 1 ); res = receive_byte(bus, timing, read_buffer, read_len > 1);
if( res != B_OK ) if (res != B_OK)
return res; return res;
} }
return B_OK; return B_OK;
} }
// combined i2c send+receive format
status_t i2c_send_receive( const i2c_bus *bus, const i2c_timing *timing, //! Combined i2c send+receive format
int slave_address, status_t
const uint8 *write_buffer, size_t write_len, i2c_send_receive(const i2c_bus *bus, const i2c_timing *timing,
uint8 *read_buffer, size_t read_len ) int slave_address, const uint8 *write_buffer, size_t write_len,
uint8 *read_buffer, size_t read_len)
{ {
status_t res; status_t res;
res = send_start_condition( bus, timing ); res = send_start_condition(bus, timing);
if( res != B_OK ) if (res != B_OK)
return res; return res;
res = send_slave_address( bus, timing, slave_address, true ); res = send_slave_address(bus, timing, slave_address, true);
if( res != B_OK ) if (res != B_OK)
goto err; goto err;
res = send_bytes( bus, timing, write_buffer, write_len ); res = send_bytes(bus, timing, write_buffer, write_len);
if( res != B_OK ) if (res != B_OK)
goto err; goto err;
res = send_start_condition( bus, timing ); res = send_start_condition(bus, timing);
if( res != B_OK ) if (res != B_OK)
return res; return res;
res = send_slave_address( bus, timing, slave_address, false ); res = send_slave_address(bus, timing, slave_address, false);
if( res != B_OK ) if (res != B_OK)
goto err; goto err;
res = receive_bytes( bus, timing, read_buffer, read_len ); res = receive_bytes(bus, timing, read_buffer, read_len);
if( res != B_OK ) if (res != B_OK)
goto err; goto err;
res = send_stop_condition( bus, timing ); res = send_stop_condition(bus, timing);
return res; return res;
err: err:
SHOW_FLOW0( 3, "Cancelling transmission" ); SHOW_FLOW0(3, "Cancelling transmission");
send_stop_condition( bus, timing ); send_stop_condition(bus, timing);
return res; return res;
} }
// timining for 100kHz bus (fractional parts are rounded up)
i2c_timing i2c_timing_100k = //! Timining for 100kHz bus (fractional parts are rounded up)
{ i2c_timing i2c_timing_100k = {
buf : 5, buf : 5,
hd_sta : 4, hd_sta : 4,
low : 5, low : 5,
@@ -390,8 +414,7 @@ i2c_timing i2c_timing_100k =
// timing for 400 kHz bus // timing for 400 kHz bus
// (argh! heavy up-rounding here) // (argh! heavy up-rounding here)
i2c_timing i2c_timing_400k = i2c_timing i2c_timing_400k = {
{
buf : 2, buf : 2,
hd_sta : 1, hd_sta : 1,
low : 2, low : 2,
@@ -411,12 +434,16 @@ i2c_timing i2c_timing_400k =
ack_timeout : 2 ack_timeout : 2
}; };
void i2c_get100k_timing( i2c_timing *timing )
void
i2c_get100k_timing(i2c_timing *timing)
{ {
*timing = i2c_timing_100k; *timing = i2c_timing_100k;
} }
void i2c_get400k_timing( i2c_timing *timing )
void
i2c_get400k_timing(i2c_timing *timing)
{ {
*timing = i2c_timing_400k; *timing = i2c_timing_400k;
} }