source: svn/trunk/newcon3bcm2_21bu/nexus/modules/keypad/7552/src/nexus_keypad.c

Last change on this file was 2, checked in by jglee, 11 years ago

first commit

  • Property svn:executable set to *
File size: 13.7 KB
Line 
1/***************************************************************************
2 *     (c)2007-2011 Broadcom Corporation
3 *
4 *  This program is the proprietary software of Broadcom Corporation and/or its licensors,
5 *  and may only be used, duplicated, modified or distributed pursuant to the terms and
6 *  conditions of a separate, written license agreement executed between you and Broadcom
7 *  (an "Authorized License").  Except as set forth in an Authorized License, Broadcom grants
8 *  no license (express or implied), right to use, or waiver of any kind with respect to the
9 *  Software, and Broadcom expressly reserves all rights in and to the Software and all
10 *  intellectual property rights therein.  IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU
11 *  HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY
12 *  NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE.
13 *
14 *  Except as expressly set forth in the Authorized License,
15 *
16 *  1.     This program, including its structure, sequence and organization, constitutes the valuable trade
17 *  secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof,
18 *  and to use this information only in connection with your use of Broadcom integrated circuit products.
19 *
20 *  2.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
21 *  AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR
22 *  WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
23 *  THE SOFTWARE.  BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES
24 *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE,
25 *  LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION
26 *  OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF
27 *  USE OR PERFORMANCE OF THE SOFTWARE.
28 *
29 *  3.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS
30 *  LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR
31 *  EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR
32 *  USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF
33 *  THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT
34 *  ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
35 *  LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF
36 *  ANY LIMITED REMEDY.
37 *
38 * $brcm_Workfile: nexus_keypad.c $
39 * $brcm_Revision: 16 $
40 * $brcm_Date: 3/28/11 3:45p $
41 *
42 * Module Description:
43 *
44 * Revision History:
45 *
46 * $brcm_Log: /nexus/modules/keypad/7400/src/nexus_keypad.c $
47 *
48 * 16   3/28/11 3:45p vsilyaev
49 * SW7335-1214: Added NEXUS_CallbackHandler framework
50 *
51 * 15   12/27/10 4:17p erickson
52 * SW7342-325: unhook from gpio when keypad is closed
53 *
54 * 14   5/13/10 3:21p mward
55 * SW7125-141: Eliminated unnecessary and incorrect read of unitialized
56 *  "repeat" value in keypad detection.
57 *
58 * 13   5/11/10 5:05p jtna
59 * SW7125-307: Coverity - check for null pointer arguments before
60 *  dereferencing them
61 *
62 * 12   12/17/09 9:47a mward
63 * SW7125-141:  Fix compile error if !NEXUS_HAS_SPI.
64 *
65 * 11   12/16/09 12:05p mward
66 * SW7125-141: Detect when a keypad is not connected and fail to open.
67 *
68 * 10   11/18/09 2:07p gmohile
69 * SW7408-1 : Use NEXUS_HAS_SPI for spi frontend
70 *
71 * 9   4/9/09 11:30a jrubio
72 * PR52188: add support for 2nd Receiver
73 *
74 * 8   1/26/09 1:54p erickson
75 * PR51468: global variable naming convention
76 *
77 * 7   7/21/08 2:54p erickson
78 * PR37942: add repeat detection logic
79 *
80 * 6   4/11/08 9:53a erickson
81 * PR41246: convert BDBG_OBJECT_UNSET to BDBG_OBJECT_DESTROY if freeing
82 *  memory
83 *
84 * 5   3/31/08 12:33p erickson
85 * PR41073: check result of malloc and fail graciously
86 *
87 * 4   3/25/08 6:13p erickson
88 * PR40928: reorder for Close
89 *
90 * 3   3/8/08 7:29a erickson
91 * PR40103: convert to NEXUS_TaskCallback
92 *
93 * 2   1/25/08 10:42a erickson
94 * PR39016: impl 740x Keypad
95 *
96 * 1   1/18/08 2:22p jgarrett
97 * PR 38808: Merging to main branch
98 *
99 * Nexus_Devel/3   11/30/07 11:49a jgarrett
100 * PR 37423: Removing warnings
101 *
102 * Nexus_Devel/2   11/21/07 11:12a erickson
103 * PR37423: update
104 *
105 * Nexus_Devel/1   11/20/07 5:55p erickson
106 * PR37423: added module for ir_blaster, keypad and uhf_input
107 *
108 **************************************************************************/
109#include "nexus_keypad_module.h"
110#include "priv/nexus_core.h"
111#include "bkpd.h"
112
113BDBG_MODULE(nexus_keypad);
114
115NEXUS_ModuleHandle g_NEXUS_keypadModule;
116struct {
117    NEXUS_KeypadModuleSettings settings;
118} g_NEXUS_keypad;
119
120/****************************************
121* Module functions
122***************/
123
124void NEXUS_KeypadModule_GetDefaultSettings(NEXUS_KeypadModuleSettings *pSettings)
125{
126    BKNI_Memset(pSettings, 0, sizeof(*pSettings));
127}
128
129NEXUS_ModuleHandle NEXUS_KeypadModule_Init(const NEXUS_KeypadModuleSettings *pSettings)
130{
131    BDBG_ASSERT(!g_NEXUS_keypadModule);
132    g_NEXUS_keypadModule = NEXUS_Module_Create("keypad", NULL);
133    if (pSettings) {
134        g_NEXUS_keypad.settings = *pSettings;
135    }
136    else {
137        NEXUS_KeypadModule_GetDefaultSettings(&g_NEXUS_keypad.settings);
138    }
139    return g_NEXUS_keypadModule;
140}
141
142void NEXUS_KeypadModule_Uninit()
143{
144    NEXUS_Module_Destroy(g_NEXUS_keypadModule);
145    g_NEXUS_keypadModule = NULL;
146}
147
148/****************************************
149* API functions
150***************/
151
152BDBG_OBJECT_ID(NEXUS_Keypad);
153
154
155struct NEXUS_Keypad {
156    BDBG_OBJECT(NEXUS_Keypad)
157    NEXUS_KeypadSettings settings;
158    BKPD_Handle kpd;
159    NEXUS_EventCallbackHandle eventHandler;
160    bool overflow;
161    NEXUS_KeypadEvent *queue;
162    unsigned rptr, wptr;
163    NEXUS_TaskCallbackHandle dataReadyCallback;
164    uint32_t lastCode;
165    NEXUS_Time lastTime;
166#if NEXUS_HAS_SPI
167    NEXUS_CallbackHandler spiInterrupt;
168#endif
169};
170
171void NEXUS_Keypad_GetDefaultSettings(NEXUS_KeypadSettings *pSettings)
172{
173    BKNI_Memset(pSettings, 0, sizeof(*pSettings));
174    pSettings->eventQueueSize = 10;
175    pSettings->prescale = 0x0055; /* taken from KPD PI default */
176    pSettings->debounce = 0x40; /* taken from KPD PI default */
177    pSettings->repeatFilterTime = 200;
178}
179
180#if NEXUS_HAS_SPI
181/* This is the low-level SPI read */
182static BERR_Code NEXUS_Keypad_P_ReadOne( uint16_t *data)
183{
184    uint8_t wData[32], rData[32];
185    BERR_Code rc;
186
187    wData[0] = 0;   /* Chip address is zero */
188    wData[1] = 0xff;
189
190    rc = NEXUS_Spi_Read(g_NEXUS_keypad.settings.spi, &wData[0], &rData[0], 2);
191    if (!rc) {
192        *data = rData[1];
193    }
194    return rc;
195}
196
197/* This is the high-level debounced read */
198static BERR_Code NEXUS_Keypad_P_Read(uint16_t *pData)
199{
200    BERR_Code rc;
201    uint16_t val[2];
202
203    rc = NEXUS_Keypad_P_ReadOne(&val[0]);
204    if (rc) return BERR_TRACE(rc);
205    BKNI_Sleep(10); /* debouncing */
206
207    rc = NEXUS_Keypad_P_ReadOne( &val[1]);
208    if (rc) return BERR_TRACE(rc);
209    BKNI_Sleep(100); /* debouncing */
210
211    if (val[0] == val[1]) {
212        *pData = val[0];
213        rc = 0;
214    }
215    else {
216        BDBG_MSG(("debounce rejected keys %x, %x", val[0], val[1]));
217        rc = -1;
218    }
219
220    return rc;
221}
222
223
224static void NEXUS_Keypad_P_DataReady_spi(void *context)
225{
226    BERR_Code rc;
227    NEXUS_KeypadHandle keypad = (NEXUS_KeypadHandle)context;
228    NEXUS_KeypadEvent event;
229    NEXUS_Time currentTime;
230
231    event.code = 0;
232
233    BDBG_OBJECT_ASSERT(keypad, NEXUS_Keypad);
234
235    rc = NEXUS_Keypad_P_Read( &event.code);
236    /* After reading, re-enable interrupt */
237    NEXUS_Gpio_ClearInterrupt(g_NEXUS_keypad.settings.gpio);
238    if (rc) {
239        /* no error message. a debounced key will return non-zero, and this is normal */
240        goto done;
241    }
242
243    NEXUS_Time_Get(&currentTime);
244
245    event.repeat =  (keypad->lastCode == event.code && NEXUS_Time_Diff(&currentTime, &keypad->lastTime) < (int)keypad->settings.repeatFilterTime);
246    keypad->lastTime = currentTime;
247    keypad->lastCode = event.code;
248
249    BDBG_MSG(("DataReady: %x%s", event.code, event.repeat?" (repeat)":""));
250
251    keypad->queue[keypad->wptr++] = event;
252    if (keypad->wptr == keypad->settings.eventQueueSize) {
253        keypad->wptr = 0;
254    }
255
256    /* if we add an element and the queue is now empty, we have overflowed. */
257    if (keypad->rptr == keypad->wptr) {
258        keypad->overflow = true;
259    }
260
261    NEXUS_TaskCallback_Fire(keypad->dataReadyCallback);
262done:
263    return;
264}
265#endif
266
267void NEXUS_Keypad_P_DataReady(void *context)
268{
269    BERR_Code rc;
270    NEXUS_KeypadHandle keypad = (NEXUS_KeypadHandle)context;
271    NEXUS_KeypadEvent event;
272    NEXUS_Time time;
273
274    rc = BKPD_Read(keypad->kpd, &event.code);
275    if (rc) BERR_TRACE(rc);
276
277    NEXUS_Time_Get(&time);
278    event.repeat = (keypad->lastCode == event.code) && (unsigned)NEXUS_Time_Diff(&time, &keypad->lastTime) < keypad->settings.repeatFilterTime;
279    keypad->lastTime = time;
280    keypad->lastCode = event.code;
281
282    BDBG_MSG(("NEXUS_Keypad_P_DataReady %x %s", event.code, event.repeat?"(repeat)":""));
283
284    keypad->queue[keypad->wptr++] = event;
285    if (keypad->wptr == keypad->settings.eventQueueSize) {
286        keypad->wptr = 0;
287    }
288
289    /* if we add an element and the queue is now empty, we have overflowed. */
290    if (keypad->rptr == keypad->wptr) {
291        keypad->overflow = true;
292    }
293
294    NEXUS_TaskCallback_Fire(keypad->dataReadyCallback);
295}
296
297NEXUS_KeypadHandle NEXUS_Keypad_Open(unsigned index, const NEXUS_KeypadSettings *pSettings)
298{
299    NEXUS_KeypadHandle keypad;
300    BERR_Code rc;
301    BKNI_EventHandle event;
302    NEXUS_KeypadSettings defaultSettings;
303    BKPD_Settings kpdSettings;
304#if NEXUS_HAS_SPI
305    NEXUS_GpioSettings gpioSettings;
306    NEXUS_Error err;
307#endif
308        int i;
309
310    BSTD_UNUSED(index);
311
312    if (!pSettings) {
313        NEXUS_Keypad_GetDefaultSettings(&defaultSettings);
314        pSettings = &defaultSettings;
315    }
316
317    keypad = BKNI_Malloc(sizeof(*keypad));
318    if (!keypad) {
319        BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
320        return NULL;
321    }
322
323    BKNI_Memset(keypad, 0, sizeof(*keypad));
324    BDBG_OBJECT_SET(keypad, NEXUS_Keypad);
325    keypad->dataReadyCallback = NEXUS_TaskCallback_Create(keypad, NULL);
326    NEXUS_TaskCallback_Set(keypad->dataReadyCallback, &pSettings->dataReady);
327
328    keypad->queue = BKNI_Malloc(sizeof(NEXUS_KeypadEvent) * pSettings->eventQueueSize);
329    if (!keypad->queue) {
330        BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
331        goto error;
332    }
333
334    /* Check for SPI */
335    /* SPI keypad requires GPIO Interrupt */
336#if NEXUS_HAS_SPI
337    if(g_NEXUS_keypad.settings.spi && g_NEXUS_keypad.settings.gpio)
338    {
339        NEXUS_Gpio_GetDefaultSettings(NEXUS_GpioType_eStandard, &gpioSettings);
340        NEXUS_CallbackHandler_Init(keypad->spiInterrupt, NEXUS_Keypad_P_DataReady_spi, keypad);
341        gpioSettings.mode = NEXUS_GpioMode_eInput;
342        gpioSettings.interruptMode = NEXUS_GpioInterrupt_eHigh;
343        NEXUS_CallbackHandler_PrepareCallback(keypad->spiInterrupt, gpioSettings.interrupt);
344        err = NEXUS_Gpio_SetSettings(g_NEXUS_keypad.settings.gpio, &gpioSettings);
345        if (err) {
346            BDBG_ERR(("Unable to Set GPIO Settings keypad SPI interrupt"));
347            goto error;
348        }
349
350        goto done;
351    }
352#endif
353
354    rc = BKPD_GetDefaultSettings(&kpdSettings, g_pCoreHandles->chp);
355    if (rc) {BERR_TRACE(rc);goto error;}
356
357    kpdSettings.prescale = pSettings->prescale;
358    kpdSettings.debounce = pSettings->debounce;
359    kpdSettings.intMode = true;
360
361    rc = BKPD_Open(&keypad->kpd, g_pCoreHandles->chp, g_pCoreHandles->reg, g_pCoreHandles->bint, &kpdSettings);
362    if (rc) {BERR_TRACE(rc);goto error;}
363
364    rc = BKPD_GetEventHandle(keypad->kpd, &event);
365    if (rc) {BERR_TRACE(rc);goto error;}
366
367    keypad->eventHandler = NEXUS_RegisterEvent(event, NEXUS_Keypad_P_DataReady, keypad);
368
369        for (i=0;i<4;i++)
370        {
371                uint16_t code;
372
373                rc = BKPD_Read(keypad->kpd, &code);
374                if (rc) {BERR_TRACE(rc);goto error;}
375                if (code != 0)
376                {       /* this pattern occurs when no keypad is connected */
377                        goto done;
378                }
379        }
380        BDBG_WRN(("no keypad detected"));
381        goto error;
382
383done:
384    keypad->settings = *pSettings;
385
386    return keypad;
387error:
388    NEXUS_Keypad_Close(keypad);
389    return NULL;
390}
391
392void NEXUS_Keypad_Close(NEXUS_KeypadHandle keypad)
393{
394    BDBG_OBJECT_ASSERT(keypad, NEXUS_Keypad);
395    if (keypad->eventHandler) {
396        NEXUS_UnregisterEvent(keypad->eventHandler);
397    }
398
399    /* Check for SPI keypad */
400#if NEXUS_HAS_SPI
401    if (keypad->kpd && (g_NEXUS_keypad.settings.spi ==NULL) && (g_NEXUS_keypad.settings.gpio ==NULL))
402#endif
403    {
404        BKPD_Close(keypad->kpd);
405    }
406
407#if NEXUS_HAS_SPI
408    if(g_NEXUS_keypad.settings.spi && g_NEXUS_keypad.settings.gpio)
409    {
410        NEXUS_GpioSettings gpioSettings;
411
412        /* Device closed. No GPIO callbacks wanted. */
413        NEXUS_Gpio_GetDefaultSettings(NEXUS_GpioType_eStandard, &gpioSettings);
414        gpioSettings.interrupt.callback = NULL;
415        NEXUS_Gpio_SetSettings(g_NEXUS_keypad.settings.gpio, &gpioSettings);
416        NEXUS_CallbackHandler_Shutdown(keypad->spiInterrupt);
417    }
418#endif
419
420    if (keypad->queue) {
421        BKNI_Free(keypad->queue);
422    }
423    if(keypad->dataReadyCallback) {
424        NEXUS_TaskCallback_Destroy(keypad->dataReadyCallback);
425    }
426
427    BDBG_OBJECT_DESTROY(keypad, NEXUS_Keypad);
428    BKNI_Free(keypad);
429}
430
431NEXUS_Error NEXUS_Keypad_GetEvents(NEXUS_KeypadHandle keypad, NEXUS_KeypadEvent *pEvents, size_t numEvents, size_t *pNumEventsRead, bool *pOverflow)
432{
433    BDBG_OBJECT_ASSERT(keypad, NEXUS_Keypad);
434
435    if (numEvents && !pEvents) return BERR_TRACE(NEXUS_INVALID_PARAMETER);
436    *pNumEventsRead = 0;
437    while (numEvents && keypad->rptr != keypad->wptr) {
438        pEvents[(*pNumEventsRead)++] = keypad->queue[keypad->rptr++];
439        numEvents--;
440        if (keypad->rptr == keypad->settings.eventQueueSize) {
441            keypad->rptr = 0;
442        }
443    }
444
445    *pOverflow = keypad->overflow;
446    keypad->overflow = false;
447
448    return 0;
449}
450
451void NEXUS_Keypad_FlushEvents(NEXUS_KeypadHandle keypad)
452{
453    BDBG_OBJECT_ASSERT(keypad, NEXUS_Keypad);
454    keypad->rptr = keypad->wptr = 0;
455}
Note: See TracBrowser for help on using the repository browser.