2 Copyright © 2004-2006, The AROS Development Team. All rights reserved.
6 #include <exec/types.h>
11 #include <utility/tagitem.h>
12 #include <utility/hooks.h>
13 #include <devices/timer.h>
15 #include <proto/exec.h>
16 #include <proto/utility.h>
17 #include <proto/oop.h>
19 #include <aros/symbolsets.h>
24 #include <aros/debug.h>
25 #include <aros/atomic.h>
28 There are no static AttrBases in this class. Therefore it might be placed
29 directly in ROM without any harm
31 #undef HiddI2CAttrBase
32 #undef HiddI2CDeviceAttrBase
34 #define HiddI2CAttrBase (SD(cl)->hiddI2CAB)
35 #define HiddI2CDeviceAttrBase (SD(cl)->hiddI2CDeviceAB)
36 #define HiddAttrBase (SD(cl)->hiddAB)
38 static void I2C_UDelay(tDrvData
*drv
, ULONG delay
)
40 drv
->mp
.mp_SigTask
= FindTask(NULL
);
41 drv
->tr
.tr_node
.io_Command
= TR_ADDREQUEST
;
42 drv
->tr
.tr_time
.tv_secs
= delay
/ 100000;
43 drv
->tr
.tr_time
.tv_micro
= 10 * (delay
% 100000);
45 DoIO((struct IORequest
*)&drv
->tr
);
47 drv
->mp
.mp_SigTask
= NULL
;
51 static BOOL
RaiseSCL(OOP_Class
*cl
, OOP_Object
*o
, BOOL sda
, ULONG timeout
)
53 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
58 I2C_PutBits(o
, 1, sda
);
59 I2C_UDelay(drv
, drv
->RiseFallTime
);
61 for (i
=timeout
; i
>0; i
-= drv
->RiseFallTime
)
63 I2C_GetBits(o
, &scl
, &sda
);
65 I2C_UDelay(drv
, drv
->RiseFallTime
);
70 bug("[I2C] RaiseSCL(<%s>,%d,%d) timeout\n", drv
->name
, sda
, timeout
);
77 static BOOL
WriteBit(OOP_Class
*cl
, OOP_Object
*o
, BOOL sda
, ULONG timeout
)
79 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
83 I2C_PutBits(o
, 0, sda
);
84 I2C_UDelay(drv
, drv
->RiseFallTime
);
86 r
= RaiseSCL(cl
, o
, sda
, timeout
);
87 I2C_UDelay(drv
, drv
->HoldTime
);
89 I2C_PutBits(o
, 0, sda
);
90 I2C_UDelay(drv
, drv
->HoldTime
);
95 static BOOL
ReadBit(OOP_Class
*cl
, OOP_Object
*o
, BOOL
*sda
, ULONG timeout
)
97 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
101 r
= RaiseSCL(cl
, o
, 1, timeout
);
102 I2C_UDelay(drv
, drv
->HoldTime
);
104 I2C_GetBits(o
, &scl
, sda
);
106 I2C_PutBits(o
, 0, 1);
107 I2C_UDelay(drv
, drv
->HoldTime
);
114 void METHOD(I2C
, Hidd_I2C
, PutBits
)
116 bug("[I2C] Pure virtual method I2C::PutBits() called!!!\n");
119 void METHOD(I2C
, Hidd_I2C
, GetBits
)
121 bug("[I2C] Pure virtual method I2C::GetBits() called!!!\n");
124 BOOL
METHOD(I2C
, Hidd_I2C
, Start
)
126 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
130 if (!RaiseSCL(cl
, o
, 1, msg
->timeout
))
133 I2C_PutBits(o
, 1, 0);
134 I2C_UDelay(drv
, drv
->HoldTime
);
135 I2C_PutBits(o
, 0, 0);
136 I2C_UDelay(drv
, drv
->HoldTime
);
138 D(bug("\n[I2C]: <"));
145 BOOL
METHOD(I2C
, Hidd_I2C
, Address
)
147 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
148 tDevData
*dev
= (tDevData
*)OOP_INST_DATA(SD(cl
)->i2cDeviceClass
, msg
->device
);
152 if (I2C_Start(o
, dev
->StartTimeout
)) {
153 if (I2C_PutByte(o
, msg
->device
, msg
->address
& 0xFF)) {
154 if ((msg
->address
& 0xF8) != 0xF0 &&
155 (msg
->address
& 0xFE) != 0x00)
158 if (I2C_PutByte(o
, msg
->device
, (msg
->address
>> 8) & 0xFF))
162 I2C_Stop(o
, msg
->device
);
170 BOOL
METHOD(I2C
, Hidd_I2C
, ProbeAddress
)
172 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
174 struct TagItem attrs
[] = {
175 { aHidd_I2CDevice_Driver
, (IPTR
)o
},
176 { aHidd_I2CDevice_Address
, msg
->address
},
177 { aHidd_I2CDevice_Name
, (IPTR
)"Probing" },
183 D(bug("[I2C] I2C::ProbeAddress(%04x)\n", msg
->address
));
187 OOP_Object
*probing
= OOP_NewObject(SD(cl
)->i2cDeviceClass
, NULL
, attrs
);
191 r
= I2C_Address(o
, probing
, msg
->address
);
193 I2C_Stop(o
, probing
);
195 OOP_DisposeObject(probing
);
204 void METHOD(I2C
, Hidd_I2C
, Stop
)
206 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
210 I2C_PutBits(o
, 0, 0);
211 I2C_UDelay(drv
, drv
->RiseFallTime
);
213 I2C_PutBits(o
, 1, 0);
214 I2C_UDelay(drv
, drv
->HoldTime
);
215 I2C_PutBits(o
, 1, 1);
216 I2C_UDelay(drv
, drv
->HoldTime
);
223 BOOL
METHOD(I2C
, Hidd_I2C
, PutByte
)
225 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
226 tDevData
*dev
= (tDevData
*)OOP_INST_DATA(SD(cl
)->i2cDeviceClass
, msg
->device
);
233 if (!WriteBit(cl
, o
, (msg
->data
>> 7) & 1, dev
->ByteTimeout
))
239 for (i
= 6; i
>= 0; i
--)
240 if (!WriteBit(cl
, o
, (msg
->data
>> i
) & 1, dev
->BitTimeout
))
246 I2C_PutBits(o
, 0, 1);
247 I2C_UDelay(drv
, drv
->RiseFallTime
);
249 r
= RaiseSCL(cl
, o
, 1, drv
->HoldTime
);
253 for (i
= dev
->AcknTimeout
; i
> 0; i
-= drv
->HoldTime
)
255 I2C_UDelay(drv
, drv
->HoldTime
);
256 I2C_GetBits(o
, &scl
, &sda
);
261 bug("[I2C] PutByte(<%s>, 0x%02x, %d, %d, %d) timeout",
262 drv
->name
, msg
->data
, dev
->BitTimeout
,
263 dev
->ByteTimeout
, dev
->AcknTimeout
);
267 D(bug("W%02x%c ", (int) msg
->data
, sda
? '-' : '+'));
270 I2C_PutBits(o
, 0, 1);
271 I2C_UDelay(drv
, drv
->HoldTime
);
278 BOOL
METHOD(I2C
, Hidd_I2C
, GetByte
)
280 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
281 tDevData
*dev
= (tDevData
*)OOP_INST_DATA(SD(cl
)->i2cDeviceClass
, msg
->device
);
288 I2C_PutBits(o
, 0, 1);
289 I2C_UDelay(drv
, drv
->RiseFallTime
);
291 if (!ReadBit(cl
, o
, &sda
, dev
->ByteTimeout
))
298 *msg
->data
= (sda
? 1:0) << 7;
300 for (i
= 6; i
>= 0; i
--)
301 if (!ReadBit(cl
, o
, &sda
, dev
->BitTimeout
))
307 *msg
->data
|= (sda
? 1:0) << i
;
309 if (!WriteBit(cl
, o
, msg
->last
? 1 : 0, dev
->BitTimeout
))
315 D(bug("R%02x%c ", (int) *msg
->data
, msg
->last
? '+' : '-'));
322 BOOL
METHOD(I2C
, Hidd_I2C
, WriteRead
)
324 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
325 tDevData
*dev
= (tDevData
*)OOP_INST_DATA(SD(cl
)->i2cDeviceClass
, msg
->device
);
330 ULONG nWrite
= msg
->writeLength
;
331 UBYTE
*WriteBuffer
= msg
->writeBuffer
;
332 ULONG nRead
= msg
->readLength
;
333 UBYTE
*ReadBuffer
= msg
->readBuffer
;
337 if (r
&& nWrite
> 0) {
338 r
= I2C_Address(o
, msg
->device
, dev
->address
& ~1);
340 for (; nWrite
> 0; WriteBuffer
++, nWrite
--)
341 if (!(r
= I2C_PutByte(o
, msg
->device
, *WriteBuffer
)))
347 if (r
&& nRead
> 0) {
348 r
= I2C_Address(o
, msg
->device
, dev
->address
| 1);
350 for (; nRead
> 0; ReadBuffer
++, nRead
--)
351 if (!(r
= I2C_GetByte(o
, msg
->device
, ReadBuffer
, nRead
== 1)))
357 if (s
) I2C_Stop(o
, msg
->device
);
366 void METHOD(I2C
, Root
, Get
)
368 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
372 if (IS_I2C_ATTR(msg
->attrID
, idx
))
376 case aoHidd_I2C_HoldTime
:
377 *msg
->storage
= drv
->HoldTime
;
380 case aoHidd_I2C_BitTimeout
:
381 *msg
->storage
= drv
->BitTimeout
;
384 case aoHidd_I2C_ByteTimeout
:
385 *msg
->storage
= drv
->ByteTimeout
;
388 case aoHidd_I2C_AcknTimeout
:
389 *msg
->storage
= drv
->AcknTimeout
;
392 case aoHidd_I2C_StartTimeout
:
393 *msg
->storage
= drv
->StartTimeout
;
396 case aoHidd_I2C_RiseFallTime
:
397 *msg
->storage
= drv
->RiseFallTime
;
400 case aoHidd_I2C_Name
:
401 *msg
->storage
= (IPTR
)drv
->name
;
407 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
411 void METHOD(I2C
, Root
, Set
)
413 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
417 const struct TagItem
*tags
= msg
->attrList
;
419 while ((tag
= NextTagItem(&tags
)))
421 if (IS_I2C_ATTR(tag
->ti_Tag
, idx
))
425 case aoHidd_I2C_HoldTime
:
426 drv
->HoldTime
= tag
->ti_Data
;
429 case aoHidd_I2C_BitTimeout
:
430 drv
->BitTimeout
= tag
->ti_Data
;
433 case aoHidd_I2C_ByteTimeout
:
434 drv
->ByteTimeout
= tag
->ti_Data
;
437 case aoHidd_I2C_AcknTimeout
:
438 drv
->AcknTimeout
= tag
->ti_Data
;
441 case aoHidd_I2C_StartTimeout
:
442 drv
->StartTimeout
= tag
->ti_Data
;
445 case aoHidd_I2C_RiseFallTime
:
446 drv
->RiseFallTime
= tag
->ti_Data
;
453 OOP_Object
*METHOD(I2C
, Root
, New
)
455 D(bug("[I2C] new()\n"));
457 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
) msg
);
460 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
462 const struct TagItem
*tags
= msg
->attrList
;
465 drv
->AcknTimeout
= 5;
467 drv
->ByteTimeout
= 5;
468 drv
->RiseFallTime
= 2;
469 drv
->StartTimeout
= 5;
471 drv
->name
= (STRPTR
)"bus?";
473 InitSemaphore(&drv
->driver_lock
);
475 D(bug("[I2C] Initializing MsgPort\n"));
477 /* Initialize MsgPort */
478 drv
->mp
.mp_SigBit
= SIGB_SINGLE
;
479 drv
->mp
.mp_Flags
= PA_SIGNAL
;
480 drv
->mp
.mp_SigTask
= FindTask(NULL
);
481 drv
->mp
.mp_Node
.ln_Type
= NT_MSGPORT
;
482 NEWLIST(&drv
->mp
.mp_MsgList
);
484 drv
->tr
.tr_node
.io_Message
.mn_ReplyPort
= &drv
->mp
;
485 drv
->tr
.tr_node
.io_Message
.mn_Length
= sizeof(drv
->tr
);
487 D(bug("[I2C] Trying to open UNIT_MICROHZ of timer.device\n"));
489 if (!OpenDevice((STRPTR
)"timer.device", UNIT_MICROHZ
, (struct IORequest
*)&drv
->tr
, 0))
491 D(bug("[I2C] Everything OK\n"));
495 while((tag
= NextTagItem(&tags
)))
499 if (IS_I2C_ATTR(tag
->ti_Tag
, idx
))
503 case aoHidd_I2C_Name
:
504 drv
->name
= (STRPTR
)tag
->ti_Data
;
507 case aoHidd_I2C_HoldTime
:
508 drv
->HoldTime
= tag
->ti_Data
;
511 case aoHidd_I2C_BitTimeout
:
512 drv
->BitTimeout
= tag
->ti_Data
;
515 case aoHidd_I2C_ByteTimeout
:
516 drv
->ByteTimeout
= tag
->ti_Data
;
519 case aoHidd_I2C_AcknTimeout
:
520 drv
->AcknTimeout
= tag
->ti_Data
;
523 case aoHidd_I2C_StartTimeout
:
524 drv
->StartTimeout
= tag
->ti_Data
;
527 case aoHidd_I2C_RiseFallTime
:
528 drv
->RiseFallTime
= tag
->ti_Data
;
536 D(bug("[I2C] Opening of timer.device failed\n"));
537 OOP_MethodID disp_mid
= OOP_GetMethodID((STRPTR
)IID_Root
, moRoot_Dispose
);
538 OOP_CoerceMethod(cl
, o
, (OOP_Msg
) &disp_mid
);
548 /* Class initialization and destruction */
551 //#define UtilityBase (sd->utilitybase)
553 static int I2C_ExpungeClass(LIBBASETYPEPTR LIBBASE
)
555 D(bug("[I2C] Base Class destruction\n"));
557 OOP_ReleaseAttrBase((STRPTR
)IID_Hidd_I2C
);
558 OOP_ReleaseAttrBase((STRPTR
)IID_Hidd_I2C
);
559 OOP_ReleaseAttrBase((STRPTR
)IID_Hidd
);
564 static int I2C_InitClass(LIBBASETYPEPTR LIBBASE
)
566 D(bug("[I2C] base class initialization\n"));
568 LIBBASE
->sd
.hiddI2CAB
= OOP_ObtainAttrBase((STRPTR
)IID_Hidd_I2C
);
569 LIBBASE
->sd
.hiddI2CDeviceAB
= OOP_ObtainAttrBase((STRPTR
)IID_Hidd_I2CDevice
);
570 LIBBASE
->sd
.hiddAB
= OOP_ObtainAttrBase((STRPTR
)IID_Hidd
);
572 if (LIBBASE
->sd
.hiddI2CAB
&& LIBBASE
->sd
.hiddI2CDeviceAB
&& LIBBASE
->sd
.hiddAB
)
574 D(bug("[I2C] Everything OK\n"));
581 ADD2INITLIB(I2C_InitClass
, 0)
582 ADD2EXPUNGELIB(I2C_ExpungeClass
, 0)