diff options
Diffstat (limited to 'firmware/lib/vboot_audio.c')
-rw-r--r-- | firmware/lib/vboot_audio.c | 463 |
1 files changed, 244 insertions, 219 deletions
diff --git a/firmware/lib/vboot_audio.c b/firmware/lib/vboot_audio.c index 641bae0f..d89bc43f 100644 --- a/firmware/lib/vboot_audio.c +++ b/firmware/lib/vboot_audio.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +/* Copyright (c) 2013 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. * @@ -18,8 +18,10 @@ #define UINT_MAX 4294967295U /* 0xffffffff */ #endif -/* Need one second of noise in the first 22 seconds. - * Total delay >= 30 seconds, <= 60 seconds. */ +/* + * Need one second of noise in the first 22 seconds. + * Total delay >= 30 seconds, <= 60 seconds. + */ #define REQUIRED_NOISE_TIME 1000 #define REQUIRED_NOISE_WITHIN 22000 #define REQUIRED_TOTAL_DELAY 30000 @@ -39,238 +41,261 @@ uint32_t short_count_ = sizeof(short_notes_) / sizeof(VbDevMusicNote); /* No need to dynamically allocate this, is there? */ static VbAudioContext au; - /* Convert from msecs to VbExGetTimer() units. */ static uint64_t ticks_per_msec = 0; /* Initialized by VbAudioOpen() */ static uint64_t VbMsecToTicks(uint16_t msec) { return ticks_per_msec * msec; } -/* Find and return a valid set of note events. We'll use the user's struct - * if possible, but we will still enforce the 30-second timeout and require at - * least a second of audible noise within that period. We allocate storage for - * two reasons: the user's struct will be in flash, which is slow to read, and - * we may need one extra note at the end to pad out the user's notes to a full - * 30 seconds. The caller should free it when finished. +/** + * Find and return a valid set of note events. + * + * We'll use the user's struct if possible, but we will still enforce the + * 30-second timeout and require at least a second of audible noise within that + * period. We allocate storage for two reasons: the user's struct will be in + * flash, which is slow to read, and we may need one extra note at the end to + * pad out the user's notes to a full 30 seconds. The caller should free it + * when finished. */ -static void VbGetDevMusicNotes(VbAudioContext *audio, int use_short) { - VbDevMusicNote *notebuf = 0; - VbDevMusicNote *builtin = 0; - VbDevMusic *hdr = CUSTOM_MUSIC_NOTES; - uint32_t maxsize = CUSTOM_MUSIC_MAXSIZE; /* always <= flash size (8M) */ - uint32_t maxnotes, mysum, mylen, i; - uint32_t this_msecs, on_msecs, total_msecs; - uint32_t count; - - VBDEBUG(("VbGetDevMusicNotes: use_short is %d, hdr is %lx, maxsize is %d\n", - use_short, hdr, maxsize)); - - if (use_short) { - builtin = short_notes_; - count = short_count_; - goto nope; - } - - builtin = default_notes_; - count = default_count_; - - /* If we can't beep in the background, don't allow customization. */ - if (!audio->background_beep) - goto nope; - - if (!hdr || maxsize < sizeof(VbDevMusic)) - goto nope; - - if (0 != Memcmp(hdr->sig, "$SND", sizeof(hdr->sig))) { - VBDEBUG(("VbGetDevMusicNotes: bad sig\n")); - goto nope; - } - - /* How many notes will fit in the flash region? One more than you'd think, - * because there's one note in the header itself. - */ - maxnotes = 1 + (maxsize - sizeof(VbDevMusic)) / sizeof(VbDevMusicNote); - if (hdr->count == 0 || hdr->count > maxnotes) { - VBDEBUG(("VbGetDevMusicNotes: count=%d maxnotes=%d\n", - hdr->count, maxnotes)); - goto nope; - } - - /* CUSTOM_MUSIC_MAXSIZE can't be larger than the size of the flash (around 8M - * or so) so this isn't really necessary, but let's be safe anyway. - */ - if ((sizeof(VbDevMusicNote) > UINT_MAX / hdr->count) || - (sizeof(hdr->count) > UINT_MAX - hdr->count * sizeof(VbDevMusicNote))) { - VBDEBUG(("VbGetDevMusicNotes: count=%d, just isn't right\n")); - goto nope; - } - - /* Now we know this won't overflow */ - mylen = (uint32_t)(sizeof(hdr->count) + hdr->count * sizeof(VbDevMusicNote)); - mysum = Crc32(&(hdr->count), mylen); - - if (mysum != hdr->checksum) { - VBDEBUG(("VbGetDevMusicNotes: mysum=%08x, want=%08x\n", - mysum, hdr->checksum)); - goto nope; - } - - VBDEBUG(("VbGetDevMusicNotes: custom notes struct found at %lx\n", hdr)); - - /* Measure the audible sound up to the first 22 seconds, being careful to - * avoid rollover. The note time is 16 bits, and the note count is 32 bits. - * The product should fit in 64 bits. - */ - total_msecs = 0; - on_msecs = 0; - for (i=0; i < hdr->count; i++) { - this_msecs = hdr->notes[i].msec ; - if (this_msecs) { - total_msecs += this_msecs; - if (total_msecs <= REQUIRED_NOISE_WITHIN && - hdr->notes[i].frequency >= 100 && hdr->notes[i].frequency <= 2000) - on_msecs += this_msecs; - } - } - - /* We require at least one second of noise in the first 22 seconds */ - VBDEBUG(("VbGetDevMusicNotes: with %ld msecs of sound to begin\n", - on_msecs)); - if (on_msecs < REQUIRED_NOISE_TIME) { - goto nope; - } - - /* We'll also require that the total time be less than a minute. No real - * reason, it just gives us less to worry about. - */ - VBDEBUG(("VbGetDevMusicNotes: lasting %ld msecs\n", total_msecs)); - if (total_msecs > MAX_CUSTOM_DELAY) { - goto nope; - } - - /* One more check, just to be paranoid. */ - if (hdr->count > (UINT_MAX / sizeof(VbDevMusicNote) - 1)) { - VBDEBUG(("VbGetDevMusicNotes: they're all out to get me!\n")); - goto nope; - } - - /* Okay, it looks good. Allocate the space (plus one) and copy it over. */ - notebuf = VbExMalloc((hdr->count + 1) * sizeof(VbDevMusicNote)); - Memcpy(notebuf, hdr->notes, hdr->count * sizeof(VbDevMusicNote)); - count = hdr->count; - - /* We also require at least 30 seconds of delay. */ - if (total_msecs < REQUIRED_TOTAL_DELAY) { - /* If the total time is less than 30 seconds, the needed difference will - * fit in 16 bits. - */ - this_msecs = (REQUIRED_TOTAL_DELAY - total_msecs) & 0xffff; - notebuf[hdr->count].msec = this_msecs; - notebuf[hdr->count].frequency = 0; - count++; - VBDEBUG(("VbGetDevMusicNotes: adding %ld msecs of silence\n", - this_msecs)); - } - - /* done */ - audio->music_notes = notebuf; - audio->note_count = count; - audio->free_notes_when_done = 1; - return; - -nope: - /* No custom notes, use the default. The count is already set. */ - VBDEBUG(("VbGetDevMusicNotes: using %d default notes\n", count)); - audio->music_notes = builtin; - audio->note_count = count; - audio->free_notes_when_done = 0; +static void VbGetDevMusicNotes(VbAudioContext *audio, int use_short) +{ + VbDevMusicNote *notebuf = 0; + VbDevMusicNote *builtin = 0; + VbDevMusic *hdr = CUSTOM_MUSIC_NOTES; + uint32_t maxsize = CUSTOM_MUSIC_MAXSIZE; /* always <= flash size (8M) */ + uint32_t maxnotes, mysum, mylen, i; + uint32_t this_msecs, on_msecs, total_msecs; + uint32_t count; + + VBDEBUG(("VbGetDevMusicNotes: use_short is %d, hdr is %lx, " + "maxsize is %d\n", use_short, hdr, maxsize)); + + if (use_short) { + builtin = short_notes_; + count = short_count_; + goto nope; + } + + builtin = default_notes_; + count = default_count_; + + /* If we can't beep in the background, don't allow customization. */ + if (!audio->background_beep) + goto nope; + + if (!hdr || maxsize < sizeof(VbDevMusic)) + goto nope; + + if (0 != Memcmp(hdr->sig, "$SND", sizeof(hdr->sig))) { + VBDEBUG(("VbGetDevMusicNotes: bad sig\n")); + goto nope; + } + + /* + * How many notes will fit in the flash region? One more than you'd + * think, because there's one note in the header itself. + */ + maxnotes = 1 + (maxsize - sizeof(VbDevMusic)) / sizeof(VbDevMusicNote); + if (hdr->count == 0 || hdr->count > maxnotes) { + VBDEBUG(("VbGetDevMusicNotes: count=%d maxnotes=%d\n", + hdr->count, maxnotes)); + goto nope; + } + + /* + * CUSTOM_MUSIC_MAXSIZE can't be larger than the size of the flash + * (around 8M or so) so this isn't really necessary, but let's be safe + * anyway. + */ + if ((sizeof(VbDevMusicNote) > UINT_MAX / hdr->count) || + (sizeof(hdr->count) > + UINT_MAX - hdr->count * sizeof(VbDevMusicNote))) { + VBDEBUG(("VbGetDevMusicNotes: count=%d, just isn't right\n")); + goto nope; + } + + /* Now we know this won't overflow */ + mylen = (uint32_t)(sizeof(hdr->count) + + hdr->count * sizeof(VbDevMusicNote)); + mysum = Crc32(&(hdr->count), mylen); + + if (mysum != hdr->checksum) { + VBDEBUG(("VbGetDevMusicNotes: mysum=%08x, want=%08x\n", + mysum, hdr->checksum)); + goto nope; + } + + VBDEBUG(("VbGetDevMusicNotes: custom notes struct at %lx\n", hdr)); + + /* + * Measure the audible sound up to the first 22 seconds, being careful + * to avoid rollover. The note time is 16 bits, and the note count is + * 32 bits. The product should fit in 64 bits. + */ + total_msecs = 0; + on_msecs = 0; + for (i=0; i < hdr->count; i++) { + this_msecs = hdr->notes[i].msec ; + if (this_msecs) { + total_msecs += this_msecs; + if (total_msecs <= REQUIRED_NOISE_WITHIN && + hdr->notes[i].frequency >= 100 && + hdr->notes[i].frequency <= 2000) + on_msecs += this_msecs; + } + } + + /* We require at least one second of noise in the first 22 seconds */ + VBDEBUG(("VbGetDevMusicNotes: with %ld msecs of sound to begin\n", + on_msecs)); + if (on_msecs < REQUIRED_NOISE_TIME) + goto nope; + + /* + * We'll also require that the total time be less than a minute. No + * real reason, it just gives us less to worry about. + */ + VBDEBUG(("VbGetDevMusicNotes: lasting %ld msecs\n", total_msecs)); + if (total_msecs > MAX_CUSTOM_DELAY) { + goto nope; + } + + /* One more check, just to be paranoid. */ + if (hdr->count > (UINT_MAX / sizeof(VbDevMusicNote) - 1)) { + VBDEBUG(("VbGetDevMusicNotes: they're all out to get me!\n")); + goto nope; + } + + /* Looks good. Allocate the space (plus one) and copy it over. */ + notebuf = VbExMalloc((hdr->count + 1) * sizeof(VbDevMusicNote)); + Memcpy(notebuf, hdr->notes, hdr->count * sizeof(VbDevMusicNote)); + count = hdr->count; + + /* We also require at least 30 seconds of delay. */ + if (total_msecs < REQUIRED_TOTAL_DELAY) { + /* + * If the total time is less than 30 seconds, the needed + * difference will fit in 16 bits. + */ + this_msecs = (REQUIRED_TOTAL_DELAY - total_msecs) & 0xffff; + notebuf[hdr->count].msec = this_msecs; + notebuf[hdr->count].frequency = 0; + count++; + VBDEBUG(("VbGetDevMusicNotes: adding %ld msecs of silence\n", + this_msecs)); + } + + /* Done */ + audio->music_notes = notebuf; + audio->note_count = count; + audio->free_notes_when_done = 1; + return; + + nope: + /* No custom notes, use the default. The count is already set. */ + VBDEBUG(("VbGetDevMusicNotes: using %d default notes\n", count)); + audio->music_notes = builtin; + audio->note_count = count; + audio->free_notes_when_done = 0; } -/* Initialization function. Returns context for processing dev-mode delay */ -VbAudioContext* VbAudioOpen(VbCommonParams* cparams) { - GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data; - VbAudioContext* audio = &au; - int use_short = 0; - uint64_t a,b; - - /* Note: may need to allocate things here in future */ - - /* Calibrate audio delay */ - a = VbExGetTimer(); - VbExSleepMs(10); - b = VbExGetTimer(); - ticks_per_msec = (b - a) / 10ULL ; - VBDEBUG(("VbAudioOpen() - ticks_per_msec is %llu\n", ticks_per_msec)); - - /* Initialize */ - Memset(audio, 0, sizeof(*audio)); - audio->background_beep = 1; - audio->play_until = b; /* "zero" starts now */ - - /* See if we have full background sound capability or not. */ - if (VBERROR_SUCCESS != VbExBeep(0,0)) { - VBDEBUG(("VbAudioOpen() - VbExBeep() is limited\n")); - audio->background_beep = 0; - } - - /* Prepare to generate audio/delay event. Use a short developer screen delay - * if indicated by GBB flags. - */ - if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1 - && (gbb->flags & GBB_FLAG_DEV_SCREEN_SHORT_DELAY)) { - VBDEBUG(("VbAudioOpen() - using short developer screen delay\n")); - use_short = 1; - } - - VbGetDevMusicNotes(audio, use_short); - VBDEBUG(("VbAudioOpen() - note count %d\n", audio->note_count)); - - return audio; +/** + * Initialization function. Returns context for processing dev-mode delay. + */ +VbAudioContext *VbAudioOpen(VbCommonParams *cparams) +{ + GoogleBinaryBlockHeader* gbb = + (GoogleBinaryBlockHeader *)cparams->gbb_data; + VbAudioContext *audio = &au; + int use_short = 0; + uint64_t a, b; + + /* Note: may need to allocate things here in future */ + + /* Calibrate audio delay */ + a = VbExGetTimer(); + VbExSleepMs(10); + b = VbExGetTimer(); + ticks_per_msec = (b - a) / 10ULL ; + VBDEBUG(("VbAudioOpen() - ticks_per_msec is %llu\n", ticks_per_msec)); + + /* Initialize */ + Memset(audio, 0, sizeof(*audio)); + audio->background_beep = 1; + audio->play_until = b; /* "zero" starts now */ + + /* See if we have full background sound capability or not. */ + if (VBERROR_SUCCESS != VbExBeep(0,0)) { + VBDEBUG(("VbAudioOpen() - VbExBeep() is limited\n")); + audio->background_beep = 0; + } + + /* + * Prepare to generate audio/delay event. Use a short developer screen + * delay if indicated by GBB flags. + */ + if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1 + && (gbb->flags & GBB_FLAG_DEV_SCREEN_SHORT_DELAY)) { + VBDEBUG(("VbAudioOpen() - using short dev screen delay\n")); + use_short = 1; + } + + VbGetDevMusicNotes(audio, use_short); + VBDEBUG(("VbAudioOpen() - note count %d\n", audio->note_count)); + + return audio; } -/* Caller should loop without extra delay until this returns false */ -int VbAudioLooping(VbAudioContext* audio) { - uint64_t now; - uint16_t freq = audio->current_frequency; - uint16_t msec = 0; - int looping = 1; +/** + * Caller should loop without extra delay until this returns false. + */ +int VbAudioLooping(VbAudioContext *audio) +{ + uint64_t now; + uint16_t freq = audio->current_frequency; + uint16_t msec = 0; + int looping = 1; #if defined(CONFIG_SANDBOX) - return 0; + return 0; #endif - now = VbExGetTimer(); - while (audio->next_note < audio->note_count && now >= audio->play_until) { - freq = audio->music_notes[audio->next_note].frequency; - msec = audio->music_notes[audio->next_note].msec; - audio->play_until += VbMsecToTicks(msec); - audio->next_note++; - } - - if (now >= audio->play_until) { - looping = 0; - freq = 0; - } - - // Do action here. - if (audio->background_beep) { - if (audio->current_frequency != freq) { - VbExBeep(0, freq); - audio->current_frequency = freq; - } - } else if (freq && msec) { - VbExBeep(msec, freq); - now = VbExGetTimer(); - } - - audio->last_time = now; - return looping; + now = VbExGetTimer(); + while (audio->next_note < audio->note_count && + now >= audio->play_until) { + freq = audio->music_notes[audio->next_note].frequency; + msec = audio->music_notes[audio->next_note].msec; + audio->play_until += VbMsecToTicks(msec); + audio->next_note++; + } + + if (now >= audio->play_until) { + looping = 0; + freq = 0; + } + + /* Do action here. */ + if (audio->background_beep) { + if (audio->current_frequency != freq) { + VbExBeep(0, freq); + audio->current_frequency = freq; + } + } else if (freq && msec) { + VbExBeep(msec, freq); + now = VbExGetTimer(); + } + + audio->last_time = now; + return looping; } -/* Caller should call this prior to booting */ -void VbAudioClose(VbAudioContext* audio) { - VbExBeep(0,0); - if (audio->free_notes_when_done) - VbExFree(audio->music_notes); +/** + * Caller should call this prior to booting. + */ +void VbAudioClose(VbAudioContext *audio) +{ + VbExBeep(0,0); + if (audio->free_notes_when_done) + VbExFree(audio->music_notes); } |