1/*
2    File:       CIrDevice.cpp
3
4    Contains:   Generic interface to IR hardware.
5
6*/
7
8#include "CIrDevice.h"
9#include "IrGlue.h"
10#include "IrLAP.h"
11#include "AppleIrDA.h"
12#include "IrDALog.h"
13
14#if (hasTracing > 0 && hasCIrDeviceTracing > 0)
15
16enum IrLogCodes
17{
18    kLogNew = 1,
19    kLogFree,
20    kLogInit,
21    kLogStart,
22    kLogStop,
23
24    kLogChangeSpeed,
25    kLogSetSpeedComplete,
26
27    kLogReadComplete,
28    kLogPacketDropped,
29
30    kLogStartXmit,
31    kLogStartXmitPutBuf,
32    kLogStartXmitCtlBuf,
33    kLogStartXmitCtlSize,
34    kLogStartXmitDataBuf,
35    kLogStartXmitDataSize,
36    kLogStartXmitFrame,
37    kLogStartXmitLength,
38    kLogStartXmitData,
39    kLogTransmitComplete,
40    kLogStartXmitError,
41
42    kLogSetAddress,
43    kLogNotOurAddress,
44
45};
46
47static
48EventTraceCauseDesc IrLogEvents[] = {
49    {kLogNew,                   "IrDevice: new, obj="},
50    {kLogFree,                  "IrDevice: free, obj="},
51    {kLogInit,                  "IrDevice: init, obj="},
52    {kLogStart,                 "IrDevice: start"},
53    {kLogStop,                  "IrDevice: stop"},
54
55    {kLogChangeSpeed,           "IrDevice: change speed, new="},
56    {kLogSetSpeedComplete,      "IrDevice: set speed complete, worked="},
57
58    {kLogReadComplete,          "IrDevice: read complete, len=,data="},
59    {kLogPacketDropped,         "IrDevice: packet dropped.  no read pending from lap"},
60
61    {kLogStartXmit,             "IrDevice: start xmit"},
62    {kLogStartXmitPutBuf,       "IrDevice: xmit put buffer"},
63    {kLogStartXmitCtlBuf,       "IrDevice: xmit ctl buffer"},
64    {kLogStartXmitCtlSize,      "IrDevice: xmit ctl length"},
65    {kLogStartXmitDataBuf,      "IrDevice: xmit data buffer"},
66    {kLogStartXmitDataSize,     "IrDevice: xmit data length"},
67    {kLogStartXmitFrame,        "IrDevice: xmit frame buffer"},
68    {kLogStartXmitLength,       "IrDevice: xmit packet length"},
69    {kLogStartXmitData,         "IrDevice: xmit packet data"},
70    {kLogTransmitComplete,      "IrDevice: transmit complete"},
71    {kLogStartXmitError,        "IrDevice: start xmit logic ERROR. fXmitting="},
72
73    {kLogSetAddress,            "IrDevice: set lap address"},
74    {kLogNotOurAddress,         "IrDevice: not our lap address, in=, our="},
75
76};
77
78#define XTRACE(x, y, z) IrDALogAdd( x, y, (uintptr_t)z & 0xffff, IrLogEvents, true )
79
80#else
81#define XTRACE(x,y,z)((void)0)
82#endif
83
84#define super OSObject
85    OSDefineMetaClassAndStructors(CIrDevice, OSObject);
86
87/*static*/
88CIrDevice *
89CIrDevice::cIrDevice(TIrGlue *irda, AppleIrDASerial *driver)
90{
91    CIrDevice *obj = new CIrDevice;
92    XTRACE(kLogNew, 0, obj);
93    if (obj && !obj->Init(irda, driver)) {
94	obj->release();
95	obj = nil;
96    }
97    return obj;
98}
99
100void
101CIrDevice::free(void)
102{
103    XTRACE(kLogFree, 0, this);
104    super::free();
105}
106
107Boolean
108CIrDevice::Init(TIrGlue *irda, AppleIrDASerial *driver)
109{
110    XTRACE(kLogInit, 0, this);
111
112
113    fIrDA = nil;
114    fDriver = nil;
115    fGetBuffer = nil;
116    bzero(&fIrStatus, sizeof(fIrStatus));
117    fLAPAddr = 0;
118    fSpeed = 0;
119    fBofs = 0;
120    fXmitting = false;                  // true if in middle of xmit
121
122    if (!super::init()) return false;
123
124    fIrDA = irda;
125    fDriver = driver;
126
127    ResetStats();
128    return true;
129}
130
131void
132CIrDevice::Start(void)
133{
134    XTRACE(kLogStart, 0, 0);
135    ChangeSpeed(9600);  // set to default speed
136}
137
138void
139CIrDevice::Stop(void)
140{
141    XTRACE(kLogStop, 0, 0);
142
143    fDriver = nil;
144}
145
146void
147CIrDevice::SetLAPAddress(UInt8 addr)            // Set our LAP address
148{
149    XTRACE(kLogSetAddress, 0, addr);
150    fLAPAddr = addr;
151}
152
153
154//--------------------------------------------------------------------------------
155//      ValidFrameAddress
156//
157// Check the lap address field for either broadcast, or our address
158//--------------------------------------------------------------------------------
159Boolean
160CIrDevice::ValidFrameAddress(UInt8 aField)
161{
162    Boolean rc =  ((aField >> 1) == kIrLAPBroadcastAddr) || ((aField >> 1) == fLAPAddr);
163    if (!rc) {
164	XTRACE(kLogNotOurAddress, aField, fLAPAddr);
165    }
166    return rc;
167}
168
169//--------------------------------------------------------------------------------
170//      ChangeSpeed
171//--------------------------------------------------------------------------------
172IrDAErr CIrDevice::ChangeSpeed(unsigned long bps)
173{
174    XTRACE(kLogChangeSpeed, bps >> 16, bps);
175    require(fDriver, Fail);
176    check(fXmitting == false);
177
178    if (bps != fSpeed) {
179	(void) fDriver->SetSpeed(bps);      // start the speed change sequence
180	fSpeed = bps;
181    }
182
183    /***
184    if (1) {        // doing this right again finally
185	TIrLAP *lap;
186	require(fIrDA, Fail);
187	lap = fIrDA->GetLAP();
188	require(lap, Fail);
189	lap->ChangeSpeedComplete();     // finally tell lap that the speed change finished
190    }
191    ***/
192    return noErr;
193
194Fail:
195    return kIrDAErrWrongState;
196
197} // CIrDevice::ChangeSpeed
198
199void
200CIrDevice::SetSpeedComplete(Boolean worked)
201{
202    TIrLAP *lap;
203    XTRACE(kLogSetSpeedComplete, 0, worked);
204    require(fIrDA, Fail);
205    lap = fIrDA->GetLAP();
206    require(lap, Fail);
207    lap->ChangeSpeedComplete();
208
209Fail:
210    return;
211}
212
213//--------------------------------------------------------------------------------
214//      GetMediaBusy
215//--------------------------------------------------------------------------------
216Boolean CIrDevice::GetMediaBusy(void)
217{
218    // return fDevice->GetMediaBusy();
219    return false;
220}
221
222//--------------------------------------------------------------------------------
223//      ResetMediaBusy
224//--------------------------------------------------------------------------------
225void CIrDevice::ResetMediaBusy(void)
226{
227    // fDevice->ResetMediaBusy();
228    return;
229}
230
231//--------------------------------------------------------------------------------
232//      StartReceive
233//--------------------------------------------------------------------------------
234void CIrDevice::StartReceive(CBufferSegment* inputBuffer)
235{
236//  check(fGetBuffer == nil);       // see if a read is "pending" already
237    fGetBuffer = inputBuffer;
238}
239
240//--------------------------------------------------------------------------------
241//      StopReceive
242//--------------------------------------------------------------------------------
243void CIrDevice::StopReceive(void)
244{
245    //check(fGetBuffer != nil);     // this happens
246    fGetBuffer = nil;
247}
248
249//--------------------------------------------------------------------------------
250//      ReadComplete
251//--------------------------------------------------------------------------------
252void CIrDevice::ReadComplete(UInt8 *buffer, UInt32 length)
253{
254    XTRACE(kLogReadComplete, 0, length);
255    UByte aField, cField;
256
257    // if debugging really high, log data bytes too
258#if (hasTracing > 0 && hasCIrDeviceTracing > 1)
259    {
260	int len = length;
261	UInt32 w;
262	UInt8 *b = buffer;
263	int i;
264
265	while (len > 0) {
266	    w = 0;
267	    for (i = 0 ; i < 4; i++) {
268		w = w << 8;
269		if (len > 0)            // don't run off end (pad w/zeros)
270		    w = w | *b;
271		b++;
272		len--;
273	    }
274	    XTRACE(kLogReadComplete, w >> 16, w);
275	}
276    }
277
278#endif // hasCIrDeviceTracing > 1
279
280    // test for data recvd but LAP doesn't have a read pending
281    if (fGetBuffer == nil) {
282	XTRACE(kLogPacketDropped, 0, 0);
283	Stats_PacketDropped();              // different bucket for invalid sequence vs. this?
284	return;
285    }
286
287    require(length >= 2, Fail);
288
289    aField = buffer[0];
290    cField = buffer[1];
291    length -= 2;
292    buffer += 2;
293
294    if (length > 0) {
295	fGetBuffer->Putn(buffer, length);       // copy to CBufferSegment
296	fGetBuffer->Hide(fGetBuffer->GetSize() - fGetBuffer->Position(), kPosEnd);
297	// Seek to beginning of the buffer for our client
298	fGetBuffer->Seek(0, kPosBeg);
299    }
300
301    if (ValidFrameAddress(aField)) {                        // if packet addressed to us
302	Stats_DataPacketIn();
303	fGetBuffer = nil;                                   // read is done, clear our "read pending" flag
304	fIrDA->GetLAP()->InputComplete(aField,cField);      // then let LAP know about it (already owns "fGetBuffer")
305    }
306    else {
307	//int review_media_busy_logic;
308    //  fMediaBusy = true;                                  // else did we just saw someone else's traffic?
309	Stats_PacketDropped();                              // different counters?
310    }
311Fail:
312    return;
313
314} // CIrDevice::ReadComplete
315
316//--------------------------------------------------------------------------------
317//      StartTransmit
318//--------------------------------------------------------------------------------
319void CIrDevice::StartTransmit(TIrLAPPutBuffer* outputBuffer, ULong leadInCount)
320{
321    UByte   *ctlBuffer;
322    UByte   *dataBuffer;
323    int     ctlSize;
324    int     dataSize;
325    IOReturn    ior;
326
327    require(fDriver, Fail);
328    require(outputBuffer, Fail);
329    require(fXmitting == false, Fail);
330
331    fXmitting = true;
332
333    if (fBofs != leadInCount) {
334	fDriver->SetBofCount(leadInCount);      // cache and call only if different?
335	fBofs = leadInCount;
336    }
337
338    XTRACE(kLogStartXmitPutBuf, 0, outputBuffer);
339
340    ctlBuffer  = outputBuffer->GetCtrlBuffer();
341    XTRACE(kLogStartXmitCtlBuf, 0, ctlBuffer);
342
343    ctlSize    = outputBuffer->GetCtrlSize();
344    XTRACE(kLogStartXmitCtlSize, 0, ctlSize);
345
346    dataBuffer = outputBuffer->GetDataBuffer();
347    XTRACE(kLogStartXmitDataBuf, 0, dataBuffer);
348
349    dataSize   = outputBuffer->GetDataSize();
350    XTRACE(kLogStartXmitDataSize, (int)dataSize >> 16, dataSize);
351
352    //require(ctlSize + dataSize <= LapLength, Fail);
353
354#if (hasTracing > 0 && hasCIrDeviceTracing > 1)
355    if (1) {
356	int len = ctlSize + dataSize;   // dump control and data buffers
357	UInt32 w;
358	UInt8 *b = ctlBuffer;           // start with control buffer, then switch to data buffer
359	int i;
360
361	XTRACE(kLogStartXmitLength, len >> 16, len);
362
363	require(len > 0 && ctlSize > 0 && ctlBuffer != nil, Fail);  // sanity (assumes non-empty ctlbuffer)
364
365	while (len > 0) {               // loop over the packet
366	    w = 0;                      // logging 4 bytes at a time
367	    for (i = 0 ; i < 4; i++) {
368		w = w << 8;
369		if (len > 0)            // don't run off end (pad w/zeros)
370		    w = w | *b;
371		b++;
372		if (b == &ctlBuffer[ctlSize])   // if just incr'd past end of control buffer
373		    b = dataBuffer;             //  then switch to data buffer
374		len--;
375	    }
376	    XTRACE(kLogStartXmitData, w >> 16, w);
377	}
378    }
379#endif // hasCIrDeviceTracing > 1
380
381    // start the transmit
382    ior = fDriver->StartTransmit(ctlSize, ctlBuffer, dataSize, dataBuffer);
383    if (ior != kIOReturnSuccess) {
384	XTRACE(kLogStartXmitError, ior >> 16, ior);
385	TransmitComplete(false);
386	return;
387    }
388    XTRACE(kLogStartXmitData, 0xffff, 0xffff);
389    return;
390
391Fail:
392    XTRACE(kLogStartXmitError, 0, fXmitting);
393    return;
394}
395
396void CIrDevice::TransmitComplete(Boolean worked)
397{
398    TIrLAP *lap;
399
400    XTRACE(kLogTransmitComplete, 0, worked);
401    check(fXmitting);
402
403    fXmitting = false;
404    require(fIrDA, Fail);
405
406    lap = fIrDA->GetLAP();
407    require(lap, Fail);
408    Stats_DataPacketOut();
409
410    lap->OutputComplete();      // what to do if the write failed?
411
412Fail:
413    return;
414}
415
416//--------------------------------------------------------------------------------
417//      ResetStats
418//--------------------------------------------------------------------------------
419void CIrDevice::ResetStats()
420{
421    bzero(&fIrStatus, sizeof(fIrStatus));
422}
423