A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 by Mark Arigo
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdlib.h>
23#include "config.h"
24#include "cpu.h"
25#include "system.h"
26#include "kernel.h"
27#include "button-target.h"
28#include "synaptics-mep.h"
29
30/*#define LOGF_ENABLE*/
31#include "logf.h"
32
33/* Driver for the Synaptics Touchpad based on the "Synaptics Modular Embedded
34 Protocol: 3-Wire Interface Specification" documentation */
35
36#if defined(MROBE_100)
37#define INT_ENABLE GPIO_CLEAR_BITWISE(GPIOD_INT_LEV, 0x2);\
38 GPIO_SET_BITWISE(GPIOD_INT_EN, 0x2)
39#define INT_DISABLE GPIO_CLEAR_BITWISE(GPIOD_INT_EN, 0x2);\
40 GPIO_SET_BITWISE(GPIOD_INT_CLR, 0x2)
41
42#define ACK (GPIOD_INPUT_VAL & 0x1)
43#define ACK_HI GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL, 0x1)
44#define ACK_LO GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x1)
45
46#define CLK ((GPIOD_INPUT_VAL & 0x2) >> 1)
47#define CLK_HI GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL, 0x2)
48#define CLK_LO GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x2)
49
50#define DATA ((GPIOD_INPUT_VAL & 0x4) >> 2)
51#define DATA_HI GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x4);\
52 GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL, 0x4)
53#define DATA_LO GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x4);\
54 GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x4)
55#define DATA_CL GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN, 0x4)
56
57#elif defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) || \
58 defined(PBELL_VIBE500)
59#define INT_ENABLE GPIO_CLEAR_BITWISE(GPIOA_INT_LEV, 0x20);\
60 GPIO_SET_BITWISE(GPIOA_INT_EN, 0x20)
61#define INT_DISABLE GPIO_CLEAR_BITWISE(GPIOA_INT_EN, 0x20);\
62 GPIO_SET_BITWISE(GPIOA_INT_CLR, 0x20)
63
64#define ACK (GPIOD_INPUT_VAL & 0x80)
65#define ACK_HI GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL, 0x80)
66#define ACK_LO GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x80)
67
68#define CLK ((GPIOA_INPUT_VAL & 0x20) >> 5)
69#define CLK_HI GPIO_SET_BITWISE(GPIOA_OUTPUT_VAL, 0x20)
70#define CLK_LO GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_VAL, 0x20)
71
72#define DATA ((GPIOA_INPUT_VAL & 0x10) >> 4)
73#define DATA_HI GPIO_SET_BITWISE(GPIOA_OUTPUT_EN, 0x10);\
74 GPIO_SET_BITWISE(GPIOA_OUTPUT_VAL, 0x10)
75#define DATA_LO GPIO_SET_BITWISE(GPIOA_OUTPUT_EN, 0x10);\
76 GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_VAL, 0x10)
77#define DATA_CL GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_EN, 0x10)
78
79#elif defined(PHILIPS_SA9200)
80#define INT_ENABLE GPIO_CLEAR_BITWISE(GPIOD_INT_LEV, 0x2);\
81 GPIO_SET_BITWISE(GPIOD_INT_EN, 0x2)
82#define INT_DISABLE GPIO_CLEAR_BITWISE(GPIOD_INT_EN, 0x2);\
83 GPIO_SET_BITWISE(GPIOD_INT_CLR, 0x2)
84
85#define ACK (GPIOD_INPUT_VAL & 0x8)
86#define ACK_HI GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL, 0x8)
87#define ACK_LO GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x8)
88
89#define CLK ((GPIOD_INPUT_VAL & 0x2) >> 1)
90#define CLK_HI GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL, 0x2)
91#define CLK_LO GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x2)
92
93#define DATA ((GPIOD_INPUT_VAL & 0x10) >> 4)
94#define DATA_HI GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN, 0x10)
95#define DATA_LO GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x10);\
96 GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x10)
97#define DATA_CL GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN, 0x10)
98#endif
99
100#define LO 0
101#define HI 1
102
103#define READ_RETRY 8
104#define READ_ERROR -1
105
106#define MEP_HELLO_HEADER 0x19
107#define MEP_HELLO_ID 0x1
108
109#define MEP_READ 0x1
110#define MEP_WRITE 0x3
111
112static unsigned short syn_status = 0;
113
114static void syn_enable_int(bool enable)
115{
116 if (enable)
117 {
118 INT_ENABLE;
119 }
120 else
121 {
122 INT_DISABLE;
123 }
124}
125
126static int syn_wait_clk_change(unsigned int val)
127{
128 int i;
129
130 for (i = 0; i < 10000; i++)
131 {
132 if (CLK == val)
133 return 1;
134 }
135
136 return 0;
137}
138
139static void syn_set_ack(int val)
140{
141 if (val == HI)
142 {
143 ACK_HI;
144 }
145 else
146 {
147 ACK_LO;
148 }
149}
150
151static void syn_set_data(int val)
152{
153 if (val == HI)
154 {
155 DATA_HI;
156 }
157 else
158 {
159 DATA_LO;
160 }
161}
162
163static inline int syn_get_data(void)
164{
165 DATA_CL;
166#if defined(PBELL_VIBE500) /* for EABI (touchpad doesn't work without it) */
167 udelay(0);
168#endif
169 return DATA;
170}
171
172static void syn_wait_guest_flush(void)
173{
174 /* Flush receiving (flushee) state:
175 handshake until DATA goes high during P3 stage */
176 if (CLK == LO)
177 {
178 syn_set_ack(HI); /* P1 -> P2 */
179 syn_wait_clk_change(HI); /* P2 -> P3 */
180 }
181
182 while (syn_get_data() == LO)
183 {
184 syn_set_ack(HI); /* P3 -> P0 */
185 syn_wait_clk_change(LO); /* P0 -> P1 */
186 syn_set_ack(LO); /* P1 -> P2 */
187 syn_wait_clk_change(HI); /* P2 -> P3 */
188 }
189
190 /* Continue handshaking until back to P0 */
191 syn_set_ack(HI); /* P3 -> P0 */
192}
193
194static void syn_flush(void)
195{
196 int i;
197
198 logf("syn_flush...");
199
200 /* Flusher holds DATA low for at least 36 handshake cycles */
201 syn_set_data(LO);
202
203 for (i = 0; i < 36; i++)
204 {
205 syn_wait_clk_change(LO); /* P0 -> P1 */
206 syn_set_ack(LO); /* P1 -> P2 */
207 syn_wait_clk_change(HI); /* P2 -> P3 */
208 syn_set_ack(HI); /* P3 -> P0 */
209 }
210
211 /* Raise DATA in P1 stage */
212 syn_wait_clk_change(LO); /* P0 -> P1 */
213 syn_set_data(HI);
214
215 /* After a flush, the flushing device enters a flush-receiving (flushee)
216 state */
217 syn_wait_guest_flush();
218}
219
220static int syn_send(char *data, int len)
221{
222 int i, bit;
223 int parity = 0;
224
225 logf("syn_send...");
226
227 /* 1. Lower DATA line to issue a request-to-send to guest */
228 syn_set_data(LO);
229
230 /* 2. Wait for guest to lower CLK */
231 syn_wait_clk_change(LO);
232
233 /* 3. Lower ACK (with DATA still low) */
234 syn_set_ack(LO);
235
236 /* 4. Wait for guest to raise CLK */
237 syn_wait_clk_change(HI);
238
239 /* 5. Send data */
240 for (i = 0; i < len; i++)
241 {
242 logf(" sending byte: %d", data[i]);
243
244 bit = 0;
245 while (bit < 8)
246 {
247 /* 5a. Drive data low if bit is 0, or high if bit is 1 */
248 if (data[i] & (1 << bit))
249 {
250 syn_set_data(HI);
251 parity++;
252 }
253 else
254 {
255 syn_set_data(LO);
256 }
257 bit++;
258
259 /* 5b. Invert ACK to indicate that the data bit is ready */
260 syn_set_ack(HI);
261
262 /* 5c. Wait for guest to invert CLK */
263 syn_wait_clk_change(LO);
264
265 /* Repeat for next bit */
266 if (data[i] & (1 << bit))
267 {
268 syn_set_data(HI);
269 parity++;
270 }
271 else
272 {
273 syn_set_data(LO);
274 }
275 bit++;
276
277 syn_set_ack(LO);
278
279 syn_wait_clk_change(HI);
280 }
281 }
282
283 /* 7. Transmission termination sequence: */
284 /* 7a. Host may put parity bit on DATA. Hosts that do not generate
285 parity should set DATA high. Parity is 1 if there's an odd
286 number of '1' bits, or 0 if there's an even number of '1' bits. */
287 parity = parity % 2;
288 if (parity)
289 {
290 syn_set_data(HI);
291 }
292 else
293 {
294 syn_set_data(LO);
295 }
296 logf(" send parity = %d", parity);
297
298 /* 7b. Raise ACK to indicate that the optional parity bit is ready */
299 syn_set_ack(HI);
300
301 /* 7c. Guest lowers CLK */
302 syn_wait_clk_change(LO);
303
304 /* 7d. Pull DATA high (if parity bit was 0) */
305 syn_set_data(HI);
306
307 /* 7e. Lower ACK to indicate that the stop bit is ready */
308 syn_set_ack(LO);
309
310 /* 7f. Guest raises CLK */
311 syn_wait_clk_change(HI);
312
313 /* 7g. If DATA is low, guest is flushing this transfer. Host should
314 enter the flushee state. */
315 if (syn_get_data() == LO)
316 {
317 logf(" module flushing");
318
319 syn_wait_guest_flush();
320 return -1;
321 }
322
323 /* 7h. Host raises ACK and the link enters the idle state */
324 syn_set_ack(HI);
325
326 return len;
327}
328
329static int syn_read_data(char *data, int data_len)
330{
331 int i, len, bit, parity;
332 char *data_ptr, tmp;
333
334 logf("syn_read_data...");
335
336 /* 1. Guest drives CLK low */
337 if (CLK != LO)
338 return 0;
339
340 /* 1a. If the host is willing to receive a packet it lowers ACK */
341 syn_set_ack(LO);
342
343 /* 2. Guest may issue a request-to-send by lowering DATA. If the
344 guest decides not to transmit a packet, it may abort the
345 transmission by not lowering DATA. */
346
347 /* 3. The guest raises CLK */
348 syn_wait_clk_change(HI);
349
350 /* 4. If the guest is still driving DATA low, the transfer is commited
351 to occur. Otherwise, the transfer is aborted. In either case,
352 the host raises ACK. */
353 if (syn_get_data() == HI)
354 {
355 logf(" read abort");
356
357 syn_set_ack(HI);
358 return READ_ERROR;
359 }
360 else
361 {
362 syn_set_ack(HI);
363 }
364
365 /* 5. Read the incoming data packet */
366 i = 0;
367 len = 0;
368 parity = 0;
369 while (i <= len)
370 {
371 bit = 0;
372
373 if (i < data_len)
374 data_ptr = &data[i];
375 else
376 data_ptr = &tmp;
377
378 *data_ptr = 0;
379 while (bit < 8)
380 {
381 /* 5b. Guset inverts CLK to indicate that data is ready */
382 syn_wait_clk_change(LO);
383
384 /* 5d. Read the data bit from DATA */
385 if (syn_get_data() == HI)
386 {
387 *data_ptr |= (1 << bit);
388 parity++;
389 }
390 bit++;
391
392 /* 5e. Invert ACK to indicate that data has been read */
393 syn_set_ack(LO);
394
395 /* Repeat for next bit */
396 syn_wait_clk_change(HI);
397
398 if (syn_get_data() == HI)
399 {
400 *data_ptr |= (1 << bit);
401 parity++;
402 }
403 bit++;
404
405 syn_set_ack(HI);
406 }
407
408 /* First byte is the packet header */
409 if (i == 0)
410 {
411 /* Format control (bit 3) should be 1 */
412 if (*data_ptr & 0x8)
413 {
414 /* Packet length is bits 0:2 */
415 len = *data_ptr & 0x7;
416 logf(" packet length = %d", len);
417 }
418 else
419 {
420 logf(" invalid format ctrl bit");
421 return READ_ERROR;
422 }
423 }
424
425 i++;
426 }
427
428 /* 7. Transmission termination cycle */
429 /* 7a. The guest generates a parity bit on DATA */
430 /* 7b. The host waits for guest to lower CLK */
431 syn_wait_clk_change(LO);
432
433 /* 7c. The host verifies the parity bit is correct */
434 parity = parity % 2;
435 logf(" parity check: %d / %d", syn_get_data(), parity);
436
437 /* TODO: parity error handling */
438
439 /* 7d. The host lowers ACK */
440 syn_set_ack(LO);
441
442 /* 7e. The host waits for the guest to raise CLK indicating
443 that the stop bit is ready */
444 syn_wait_clk_change(HI);
445
446 /* 7f. The host reads DATA and verifies that it is 1 */
447 if (syn_get_data() == LO)
448 {
449 logf(" framing error");
450
451 syn_set_ack(HI);
452 return READ_ERROR;
453 }
454
455 syn_set_ack(HI);
456
457 return len;
458}
459
460static int syn_read(char *data, int len)
461{
462 int i;
463 int ret = READ_ERROR;
464
465 for (i = 0; i < READ_RETRY; i++)
466 {
467 if (syn_wait_clk_change(LO))
468 {
469 /* module is sending data */
470 ret = syn_read_data(data, len);
471 if (ret != READ_ERROR)
472 return ret;
473
474 syn_flush();
475 }
476 else
477 {
478 /* module is idle */
479 return 0;
480 }
481 }
482
483 return ret;
484}
485
486static int syn_reset(void)
487{
488 int val, id;
489 char data[2];
490
491 logf("syn_reset...");
492
493 /* reset module 0 */
494 data[0] = (0 << 4) | (1 << 3) | 0;
495 syn_send(data, 1);
496
497 val = syn_read(data, 2);
498 if (val == 1)
499 {
500 val = data[0] & 0xff; /* packet header */
501 id = (data[1] >> 4) & 0xf; /* packet id */
502 if ((val == MEP_HELLO_HEADER) && (id == MEP_HELLO_ID))
503 {
504 logf(" module 0 reset");
505 return 1;
506 }
507 }
508
509 logf(" reset failed");
510 return 0;
511}
512
513int touchpad_init(void)
514{
515 syn_flush();
516 syn_status = syn_reset();
517
518 if (syn_status)
519 {
520 /* reset interrupts */
521 syn_enable_int(false);
522 syn_enable_int(true);
523
524 CPU_INT_EN |= HI_MASK;
525 CPU_HI_INT_EN |= GPIO0_MASK;
526 }
527
528 return syn_status;
529}
530
531int touchpad_read_device(char *data, int len)
532{
533 char tmp[4];
534 int id;
535 int val = 0;
536
537 if (syn_status)
538 {
539 /* disable interrupt while we read the touchpad */
540 syn_enable_int(false);
541
542 val = syn_read(data, len);
543 if (val > 0)
544 {
545 val = data[0] & 0xff; /* packet header */
546 id = (data[1] >> 4) & 0xf; /* packet id */
547
548 logf("syn_read:");
549 logf(" data[0] = 0x%08x", data[0]);
550 logf(" data[1] = 0x%08x", data[1]);
551 logf(" data[2] = 0x%08x", data[2]);
552 logf(" data[3] = 0x%08x", data[3]);
553
554 if ((val == MEP_BUTTON_HEADER) && (id == MEP_BUTTON_ID))
555 {
556 /* an absolute packet should follow which we ignore */
557 syn_read(tmp, 4);
558 }
559 else if (val == MEP_ABSOLUTE_HEADER)
560 {
561/* for HDD6330 an absolute packet will follow for sensor nr 0 which we ignore */
562#if defined(PHILIPS_HDD6330)
563 if ((data[3]>>6) == 0)
564 syn_read(tmp, 4);
565 else
566 tmp[1] = 0x0; /* Initialize explicitly */
567 // relay tap gesture packet
568 if (tmp[1]==0x02) { data[1]=0x02; data[2]=0x00; data[3]=0x00; }
569#endif
570 logf(" pos %d", val);
571 logf(" z %d", data[3]);
572 logf(" finger %d", data[1] & 0x1);
573 logf(" gesture %d", data[1] & 0x2);
574 logf(" RelPosVld %d", data[1] & 0x4);
575
576 if (!(data[1] & 0x1))
577 {
578 /* finger is NOT on touch strip */
579 val = 0;
580 }
581 }
582 else
583 {
584 val = 0;
585 }
586 }
587
588 /* re-enable interrupts */
589 syn_enable_int(true);
590 }
591
592 return val;
593}
594
595int touchpad_set_parameter(char mod_nr, char par_nr, unsigned int param)
596{
597 char data[4];
598 int i, val=0;
599
600 if (syn_status)
601 {
602 syn_enable_int(false);
603
604 data[0]=0x03 | (mod_nr << 5); /* header - addr=mod_nr,global:0,ctrl:0,len:3 */
605 data[1]=0x40+par_nr; /* parameter number */
606 data[2]=(param >> 8) & 0xff; /* param_hi */
607 data[3]=param & 0xff; /* param_lo */
608 syn_send(data,4);
609 val=syn_read(data,4); /* try to get the simple ACK = 0x18 */
610
611 /* modules > 0 sometimes don't give ACK immediately but other packets like */
612 /* absolute from the scroll strip, so it has to be ignored until we receive ACK */
613 if ((mod_nr > 0) && ((data[0] & 7) != 0))
614 for (i = 0; i < 2; i++)
615 {
616 val=syn_read(data,4);
617 if (data[0] == 0x18) break;
618 }
619
620 syn_enable_int(true);
621 }
622 return val;
623}
624
625#if 0
626/* Not used normally, but useful for pulling settings or determining
627 which parameters are supported */
628int touchpad_get_parameter(char mod_nr, char par_nr, unsigned int *param_p)
629{
630 char data[4];
631 int val = 0;
632
633 if (syn_status)
634 {
635 syn_enable_int(false);
636
637 /* 'Get MEP Parameter' command packet */
638 data[0]=0x01 | (mod_nr << 5); /* header - addr=mod_nr,global:0,ctrl:0,len:1 */
639 data[1]=0x40+par_nr; /* parameter number */
640 syn_send(data,2);
641
642 /* Must not be an error packet; check size */
643 if (syn_read(data,4) == 3)
644 {
645 /* ACK: param_hi[15:8], param_lo[7:0] */
646 if (param_p)
647 *param_p = ((unsigned int)data[2] << 8) | data[3];
648 val = 3;
649 }
650
651 syn_enable_int(true);
652 }
653
654 return val;
655}
656#endif
657
658int touchpad_set_buttonlights(unsigned int led_mask, char brightness)
659{
660 char data[6];
661 int val = 0;
662
663 if (syn_status)
664 {
665 syn_enable_int(false);
666
667 /* turn on all touchpad leds */
668#if defined(PHILIPS_HDD6330)
669 data[0] = 0x25; /* HDD6330: second module */
670#else
671 data[0] = 0x05;
672#endif
673 data[1] = 0x31;
674 data[2] = (brightness & 0xf) << 4;
675 data[3] = 0x00;
676 data[4] = (led_mask >> 8) & 0xff;
677 data[5] = led_mask & 0xff;
678 syn_send(data, 6);
679
680 /* device responds with a single-byte ACK packet */
681 val = syn_read(data, 2);
682
683 syn_enable_int(true);
684 }
685
686 return val;
687}
688
689#ifdef ROCKBOX_HAS_LOGF
690void syn_info(void)
691{
692 int i, val;
693 char data[8];
694
695 logf("syn_info...");
696
697 /* module base info */
698 logf("module base info:");
699 data[0] = MEP_READ;
700 data[1] = 0x80;
701 syn_send(data, 2);
702 val = syn_read(data, 8);
703 if (val > 0)
704 {
705 for (i = 0; i < 8; i++)
706 logf(" data[%d] = 0x%02x", i, data[i]);
707 }
708
709 /* module product info */
710 logf("module product info:");
711 data[0] = MEP_READ;
712 data[1] = 0x81;
713 syn_send(data, 2);
714 val = syn_read(data, 8);
715 if (val > 0)
716 {
717 for (i = 0; i < 8; i++)
718 logf(" data[%d] = 0x%02x", i, data[i]);
719 }
720
721 /* module serialization */
722 logf("module serialization:");
723 data[0] = MEP_READ;
724 data[1] = 0x82;
725 syn_send(data, 2);
726 val = syn_read(data, 8);
727 if (val > 0)
728 {
729 for (i = 0; i < 8; i++)
730 logf(" data[%d] = 0x%02x", i, data[i]);
731 }
732
733 /* 1-D sensor info */
734 logf("1-d sensor info:");
735 data[0] = MEP_READ;
736 data[1] = 0x80 + 0x20;
737 syn_send(data, 2);
738 val = syn_read(data, 8);
739 if (val > 0)
740 {
741 for (i = 0; i < 8; i++)
742 logf(" data[%d] = 0x%02x", i, data[i]);
743 }
744}
745#endif