rockbox/firmware/target/arm/pp/usb-fw-pp502x.c
Thomas Martitz 22e802e800 playback,talk: Share audiobuffer via core_alloc_maximum().
This fixes the radioart crash that was the result of buffering.c working
on a freed buffer at the same time as buflib (radioart uses buffering.c for the
images). With this change the buffer is owned by buflib exclusively so this
cannot happen.

As a result, audio_get_buffer() doesn't exist anymore. Callers should call
core_alloc_maximum() directly. This buffer needs to be protected as usual
against movement if necessary (previously it was not protected at all which
cased the radioart crash), To get most of it they can adjust the willingness of
the talk engine to give its buffer away (at the expense of disabling voice
interface) with the new talk_buffer_set_policy() function.

Change-Id: I52123012208d04967876a304451d634e2bef3a33
2013-12-23 12:17:38 +01:00

288 lines
8 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)
{
#if defined(IPOD_VIDEO)
/* FIXME: Some iPod Video's need this 2nd call of usb_drv_init() to establish
* an USB connection. */
usb_drv_init();
#endif
}
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);
}
#endif /* USB_STATUS_BY_EVENT */
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 */