blob: 00bc9784fbc6b517ce89e44f8dc26c0a06bda02f [file] [log] [blame]
/*
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*/
#include <common.h>
#include <usb.h>
#include <cros/boot_device.h>
#include <cros/crossystem_data.h>
#include <vboot_api.h>
static int is_enumerated;
#ifdef CONFIG_USB_KEYBOARD
int board_use_usb_keyboard(int boot_mode)
{
struct vboot_flag_details devsw;
/* the keyboard is needed only in developer mode and recovery mode */
vboot_flag_fetch(VBOOT_FLAG_DEVELOPER, &devsw);
if (!devsw.value && (boot_mode != FIRMWARE_TYPE_RECOVERY))
return 0;
/* does this machine have a USB keyboard as primary input ? */
if (fdtdec_get_config_bool(gd->fdt_blob, "usb-keyboard"))
return 1;
return 0;
}
#endif
static int boot_device_usb_start(uint32_t disk_flags)
{
static char has_been_powered_on;
int enumerate = 1;
/* If we aren't looking for removable disks, skip USB */
if (!(disk_flags & VB_DISK_FLAG_REMOVABLE))
return 0;
/*
* if the USB devices have already been enumerated, redo it
* only if something has been plugged on unplugged.
*/
if (is_enumerated)
enumerate = usb_detect_change();
if (enumerate) {
/*
* TODO(crosbug/11523): USB flash drive responds to probing
* only after it is powered on; so start USB device if this is
* the first time, and wait 3 seconds for them to power up.
* From experiments a 2 seconds delay is sufficient; choose 3
* seconds to have more margin of safety.
*
* However, this should be a temporary workaround, as USB driver
* should deal with this situation.
*/
if (!has_been_powered_on) {
usb_stop();
usb_init();
mdelay(3000);
has_been_powered_on = 1;
}
/*
* We should stop all USB devices first. Otherwise we can't
* detect any new devices.
*/
usb_stop();
if (usb_init() >= 0) {
#ifdef CONFIG_USB_KEYBOARD
if (board_use_usb_keyboard(FIRMWARE_TYPE_RECOVERY))
drv_usb_kbd_init();
#endif
usb_stor_scan(/*mode=*/1);
is_enumerated = 1;
}
}
return 1;
}
static int boot_device_usb_scan(block_dev_desc_t **desc, int max_devs,
uint32_t disk_flags)
{
int index;
max_devs = min(max_devs, USB_MAX_STOR_DEV);
for (index = 0; index < max_devs; index++) {
desc[index] = usb_stor_get_dev(index);
if (!desc[index])
break;
}
return index;
}
static struct boot_interface usb_interface = {
.name = "usb",
.type = IF_TYPE_USB,
.start = boot_device_usb_start,
.scan = boot_device_usb_scan,
};
int boot_device_usb_probe(void)
{
return boot_device_register_interface(&usb_interface);
}