A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 745 lines 19 kB view raw
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