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
/ 10000;
43 drv
->tr
.tr_time
.tv_micro
= 10 * (delay
% 10000);
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
)) {
135 I2C_PutBits(o
, 1, 0);
136 I2C_UDelay(drv
, drv
->HoldTime
);
137 I2C_PutBits(o
, 0, 0);
138 I2C_UDelay(drv
, drv
->HoldTime
);
140 D(bug("\n[I2C]: <"));
147 BOOL
METHOD(I2C
, Hidd_I2C
, Address
)
149 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
150 tDevData
*dev
= (tDevData
*)OOP_INST_DATA(SD(cl
)->i2cDeviceClass
, msg
->device
);
154 if (I2C_Start(o
, dev
->StartTimeout
)) {
155 if (I2C_PutByte(o
, msg
->device
, msg
->address
& 0xFF)) {
156 if ((msg
->address
& 0xF8) != 0xF0 &&
157 (msg
->address
& 0xFE) != 0x00) {
162 if (I2C_PutByte(o
, msg
->device
, (msg
->address
>> 8) & 0xFF)) {
168 I2C_Stop(o
, msg
->device
);
176 BOOL
METHOD(I2C
, Hidd_I2C
, ProbeAddress
)
178 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
180 struct TagItem attrs
[] = {
181 { aHidd_I2CDevice_Driver
, (IPTR
)o
},
182 { aHidd_I2CDevice_Address
, msg
->address
},
183 { aHidd_I2CDevice_Name
, (IPTR
)"Probing" },
189 D(bug("[I2C] I2C::ProbeAddress(%04x)\n", msg
->address
));
193 OOP_Object
*probing
= OOP_NewObject(SD(cl
)->i2cDeviceClass
, NULL
, attrs
);
197 r
= I2C_Address(o
, probing
, msg
->address
);
199 I2C_Stop(o
, probing
);
201 OOP_DisposeObject(probing
);
210 void METHOD(I2C
, Hidd_I2C
, Stop
)
212 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
216 I2C_PutBits(o
, 0, 0);
217 I2C_UDelay(drv
, drv
->RiseFallTime
);
219 I2C_PutBits(o
, 1, 0);
220 I2C_UDelay(drv
, drv
->HoldTime
);
221 I2C_PutBits(o
, 1, 1);
222 I2C_UDelay(drv
, drv
->HoldTime
);
229 BOOL
METHOD(I2C
, Hidd_I2C
, PutByte
)
231 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
232 tDevData
*dev
= (tDevData
*)OOP_INST_DATA(SD(cl
)->i2cDeviceClass
, msg
->device
);
239 if (!WriteBit(cl
, o
, (msg
->data
>> 7) & 1, dev
->ByteTimeout
))
245 for (i
= 6; i
>= 0; i
--)
246 if (!WriteBit(cl
, o
, (msg
->data
>> i
) & 1, dev
->BitTimeout
))
252 I2C_PutBits(o
, 0, 1);
253 I2C_UDelay(drv
, drv
->RiseFallTime
);
255 r
= RaiseSCL(cl
, o
, 1, drv
->HoldTime
);
259 for (i
= dev
->AcknTimeout
; i
> 0; i
-= drv
->HoldTime
)
261 I2C_UDelay(drv
, drv
->HoldTime
);
262 I2C_GetBits(o
, &scl
, &sda
);
267 D(bug("[I2C] PutByte(<%s>, 0x%02x, %d, %d, %d) timeout",
268 drv
->name
, msg
->data
, dev
->BitTimeout
,
269 dev
->ByteTimeout
, dev
->AcknTimeout
));
273 D(bug("W%02x%c ", (int) msg
->data
, sda
? '-' : '+'));
276 I2C_PutBits(o
, 0, 1);
277 I2C_UDelay(drv
, drv
->HoldTime
);
284 BOOL
METHOD(I2C
, Hidd_I2C
, GetByte
)
286 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
287 tDevData
*dev
= (tDevData
*)OOP_INST_DATA(SD(cl
)->i2cDeviceClass
, msg
->device
);
294 I2C_PutBits(o
, 0, 1);
295 I2C_UDelay(drv
, drv
->RiseFallTime
);
297 if (!ReadBit(cl
, o
, &sda
, dev
->ByteTimeout
))
304 *msg
->data
= (sda
? 1:0) << 7;
306 for (i
= 6; i
>= 0; i
--)
307 if (!ReadBit(cl
, o
, &sda
, dev
->BitTimeout
))
313 *msg
->data
|= (sda
? 1:0) << i
;
315 if (!WriteBit(cl
, o
, msg
->last
? 1 : 0, dev
->BitTimeout
))
321 D(bug("R%02x%c ", (int) *msg
->data
, msg
->last
? '+' : '-'));
328 BOOL
METHOD(I2C
, Hidd_I2C
, WriteRead
)
330 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
331 tDevData
*dev
= (tDevData
*)OOP_INST_DATA(SD(cl
)->i2cDeviceClass
, msg
->device
);
336 ULONG nWrite
= msg
->writeLength
;
337 UBYTE
*WriteBuffer
= msg
->writeBuffer
;
338 ULONG nRead
= msg
->readLength
;
339 UBYTE
*ReadBuffer
= msg
->readBuffer
;
343 if (r
&& nWrite
> 0) {
344 r
= I2C_Address(o
, msg
->device
, dev
->address
& ~1);
346 for (; nWrite
> 0; WriteBuffer
++, nWrite
--)
347 if (!(r
= I2C_PutByte(o
, msg
->device
, *WriteBuffer
)))
353 if (r
&& nRead
> 0) {
354 r
= I2C_Address(o
, msg
->device
, dev
->address
| 1);
356 for (; nRead
> 0; ReadBuffer
++, nRead
--)
357 if (!(r
= I2C_GetByte(o
, msg
->device
, ReadBuffer
, nRead
== 1)))
363 if (s
) I2C_Stop(o
, msg
->device
);
372 void METHOD(I2C
, Root
, Get
)
374 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
378 if (IS_I2C_ATTR(msg
->attrID
, idx
))
382 case aoHidd_I2C_HoldTime
:
383 *msg
->storage
= drv
->HoldTime
;
386 case aoHidd_I2C_BitTimeout
:
387 *msg
->storage
= drv
->BitTimeout
;
390 case aoHidd_I2C_ByteTimeout
:
391 *msg
->storage
= drv
->ByteTimeout
;
394 case aoHidd_I2C_AcknTimeout
:
395 *msg
->storage
= drv
->AcknTimeout
;
398 case aoHidd_I2C_StartTimeout
:
399 *msg
->storage
= drv
->StartTimeout
;
402 case aoHidd_I2C_RiseFallTime
:
403 *msg
->storage
= drv
->RiseFallTime
;
406 case aoHidd_I2C_Name
:
407 *msg
->storage
= (IPTR
)drv
->name
;
413 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
417 void METHOD(I2C
, Root
, Set
)
419 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
423 struct TagItem
*tags
= msg
->attrList
;
425 while ((tag
= NextTagItem(&tags
)))
427 if (IS_I2C_ATTR(tag
->ti_Tag
, idx
))
431 case aoHidd_I2C_HoldTime
:
432 drv
->HoldTime
= tag
->ti_Data
;
435 case aoHidd_I2C_BitTimeout
:
436 drv
->BitTimeout
= tag
->ti_Data
;
439 case aoHidd_I2C_ByteTimeout
:
440 drv
->ByteTimeout
= tag
->ti_Data
;
443 case aoHidd_I2C_AcknTimeout
:
444 drv
->AcknTimeout
= tag
->ti_Data
;
447 case aoHidd_I2C_StartTimeout
:
448 drv
->StartTimeout
= tag
->ti_Data
;
451 case aoHidd_I2C_RiseFallTime
:
452 drv
->RiseFallTime
= tag
->ti_Data
;
459 OOP_Object
*METHOD(I2C
, Root
, New
)
461 D(bug("[I2C] new()\n"));
463 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
) msg
);
466 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
467 struct TagItem
*tag
, *tags
= msg
->attrList
;
470 drv
->AcknTimeout
= 5;
472 drv
->ByteTimeout
= 5;
473 drv
->RiseFallTime
= 2;
474 drv
->StartTimeout
= 5;
476 drv
->name
= (STRPTR
)"bus?";
478 InitSemaphore(&drv
->driver_lock
);
480 D(bug("[I2C] Initializing MsgPort\n"));
482 /* Initialize MsgPort */
483 drv
->mp
.mp_SigBit
= SIGB_SINGLE
;
484 drv
->mp
.mp_Flags
= PA_SIGNAL
;
485 drv
->mp
.mp_SigTask
= FindTask(NULL
);
486 drv
->mp
.mp_Node
.ln_Type
= NT_MSGPORT
;
487 NEWLIST(&drv
->mp
.mp_MsgList
);
489 drv
->tr
.tr_node
.io_Message
.mn_ReplyPort
= &drv
->mp
;
490 drv
->tr
.tr_node
.io_Message
.mn_Length
= sizeof(drv
->tr
);
492 D(bug("[I2C] Trying to open UNIT_MICROHZ of timer.device\n"));
494 if (!OpenDevice((STRPTR
)"timer.device", UNIT_MICROHZ
, (struct IORequest
*)&drv
->tr
, 0))
496 D(bug("[I2C] Everything OK\n"));
500 while((tag
= NextTagItem(&tags
)))
504 if (IS_I2C_ATTR(tag
->ti_Tag
, idx
))
508 case aoHidd_I2C_Name
:
509 drv
->name
= (STRPTR
)tag
->ti_Data
;
512 case aoHidd_I2C_HoldTime
:
513 drv
->HoldTime
= tag
->ti_Data
;
516 case aoHidd_I2C_BitTimeout
:
517 drv
->BitTimeout
= tag
->ti_Data
;
520 case aoHidd_I2C_ByteTimeout
:
521 drv
->ByteTimeout
= tag
->ti_Data
;
524 case aoHidd_I2C_AcknTimeout
:
525 drv
->AcknTimeout
= tag
->ti_Data
;
528 case aoHidd_I2C_StartTimeout
:
529 drv
->StartTimeout
= tag
->ti_Data
;
532 case aoHidd_I2C_RiseFallTime
:
533 drv
->RiseFallTime
= tag
->ti_Data
;
541 D(bug("[I2C] Opening of timer.device failed\n"));
542 OOP_MethodID disp_mid
= OOP_GetMethodID((STRPTR
)IID_Root
, moRoot_Dispose
);
543 OOP_CoerceMethod(cl
, o
, (OOP_Msg
) &disp_mid
);
552 VOID
METHOD(I2C
, Root
, Dispose
)
554 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
556 D(bug("[I2C] Dispose()\n"));
558 CloseDevice((struct IORequest
*)&drv
->tr
);
560 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
563 /* Class initialization and destruction */
566 //#define UtilityBase (sd->utilitybase)
568 static int I2C_ExpungeClass(LIBBASETYPEPTR LIBBASE
)
570 D(bug("[I2C] Base Class destruction\n"));
572 OOP_ReleaseAttrBase(IID_Hidd_I2CDevice
);
573 OOP_ReleaseAttrBase(IID_Hidd_I2C
);
574 OOP_ReleaseAttrBase(IID_Hidd
);
579 static int I2C_InitClass(LIBBASETYPEPTR LIBBASE
)
581 D(bug("[I2C] base class initialization\n"));
583 LIBBASE
->sd
.hiddI2CAB
= OOP_ObtainAttrBase(IID_Hidd_I2C
);
584 LIBBASE
->sd
.hiddI2CDeviceAB
= OOP_ObtainAttrBase(IID_Hidd_I2CDevice
);
585 LIBBASE
->sd
.hiddAB
= OOP_ObtainAttrBase(IID_Hidd
);
587 if (LIBBASE
->sd
.hiddI2CAB
&& LIBBASE
->sd
.hiddI2CDeviceAB
&& LIBBASE
->sd
.hiddAB
)
589 D(bug("[I2C] Everything OK\n"));
596 ADD2INITLIB(I2C_InitClass
, 0)
597 ADD2EXPUNGELIB(I2C_ExpungeClass
, 0)