rockbox/firmware/target/arm/tms320dm320/creative-zvm/pic-creativezvm.c
Maurus Cuelenaere ee1e8be37f Creative ZVM:
* Re-enable USB
 * Acknowledge EP0SETUP packets
 * Spin disk down when no files get loaded in the bootloader
 * Clean up/fix some other stuff


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19931 a1c6a512-1295-4272-9138-f99709370657
2009-02-05 21:47:54 +00:00

383 lines
12 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2008 by Maurus Cuelenaere
*
* Creative Zen Vision:M interrupt based PIC driver
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "system.h"
#include "kernel.h"
#include "button-target.h"
#include "i2c-dm320.h"
#include "sprintf.h"
#include "logf.h"
#ifdef BUTTON_DEBUG
#include "lcd-target.h"
#include "lcd.h"
#include "font.h"
#endif
#ifndef ZEN_VISION
/* Creative Zen Vision:M */
#define BTN_LEFT 0xAF00
#define BTN_RIGHT 0xA700
#define BTN_BACK 0xDF00
#define BTN_CUSTOM 0xC700
#define BTN_PLAY 0x9700
#define BTN_POWER 0x8700
#define BTN_MENU 0xCF00
#define BTN_HOLD 0xCF07
#define BTN_UNHOLD 0xD707
#define BTN_REL 1
#define BTN_TOUCHPAD_PRESS 0x8F00
#define BTN_TOUCHPAD_SCROLL_DOWN 0x0F03
#define BTN_TOUCHPAD_CORNER_DOWN 0xD700
#define BTN_TOUCHPAD_CORNER_UP 0x9F00
#define BTN_TOUCHPAD_SCROLL_UP 0x0F04
#define HEADPHONE_PLUGIN_A 0x5707
#define HEADPHONE_PLUGIN_B 0x5F07
#define HEADPHONE_UNPLUG_A 0x3707
#define HEADPHONE_UNPLUG_B 0x3F07
#define DOCK_INSERT 0x6707
#define DOCK_UNPLUG 0xDF06
#define DOCK_USB_INSERT 0x2F06
#define DOCK_USB_UNPLUG 0x3F06
#define DOCK_POWER_INSERT 0x1707
#define DOCK_POWER_UNPLUG 0x1F07
#else
/* Creative Zen Vision */
#define BTN_LEFT 0xCF00
#define BTN_RIGHT 0xEF00
#define BTN_BACK 0xBF00
#define BTN_CUSTOM 0x0
#define BTN_PLAY 0x2F00
#define BTN_POWER 0x0F00
#define BTN_MENU 0x9F00
#define BTN_HOLD 0x9F06
#define BTN_UNHOLD 0xAF06
/* TODO: other values
First number is just pressing it, second is when you release it or keep it
pressed a bit longer
On/Off = 0F00 && 0F01
Hold = 9F06 && AF06
Volume Up = 6F00 && 6F01
Vol Down = 7F00 && 7F01
Up = DF00 && DF01
Right = EF00 && EF01
Down = FF00 && FF01
Left = CF00 && CF01
Back = BF00 && BF01
Menu = 9F00 && Etcetera
Ok = 1F00
Play = 2F00
Next = 4F00
Prev = 5F00
USB = 2F06
USB ouot = 3F06
Headphones= AF06
Hdphns out= BF06
Charger = 4F06 -> 9F05
Chgrout = 5F06 -> 8F05
AV in = 8F06
AV out = 9F06 */
#define BTN_REL 1
#define BTN_TOUCHPAD_PRESS 0x1F00
#define BTN_TOUCHPAD_LONG_PRESS 0x1F01
#define BTN_TOUCHPAD_CORNER_DOWN 0xFF00
#define BTN_TOUCHPAD_SCROLL_DOWN 0xFF01
#define BTN_TOUCHPAD_CORNER_UP 0xDF00
#define BTN_TOUCHPAD_SCROLL_UP 0xDF01
#define HEADPHONE_PLUGIN_A 0xAF06
#define HEADPHONE_PLUGIN_B 0x00AF06 //Dummy Value
#define HEADPHONE_UNPLUG_A 0x00BF06 //Dummy Value
#define HEADPHONE_UNPLUG_B 0x00BF061 //Dummy Value
#define DOCK_INSERT 0x00003 //Dummy Value
#define DOCK_UNPLUG 0x00002 //Dummy Value
#define DOCK_USB_INSERT 0x2F06
#define DOCK_USB_UNPLUG 0x3F06
#define DOCK_POWER_INSERT 0x4F06
#define DOCK_POWER_UNPLUG 0x5F06
#define DOCK_AV_INSERT 0x8F06
#define DOCK_AV_UNPLUG 0x9F06
#endif
#define PIC_ADR 0x07
#define MASK_TV_OUT(x) ((x >> 14) & 1)
#define MASK_xx1(x) ((x >> 9) & 3)
#define MASK_xx2(x) ((x >> 4) & 1)
#define MASK_xx3(x) ((x >> 5) & 1)
#define MASK_xx4(x) ((x >> 6) & 1)
#define MASK_xx5(x) ((x >> 13) & 1)
#define MASK_xx6(x) ((x >> 12) & 1)
#define MASK_xx7(x) ((x >> 11) & 1)
#define NONBUTTON_HEADPHONE (1 << 0)
#define NONBUTTON_DOCK (1 << 1)
#define NONBUTTON_USB (1 << 2)
#define NONBUTTON_POWER (1 << 3)
#define NONBUTTON_VIDEOUT (1 << 4)
static unsigned int btn;
static bool hold_switch;
static unsigned char nonbtn;
static unsigned int pic_init_value;
static unsigned int pic_init2_value;
static unsigned int last_btn;
static long last_tick;
static int tick_diff;
#define TICK_MIN 0x33
#define TICK_MAX 0x34
/* Taken from scramble.c and modified */
static inline unsigned short le2short(unsigned char* buf)
{
return (unsigned short)((buf[1] << 8) | buf[0]);
}
#define map_button(BtN,BtN2) case BtN: \
btn ^= BtN2; \
btn &= BtN2; \
break; \
case BtN ^ BTN_REL: \
btn ^= BtN2; \
btn &= BtN2; \
break;
#ifdef BUTTON_DEBUG
static bool sw = false;
#endif
void GIO0(void)
{
/* Mask GIO0 interrupt */
IO_INTC_IRQ1 = INTR_IRQ1_EXT0;
unsigned char msg[4];
i2c_read(PIC_ADR, msg, sizeof(msg));
tick_diff = current_tick - last_tick;
last_tick = current_tick;
unsigned short btn_press = le2short(msg);
if(tick_diff >= TICK_MIN && tick_diff <= TICK_MAX)
{
/* Ignore this, as it is a hold event */
return;
}
last_btn = btn_press;
switch(btn_press)
{
map_button(BTN_LEFT, BUTTON_LEFT);
map_button(BTN_RIGHT, BUTTON_RIGHT);
map_button(BTN_BACK, BUTTON_BACK);
map_button(BTN_CUSTOM, BUTTON_CUSTOM);
map_button(BTN_MENU, BUTTON_MENU);
map_button(BTN_PLAY, BUTTON_PLAY);
map_button(BTN_POWER, BUTTON_POWER);
map_button(BTN_TOUCHPAD_PRESS, BUTTON_SELECT);
map_button(BTN_TOUCHPAD_CORNER_DOWN, BUTTON_DOWN);
map_button(BTN_TOUCHPAD_CORNER_UP, BUTTON_UP);
#ifndef ZEN_VISION
/* These don't seem to work for some reason on the Zen Vision.. */
case BTN_TOUCHPAD_SCROLL_DOWN:
btn = BUTTON_DOWN;
break;
case BTN_TOUCHPAD_SCROLL_UP:
btn = BUTTON_UP;
break;
#endif
case BTN_HOLD:
hold_switch = true;
break;
case BTN_UNHOLD:
hold_switch = false;
break;
#ifndef ZEN_VISION
/* These don't seem to work for some reason.. */
case HEADPHONE_PLUGIN_A:
case HEADPHONE_PLUGIN_B:
nonbtn |= NONBUTTON_HEADPHONE;
break;
case HEADPHONE_UNPLUG_A:
case HEADPHONE_UNPLUG_B:
nonbtn &= ~NONBUTTON_HEADPHONE;
break;
#endif
case DOCK_INSERT:
nonbtn |= NONBUTTON_DOCK;
break;
case DOCK_UNPLUG:
nonbtn &= ~(NONBUTTON_DOCK | NONBUTTON_USB | NONBUTTON_POWER);
break;
case DOCK_USB_INSERT:
nonbtn |= NONBUTTON_USB;
break;
case DOCK_USB_UNPLUG:
nonbtn &= ~NONBUTTON_USB;
break;
case DOCK_POWER_INSERT:
nonbtn |= NONBUTTON_POWER;
break;
case DOCK_POWER_UNPLUG:
nonbtn &= ~NONBUTTON_POWER;
break;
}
#ifdef BUTTON_DEBUG
unsigned char weergvn[10];
#ifdef BOOTLOADER
lcd_set_foreground((sw ? LCD_RGBPACK(255,0,0) : LCD_RGBPACK(0,255,0) ));
#endif
snprintf(weergvn, sizeof(char)*10, "%x",
(unsigned int)((msg[3] << 24) |
(msg[2] << 16) | (msg[1] << 8) | msg[0]));
lcd_putsxy(LCD_WIDTH-SYSFONT_WIDTH*10, LCD_HEIGHT-SYSFONT_HEIGHT*10,
weergvn);
snprintf(weergvn, sizeof(char)*10, "%x", btn);
lcd_putsxy(LCD_WIDTH-SYSFONT_WIDTH*10, LCD_HEIGHT-SYSFONT_HEIGHT*7,
weergvn);
#ifdef BOOTLOADER
lcd_set_foreground(LCD_BLACK);
#endif
lcd_update();
sw = !sw;
#endif
logf("PIC: 0x%x", (unsigned int)((msg[3] << 24) |
(msg[2] << 16) | (msg[1] << 8) | msg[0]));
}
static void send_command_to_pic(const unsigned char in, unsigned char* out,
const unsigned int length)
{
/* Disable GIO0 interrupt */
IO_INTC_EINT1 &= ~INTR_EINT1_EXT0;
/* Clear EXT0 interrupt */
IO_INTC_IRQ1 = INTR_IRQ1_EXT0;
/* Write command to I²C */
restart:
i2c_write(PIC_ADR, &in, 1);
/* Wait for PIC */
int i = 0;
while(!(IO_INTC_IRQ1 & INTR_IRQ1_EXT0))
{
sleep(0);
i++;
if(i > 50)
goto restart;
}
/* Read return from I²C */
i2c_read(PIC_ADR, out, length);
/* Re-enable GIO0 interrupt */
IO_INTC_EINT1 |= INTR_EINT1_EXT0;
}
bool headphones_inserted(void)
{
return (bool)(nonbtn & NONBUTTON_HEADPHONE);
}
void button_init_device(void)
{
/* TODO: I suppose GIO0 has to be set to input and enable interrupts on
it? */
/* Enable GIO0 interrupt */
IO_INTC_EINT1 |= INTR_EINT1_EXT0;
btn=nonbtn=pic_init_value=pic_init2_value=last_btn=hold_switch=0;
/* Initialize PIC */
send_command_to_pic(1, (unsigned char *)&pic_init_value,
sizeof(pic_init_value));
send_command_to_pic(2, (unsigned char *)&pic_init2_value,
sizeof(pic_init2_value));
}
int button_read_device(void)
{
if(hold_switch)
return 0;
else
return btn;
}
bool button_hold(void)
{
return hold_switch;
}
bool button_usb_connected(void)
{
return (bool)(nonbtn & NONBUTTON_USB);
}
#ifndef BOOTLOADER
int pic_dbg_num_items(void)
{
return 13;
}
char* pic_dbg_item(int selected_item, void *data, char *buffer, size_t buffer_len)
{
(void)data;
switch(selected_item)
{
case 0:
snprintf(buffer, buffer_len, "Init value 1: 0x%04x", pic_init_value);
return buffer;
case 1:
snprintf(buffer, buffer_len, "Init value 2: 0x%04x", pic_init2_value);
return buffer;
case 2:
snprintf(buffer, buffer_len, "Last button value: 0x%04x Raw value: 0x%04x", last_btn, btn);
return buffer;
case 3:
snprintf(buffer, buffer_len, "Last button differs in ticks: 0x%04x", tick_diff);
return buffer;
case 4:
snprintf(buffer, buffer_len, "Dock values: 0x%04x", nonbtn);
return buffer;
#define B(n,w,b) case n: \
snprintf(buffer, buffer_len, "%s: 0x%04x", w, b); \
return buffer;
B(5, "MASK_TV_OUT", MASK_TV_OUT(pic_init_value));
B(6, "MASK_xx1", MASK_xx1(pic_init_value));
B(7, "MASK_xx2", MASK_xx2(pic_init_value));
B(8, "MASK_xx3", MASK_xx3(pic_init_value));
B(9, "MASK_xx4", MASK_xx4(pic_init_value));
B(10, "MASK_xx5", MASK_xx5(pic_init_value));
B(11, "MASK_xx6", MASK_xx6(pic_init_value));
B(12, "MASK_xx7", MASK_xx7(pic_init_value));
#undef B
}
return NULL;
}
#endif