568c441fd8
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31498 a1c6a512-1295-4272-9138-f99709370657
308 lines
8.6 KiB
C
308 lines
8.6 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2002 by Linus Nielsen Feltzing
|
|
*
|
|
* iPod driver based on code from the ipodlinux project - http://ipodlinux.org
|
|
* Adapted for Rockbox in January 2006
|
|
* Original file: podzilla/usb.c
|
|
* Copyright (C) 2005 Adam Johnston
|
|
*
|
|
* 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 "usb.h"
|
|
#include "button.h"
|
|
#include "ata.h"
|
|
#include "string.h"
|
|
#include "usb_core.h"
|
|
#include "usb_drv.h"
|
|
|
|
#if defined(IPOD_4G) || defined(IPOD_COLOR) \
|
|
|| defined(IPOD_MINI) || defined(IPOD_MINI2G)
|
|
/* GPIO D bit 3 is usb detect */
|
|
#define USB_GPIO GPIOD
|
|
#define USB_GPIO_MASK 0x08
|
|
#define USB_GPIO_VAL 0x08
|
|
|
|
#elif defined(IPOD_NANO) || defined(IPOD_VIDEO)
|
|
/* GPIO L bit 4 is usb detect */
|
|
#define USB_GPIO GPIOL
|
|
#define USB_GPIO_MASK 0x10
|
|
#define USB_GPIO_VAL 0x10
|
|
|
|
#elif defined(SANSA_C200)
|
|
/* GPIO H bit 1 is usb/charger detect */
|
|
#define USB_GPIO GPIOH
|
|
#define USB_GPIO_MASK 0x02
|
|
#define USB_GPIO_VAL 0x02
|
|
|
|
#elif defined(SANSA_E200)
|
|
/* GPIO B bit 4 is usb/charger detect */
|
|
#define USB_GPIO GPIOB
|
|
#define USB_GPIO_MASK 0x10
|
|
#define USB_GPIO_VAL 0x10
|
|
|
|
#elif defined(IRIVER_H10) || defined(IRIVER_H10_5GB) || defined(MROBE_100)
|
|
/* GPIO L bit 2 is usb detect */
|
|
#define USB_GPIO GPIOL
|
|
#define USB_GPIO_MASK 0x04
|
|
#define USB_GPIO_VAL 0x04
|
|
|
|
#elif defined(PHILIPS_SA9200)
|
|
/* GPIO B bit 6 (high) is usb bus power detect */
|
|
#define USB_GPIO GPIOB
|
|
#define USB_GPIO_MASK 0x40
|
|
#define USB_GPIO_VAL 0x40
|
|
|
|
#elif defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330)
|
|
/* GPIO E bit 2 is usb detect */
|
|
#define USB_GPIO GPIOE
|
|
#define USB_GPIO_MASK 0x04
|
|
#define USB_GPIO_VAL 0x04
|
|
|
|
#elif defined(SAMSUNG_YH820) || defined(SAMSUNG_YH920) || defined(SAMSUNG_YH925)
|
|
/* GPIO D bit 4 is usb detect */
|
|
#define USB_GPIO GPIOD
|
|
#define USB_GPIO_MASK 0x10
|
|
#define USB_GPIO_VAL 0x10
|
|
|
|
#elif defined(TATUNG_TPJ1022)
|
|
/* GPIO ? bit ? is usb detect (dummy value)*/
|
|
#define USB_GPIO GPIOD
|
|
#define USB_GPIO_MASK 0x10
|
|
#define USB_GPIO_VAL 0x10
|
|
|
|
#elif defined(PBELL_VIBE500)
|
|
/* GPIO L bit 3 is usb detect */
|
|
#define USB_GPIO GPIOL
|
|
#define USB_GPIO_MASK 0x04
|
|
#define USB_GPIO_VAL 0x04
|
|
|
|
#else
|
|
#error No USB GPIO config specified
|
|
#endif
|
|
|
|
#define USB_GPIO_ENABLE GPIO_ENABLE(USB_GPIO)
|
|
#define USB_GPIO_OUTPUT_EN GPIO_OUTPUT_EN(USB_GPIO)
|
|
#define USB_GPIO_INPUT_VAL GPIO_INPUT_VAL(USB_GPIO)
|
|
#define USB_GPIO_INT_EN GPIO_INT_EN(USB_GPIO)
|
|
#define USB_GPIO_INT_LEV GPIO_INT_LEV(USB_GPIO)
|
|
#define USB_GPIO_INT_CLR GPIO_INT_CLR(USB_GPIO)
|
|
#define USB_GPIO_HI_INT_MASK GPIO_HI_INT_MASK(USB_GPIO)
|
|
|
|
static void usb_reset_controller(void)
|
|
{
|
|
/* enable usb module */
|
|
outl(inl(0x7000002C) | 0x3000000, 0x7000002C);
|
|
|
|
DEV_EN |= DEV_USB0;
|
|
DEV_EN |= DEV_USB1;
|
|
|
|
/* reset both USBs */
|
|
DEV_RS |= DEV_USB0;
|
|
DEV_RS &=~DEV_USB0;
|
|
DEV_RS |= DEV_USB1;
|
|
DEV_RS &=~DEV_USB1;
|
|
|
|
DEV_INIT2 |= INIT_USB;
|
|
|
|
while ((inl(0x70000028) & 0x80) == 0);
|
|
outl(inl(0x70000028) | 0x2, 0x70000028);
|
|
udelay(100000);
|
|
XMB_RAM_CFG |= 0x47A;
|
|
|
|
/* disable USB-devices until USB is detected via GPIO */
|
|
#ifndef BOOTLOADER
|
|
/* Disabling USB0 in the bootloader makes the OF not load,
|
|
Also something here breaks usb pin detect in bootloader.
|
|
leave it all enabled untill rockbox main loads */
|
|
DEV_EN &= ~DEV_USB0;
|
|
DEV_EN &= ~DEV_USB1;
|
|
DEV_INIT2 &= ~INIT_USB;
|
|
#endif
|
|
}
|
|
|
|
/* Enable raw status pin read only - not interrupt */
|
|
void usb_pin_init(void)
|
|
{
|
|
GPIO_CLEAR_BITWISE(USB_GPIO_OUTPUT_EN, USB_GPIO_MASK);
|
|
GPIO_SET_BITWISE(USB_GPIO_ENABLE, USB_GPIO_MASK);
|
|
#ifdef USB_FIREWIRE_HANDLING
|
|
/* GPIO C bit 1 is firewire detect */
|
|
GPIO_CLEAR_BITWISE(GPIOC_OUTPUT_EN, 0x02);
|
|
GPIO_SET_BITWISE(GPIOC_ENABLE, 0x02);
|
|
#endif
|
|
}
|
|
|
|
void usb_init_device(void)
|
|
{
|
|
usb_reset_controller();
|
|
|
|
/* Do one-time inits (no dependency on controller) */
|
|
usb_drv_startup();
|
|
|
|
usb_pin_init();
|
|
|
|
/* These set INT_LEV to the inserted level so it will fire if already
|
|
* inserted at the time they are enabled. */
|
|
#ifdef USB_STATUS_BY_EVENT
|
|
GPIO_CLEAR_BITWISE(USB_GPIO_INT_EN, USB_GPIO_MASK);
|
|
GPIO_WRITE_BITWISE(USB_GPIO_INT_LEV, USB_GPIO_VAL, USB_GPIO_MASK);
|
|
USB_GPIO_INT_CLR = USB_GPIO_MASK;
|
|
GPIO_SET_BITWISE(USB_GPIO_INT_EN, USB_GPIO_MASK);
|
|
CPU_HI_INT_EN = USB_GPIO_HI_INT_MASK;
|
|
|
|
#ifdef USB_FIREWIRE_HANDLING
|
|
/* GPIO C bit 1 is firewire detect */
|
|
GPIO_CLEAR_BITWISE(GPIOC_INT_EN, 0x02);
|
|
GPIO_WRITE_BITWISE(GPIOC_INT_LEV, 0x00, 0x02);
|
|
GPIOC_INT_CLR = 0x02;
|
|
GPIO_SET_BITWISE(GPIOC_INT_EN, 0x02);
|
|
CPU_HI_INT_EN = GPIO0_MASK;
|
|
#endif
|
|
CPU_INT_EN = HI_MASK;
|
|
#endif /* USB_STATUS_BY_EVENT */
|
|
}
|
|
|
|
void usb_enable(bool on)
|
|
{
|
|
if (on) {
|
|
/* if USB is detected, re-enable the USB-devices, otherwise make sure it's disabled */
|
|
DEV_EN |= DEV_USB0;
|
|
DEV_EN |= DEV_USB1;
|
|
DEV_INIT2 |= INIT_USB;
|
|
usb_core_init();
|
|
}
|
|
else {
|
|
usb_core_exit();
|
|
/* Disable USB devices */
|
|
usb_reset_controller();
|
|
}
|
|
}
|
|
|
|
void usb_attach(void)
|
|
{
|
|
usb_drv_attach();
|
|
}
|
|
|
|
bool usb_plugged(void)
|
|
{
|
|
return (USB_GPIO_INPUT_VAL & USB_GPIO_MASK) == USB_GPIO_VAL;
|
|
}
|
|
|
|
#ifdef USB_STATUS_BY_EVENT
|
|
/* Cannot always tell power pin from USB pin */
|
|
static int usb_status = USB_EXTRACTED;
|
|
|
|
static int usb_timeout_event(struct timeout *tmo)
|
|
{
|
|
usb_status_event(tmo->data == USB_GPIO_VAL ? USB_INSERTED : USB_EXTRACTED);
|
|
return 0;
|
|
}
|
|
|
|
void usb_insert_int(void)
|
|
{
|
|
static struct timeout usb_oneshot;
|
|
unsigned long val = USB_GPIO_INPUT_VAL & USB_GPIO_MASK;
|
|
usb_status = (val == USB_GPIO_VAL) ? USB_INSERTED : USB_EXTRACTED;
|
|
GPIO_WRITE_BITWISE(USB_GPIO_INT_LEV, val ^ USB_GPIO_MASK, USB_GPIO_MASK);
|
|
USB_GPIO_INT_CLR = USB_GPIO_MASK;
|
|
timeout_register(&usb_oneshot, usb_timeout_event, HZ/5, val);
|
|
}
|
|
|
|
/* USB_DETECT_BY_CORE: Called when device descriptor is requested */
|
|
void usb_drv_usb_detect_event(void)
|
|
{
|
|
/* Filter for invalid bus reset when unplugging by checking the pin state. */
|
|
if(usb_plugged()) {
|
|
usb_status_event(USB_HOSTED);
|
|
}
|
|
}
|
|
#endif /* USB_STATUS_BY_EVENT */
|
|
|
|
#ifdef HAVE_BOOTLOADER_USB_MODE
|
|
/* Replacement function that returns all unused memory after the bootloader
|
|
* because the storage driver uses the audio buffer */
|
|
extern unsigned char freebuffer[];
|
|
extern unsigned char freebufferend[];
|
|
unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
|
|
{
|
|
if (buffer_size)
|
|
*buffer_size = freebufferend - freebuffer + 1;
|
|
|
|
return freebuffer;
|
|
(void)talk_buf;
|
|
}
|
|
#endif /* HAVE_BOOTLOADER_USB_MODE */
|
|
|
|
void usb_drv_int_enable(bool enable)
|
|
{
|
|
/* enable/disable USB IRQ in CPU */
|
|
if(enable) {
|
|
CPU_INT_EN = USB_MASK;
|
|
}
|
|
else {
|
|
CPU_INT_DIS = USB_MASK;
|
|
}
|
|
}
|
|
|
|
/* detect host or charger (INSERTED or EXTRACTED) */
|
|
int usb_detect(void)
|
|
{
|
|
#ifdef USB_STATUS_BY_EVENT
|
|
return usb_status;
|
|
#else
|
|
return usb_plugged() ? USB_INSERTED : USB_EXTRACTED;
|
|
#endif
|
|
}
|
|
|
|
#ifdef USB_FIREWIRE_HANDLING
|
|
#ifdef USB_STATUS_BY_EVENT
|
|
static bool firewire_status = false;
|
|
#endif
|
|
|
|
bool firewire_detect(void)
|
|
{
|
|
#ifdef USB_STATUS_BY_EVENT
|
|
return firewire_status;
|
|
#else
|
|
/* GPIO C bit 1 is firewire detect */
|
|
/* no charger detection needed for firewire */
|
|
return (GPIOC_INPUT_VAL & 0x02) == 0x00;
|
|
#endif
|
|
}
|
|
|
|
#ifdef USB_STATUS_BY_EVENT
|
|
static int firewire_timeout_event(struct timeout *tmo)
|
|
{
|
|
if (tmo->data == 0x00)
|
|
usb_firewire_connect_event();
|
|
return 0;
|
|
}
|
|
|
|
void firewire_insert_int(void)
|
|
{
|
|
static struct timeout firewire_oneshot;
|
|
unsigned long val = GPIOC_INPUT_VAL & 0x02;
|
|
firewire_status = val == 0x00;
|
|
GPIO_WRITE_BITWISE(GPIOC_INT_LEV, val ^ 0x02, 0x02);
|
|
GPIOC_INT_CLR = 0x02;
|
|
timeout_register(&firewire_oneshot, firewire_timeout_event, HZ/5, val);
|
|
}
|
|
#endif /* USB_STATUS_BY_EVENT */
|
|
#endif /* USB_FIREWIRE_HANDLING */
|