- Now splits paragraphs into multiple lines, with each line fitting the
[AROS.git] / workbench / hidds / hidd.i2c / i2cclass.c
blob969e86dacbe09fc39ebaf295767765a96c87b823
1 /*
2 Copyright � 2004-2006, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <exec/types.h>
7 #include <hidd/hidd.h>
8 #include <hidd/i2c.h>
9 #include <oop/oop.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>
21 #include "i2c.h"
23 #define DEBUG 0
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);
55 int i;
56 BOOL scl;
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);
64 if (scl) break;
65 I2C_UDelay(drv, drv->RiseFallTime);
68 if (i <= 0)
70 bug("[I2C] RaiseSCL(<%s>,%d,%d) timeout\n", drv->name, sda, timeout);
71 return FALSE;
74 return TRUE;
77 static BOOL WriteBit(OOP_Class *cl, OOP_Object *o, BOOL sda, ULONG timeout)
79 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
81 BOOL r;
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);
92 return r;
95 static BOOL ReadBit(OOP_Class *cl, OOP_Object *o, BOOL *sda, ULONG timeout)
97 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
99 BOOL scl, r;
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);
109 return r;
112 /*** Hidd::I2C */
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);
128 LOCK_HW
130 if (!RaiseSCL(cl, o, 1, msg->timeout)) {
131 UNLOCK_HW
132 return FALSE;
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]: <"));
142 UNLOCK_HW
144 return TRUE;
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);
152 LOCK_HW
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) {
158 UNLOCK_HW;
159 return TRUE;
162 if (I2C_PutByte(o, msg->device, (msg->address >> 8) & 0xFF)) {
163 UNLOCK_HW;
164 return TRUE;
168 I2C_Stop(o, msg->device);
171 UNLOCK_HW
173 return FALSE;
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" },
184 { TAG_DONE, 0UL }
187 BOOL r = FALSE;
189 D(bug("[I2C] I2C::ProbeAddress(%04x)\n", msg->address));
191 LOCK_HW
193 OOP_Object *probing = OOP_NewObject(SD(cl)->i2cDeviceClass, NULL, attrs);
195 if (probing)
197 r = I2C_Address(o, probing, msg->address);
198 if (r)
199 I2C_Stop(o, probing);
201 OOP_DisposeObject(probing);
204 UNLOCK_HW
206 return r;
210 void METHOD(I2C, Hidd_I2C, Stop)
212 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
214 LOCK_HW
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);
224 D(bug(">\n"));
226 UNLOCK_HW
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);
234 BOOL r, scl, sda;
235 int i;
237 LOCK_HW
239 if (!WriteBit(cl, o, (msg->data >> 7) & 1, dev->ByteTimeout))
241 UNLOCK_HW
242 return FALSE;
245 for (i = 6; i >= 0; i--)
246 if (!WriteBit(cl, o, (msg->data >> i) & 1, dev->BitTimeout))
248 UNLOCK_HW
249 return FALSE;
252 I2C_PutBits(o, 0, 1);
253 I2C_UDelay(drv, drv->RiseFallTime);
255 r = RaiseSCL(cl, o, 1, drv->HoldTime);
257 if (r)
259 for (i = dev->AcknTimeout; i > 0; i -= drv->HoldTime)
261 I2C_UDelay(drv, drv->HoldTime);
262 I2C_GetBits(o, &scl, &sda);
263 if (sda == 0) break;
266 if (i <= 0) {
267 D(bug("[I2C] PutByte(<%s>, 0x%02x, %d, %d, %d) timeout",
268 drv->name, msg->data, dev->BitTimeout,
269 dev->ByteTimeout, dev->AcknTimeout));
270 r = FALSE;
273 D(bug("W%02x%c ", (int) msg->data, sda ? '-' : '+'));
276 I2C_PutBits(o, 0, 1);
277 I2C_UDelay(drv, drv->HoldTime);
279 UNLOCK_HW
281 return r;
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);
289 int i;
290 BOOL sda;
292 LOCK_HW
294 I2C_PutBits(o, 0, 1);
295 I2C_UDelay(drv, drv->RiseFallTime);
297 if (!ReadBit(cl, o, &sda, dev->ByteTimeout))
299 UNLOCK_HW
300 return FALSE;
304 *msg->data = (sda? 1:0) << 7;
306 for (i = 6; i >= 0; i--)
307 if (!ReadBit(cl, o, &sda, dev->BitTimeout))
309 UNLOCK_HW
310 return FALSE;
312 else
313 *msg->data |= (sda? 1:0) << i;
315 if (!WriteBit(cl, o, msg->last ? 1 : 0, dev->BitTimeout))
317 UNLOCK_HW
318 return FALSE;
321 D(bug("R%02x%c ", (int) *msg->data, msg->last ? '+' : '-'));
323 UNLOCK_HW
325 return TRUE;
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);
333 BOOL r = TRUE;
334 int s = 0;
336 ULONG nWrite = msg->writeLength;
337 UBYTE *WriteBuffer = msg->writeBuffer;
338 ULONG nRead = msg->readLength;
339 UBYTE *ReadBuffer = msg->readBuffer;
341 LOCK_HW
343 if (r && nWrite > 0) {
344 r = I2C_Address(o, msg->device, dev->address & ~1);
345 if (r) {
346 for (; nWrite > 0; WriteBuffer++, nWrite--)
347 if (!(r = I2C_PutByte(o, msg->device, *WriteBuffer)))
348 break;
349 s++;
353 if (r && nRead > 0) {
354 r = I2C_Address(o, msg->device, dev->address | 1);
355 if (r) {
356 for (; nRead > 0; ReadBuffer++, nRead--)
357 if (!(r = I2C_GetByte(o, msg->device, ReadBuffer, nRead == 1)))
358 break;
359 s++;
363 if (s) I2C_Stop(o, msg->device);
365 UNLOCK_HW
367 return r;
370 /*** Root */
372 void METHOD(I2C, Root, Get)
374 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
376 ULONG idx;
378 if (IS_I2C_ATTR(msg->attrID, idx))
380 switch (idx)
382 case aoHidd_I2C_HoldTime:
383 *msg->storage = drv->HoldTime;
384 break;
386 case aoHidd_I2C_BitTimeout:
387 *msg->storage = drv->BitTimeout;
388 break;
390 case aoHidd_I2C_ByteTimeout:
391 *msg->storage = drv->ByteTimeout;
392 break;
394 case aoHidd_I2C_AcknTimeout:
395 *msg->storage = drv->AcknTimeout;
396 break;
398 case aoHidd_I2C_StartTimeout:
399 *msg->storage = drv->StartTimeout;
400 break;
402 case aoHidd_I2C_RiseFallTime:
403 *msg->storage = drv->RiseFallTime;
404 break;
406 case aoHidd_I2C_Name:
407 *msg->storage = (IPTR)drv->name;
408 break;
411 else
413 OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
417 void METHOD(I2C, Root, Set)
419 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
421 ULONG idx;
422 struct TagItem *tag;
423 struct TagItem *tags = msg->attrList;
425 while ((tag = NextTagItem(&tags)))
427 if (IS_I2C_ATTR(tag->ti_Tag, idx))
429 switch (idx)
431 case aoHidd_I2C_HoldTime:
432 drv->HoldTime = tag->ti_Data;
433 break;
435 case aoHidd_I2C_BitTimeout:
436 drv->BitTimeout = tag->ti_Data;
437 break;
439 case aoHidd_I2C_ByteTimeout:
440 drv->ByteTimeout = tag->ti_Data;
441 break;
443 case aoHidd_I2C_AcknTimeout:
444 drv->AcknTimeout = tag->ti_Data;
445 break;
447 case aoHidd_I2C_StartTimeout:
448 drv->StartTimeout = tag->ti_Data;
449 break;
451 case aoHidd_I2C_RiseFallTime:
452 drv->RiseFallTime = tag->ti_Data;
453 break;
459 OOP_Object *METHOD(I2C, Root, New)
461 D(bug("[I2C] new()\n"));
463 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
464 if (o)
466 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
467 struct TagItem *tag, *tags = msg->attrList;
469 drv->HoldTime = 5;
470 drv->AcknTimeout = 5;
471 drv->BitTimeout = 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"));
498 tags=msg->attrList;
500 while((tag = NextTagItem(&tags)))
502 ULONG idx;
504 if (IS_I2C_ATTR(tag->ti_Tag, idx))
506 switch(idx)
508 case aoHidd_I2C_Name:
509 drv->name = (STRPTR)tag->ti_Data;
510 break;
512 case aoHidd_I2C_HoldTime:
513 drv->HoldTime = tag->ti_Data;
514 break;
516 case aoHidd_I2C_BitTimeout:
517 drv->BitTimeout = tag->ti_Data;
518 break;
520 case aoHidd_I2C_ByteTimeout:
521 drv->ByteTimeout = tag->ti_Data;
522 break;
524 case aoHidd_I2C_AcknTimeout:
525 drv->AcknTimeout = tag->ti_Data;
526 break;
528 case aoHidd_I2C_StartTimeout:
529 drv->StartTimeout = tag->ti_Data;
530 break;
532 case aoHidd_I2C_RiseFallTime:
533 drv->RiseFallTime = tag->ti_Data;
534 break;
539 else
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);
544 o = NULL;
549 return o;
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 */
565 //#undef UtilityBase
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);
576 return TRUE;
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"));
590 return TRUE;
593 return FALSE;
596 ADD2INITLIB(I2C_InitClass, 0)
597 ADD2EXPUNGELIB(I2C_ExpungeClass, 0)