~ubuntu-branches/ubuntu/trusty/vboot-utils/trusty

« back to all changes in this revision

Viewing changes to firmware/lib/vboot_audio.c

  • Committer: Package Import Robot
  • Author(s): Antonio Terceiro
  • Date: 2012-12-16 11:03:40 UTC
  • Revision ID: package-import@ubuntu.com-20121216110340-f7wcseecbc9jed5l
Tags: upstream-0~20121212
ImportĀ upstreamĀ versionĀ 0~20121212

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 
2
 * Use of this source code is governed by a BSD-style license that can be
 
3
 * found in the LICENSE file.
 
4
 *
 
5
 * Delay/beep functions used in dev-mode kernel selection.
 
6
 */
 
7
 
 
8
#include "crc32.h"
 
9
#include "gbb_header.h"
 
10
#include "utility.h"
 
11
#include "vboot_api.h"
 
12
#include "vboot_audio.h"
 
13
#include "vboot_audio_private.h"
 
14
#include "vboot_common.h"
 
15
 
 
16
/* BIOS doesn't have /usr/include */
 
17
#ifndef UINT_MAX
 
18
#define UINT_MAX 4294967295U            /* 0xffffffff */
 
19
#endif
 
20
 
 
21
/* Need one second of noise in the first 22 seconds.
 
22
 * Total delay >= 30 seconds, <= 60 seconds. */
 
23
#define REQUIRED_NOISE_TIME    1000
 
24
#define REQUIRED_NOISE_WITHIN 22000
 
25
#define REQUIRED_TOTAL_DELAY  30000
 
26
#define MAX_CUSTOM_DELAY      60000
 
27
 
 
28
/* These are visible externally only to make testing easier */
 
29
VbDevMusicNote default_notes_[] = { {20000, 0}, /* 20 seconds */
 
30
                                    {250, 400}, /* two beeps */
 
31
                                    {250, 0},
 
32
                                    {250, 400},
 
33
                                    {9250, 0} }; /* total 30 seconds */
 
34
uint32_t default_count_ = sizeof(default_notes_) / sizeof(VbDevMusicNote);
 
35
 
 
36
VbDevMusicNote short_notes_[] = { {2000, 0} }; /* two seconds */
 
37
uint32_t short_count_ = sizeof(short_notes_) / sizeof(VbDevMusicNote);
 
38
 
 
39
/* No need to dynamically allocate this, is there? */
 
40
static VbAudioContext au;
 
41
 
 
42
 
 
43
/* Convert from msecs to VbExGetTimer() units. */
 
44
static uint64_t ticks_per_msec = 0;     /* Initialized by VbAudioOpen() */
 
45
static uint64_t VbMsecToTicks(uint16_t msec) {
 
46
  return ticks_per_msec * msec;
 
47
}
 
48
 
 
49
/* Find and return a valid set of note events. We'll use the user's struct
 
50
 * if possible, but we will still enforce the 30-second timeout and require at
 
51
 * least a second of audible noise within that period. We allocate storage for
 
52
 * two reasons: the user's struct will be in flash, which is slow to read, and
 
53
 * we may need one extra note at the end to pad out the user's notes to a full
 
54
 * 30 seconds. The caller should free it when finished.
 
55
 */
 
56
static void VbGetDevMusicNotes(VbAudioContext *audio, int use_short) {
 
57
  VbDevMusicNote *notebuf = 0;
 
58
  VbDevMusicNote *builtin = 0;
 
59
  VbDevMusic *hdr = CUSTOM_MUSIC_NOTES;
 
60
  uint32_t maxsize = CUSTOM_MUSIC_MAXSIZE; /* always <= flash size (8M) */
 
61
  uint32_t maxnotes, mysum, mylen, i;
 
62
  uint32_t this_msecs, on_msecs, total_msecs;
 
63
  uint32_t count;
 
64
 
 
65
  VBDEBUG(("VbGetDevMusicNotes: use_short is %d, hdr is %lx, maxsize is %d\n",
 
66
           use_short, hdr, maxsize));
 
67
 
 
68
  if (use_short) {
 
69
    builtin = short_notes_;
 
70
    count = short_count_;
 
71
    goto nope;
 
72
  }
 
73
 
 
74
  builtin = default_notes_;
 
75
  count = default_count_;
 
76
 
 
77
  /* If we can't beep in the background, don't allow customization. */
 
78
  if (!audio->background_beep)
 
79
    goto nope;
 
80
 
 
81
  if (!hdr || maxsize < sizeof(VbDevMusic))
 
82
    goto nope;
 
83
 
 
84
  if (0 != Memcmp(hdr->sig, "$SND", sizeof(hdr->sig))) {
 
85
    VBDEBUG(("VbGetDevMusicNotes: bad sig\n"));
 
86
    goto nope;
 
87
  }
 
88
 
 
89
  /* How many notes will fit in the flash region? One more than you'd think,
 
90
   * because there's one note in the header itself.
 
91
   */
 
92
  maxnotes = 1 + (maxsize - sizeof(VbDevMusic)) / sizeof(VbDevMusicNote);
 
93
  if (hdr->count == 0 || hdr->count > maxnotes) {
 
94
    VBDEBUG(("VbGetDevMusicNotes: count=%d maxnotes=%d\n",
 
95
             hdr->count, maxnotes));
 
96
    goto nope;
 
97
  }
 
98
 
 
99
  /* CUSTOM_MUSIC_MAXSIZE can't be larger than the size of the flash (around 8M
 
100
   * or so) so this isn't really necessary, but let's be safe anyway.
 
101
   */
 
102
  if ((sizeof(VbDevMusicNote) > UINT_MAX / hdr->count) ||
 
103
      (sizeof(hdr->count) > UINT_MAX - hdr->count * sizeof(VbDevMusicNote))) {
 
104
    VBDEBUG(("VbGetDevMusicNotes: count=%d, just isn't right\n"));
 
105
    goto nope;
 
106
  }
 
107
 
 
108
  /* Now we know this won't overflow */
 
109
  mylen = (uint32_t)(sizeof(hdr->count) + hdr->count * sizeof(VbDevMusicNote));
 
110
  mysum = Crc32(&(hdr->count), mylen);
 
111
 
 
112
  if (mysum != hdr->checksum) {
 
113
    VBDEBUG(("VbGetDevMusicNotes: mysum=%08x, want=%08x\n",
 
114
             mysum, hdr->checksum));
 
115
    goto nope;
 
116
  }
 
117
 
 
118
  VBDEBUG(("VbGetDevMusicNotes: custom notes struct found at %lx\n", hdr));
 
119
 
 
120
  /* Measure the audible sound up to the first 22 seconds, being careful to
 
121
   * avoid rollover. The note time is 16 bits, and the note count is 32 bits.
 
122
   * The product should fit in 64 bits.
 
123
   */
 
124
  total_msecs = 0;
 
125
  on_msecs = 0;
 
126
  for (i=0; i < hdr->count; i++) {
 
127
    this_msecs = hdr->notes[i].msec ;
 
128
    if (this_msecs) {
 
129
      total_msecs += this_msecs;
 
130
      if (total_msecs <= REQUIRED_NOISE_WITHIN &&
 
131
          hdr->notes[i].frequency >= 100 && hdr->notes[i].frequency <= 2000)
 
132
        on_msecs += this_msecs;
 
133
    }
 
134
  }
 
135
 
 
136
  /* We require at least one second of noise in the first 22 seconds */
 
137
  VBDEBUG(("VbGetDevMusicNotes:   with %ld msecs of sound to begin\n",
 
138
           on_msecs));
 
139
  if (on_msecs < REQUIRED_NOISE_TIME) {
 
140
    goto nope;
 
141
  }
 
142
 
 
143
  /* We'll also require that the total time be less than a minute. No real
 
144
   * reason, it just gives us less to worry about.
 
145
   */
 
146
  VBDEBUG(("VbGetDevMusicNotes:   lasting %ld msecs\n", total_msecs));
 
147
  if (total_msecs > MAX_CUSTOM_DELAY) {
 
148
    goto nope;
 
149
  }
 
150
 
 
151
  /* One more check, just to be paranoid. */
 
152
  if (hdr->count > (UINT_MAX / sizeof(VbDevMusicNote) - 1)) {
 
153
    VBDEBUG(("VbGetDevMusicNotes:   they're all out to get me!\n"));
 
154
    goto nope;
 
155
  }
 
156
 
 
157
  /* Okay, it looks good. Allocate the space (plus one) and copy it over. */
 
158
  notebuf = VbExMalloc((hdr->count + 1) * sizeof(VbDevMusicNote));
 
159
  Memcpy(notebuf, hdr->notes, hdr->count * sizeof(VbDevMusicNote));
 
160
  count = hdr->count;
 
161
 
 
162
  /* We also require at least 30 seconds of delay. */
 
163
  if (total_msecs < REQUIRED_TOTAL_DELAY) {
 
164
    /* If the total time is less than 30 seconds, the needed difference will
 
165
     * fit in 16 bits.
 
166
     */
 
167
    this_msecs = (REQUIRED_TOTAL_DELAY - total_msecs) & 0xffff;
 
168
    notebuf[hdr->count].msec = this_msecs;
 
169
    notebuf[hdr->count].frequency = 0;
 
170
    count++;
 
171
    VBDEBUG(("VbGetDevMusicNotes:   adding %ld msecs of silence\n",
 
172
             this_msecs));
 
173
  }
 
174
 
 
175
  /* done */
 
176
  audio->music_notes = notebuf;
 
177
  audio->note_count = count;
 
178
  audio->free_notes_when_done = 1;
 
179
  return;
 
180
 
 
181
nope:
 
182
  /* No custom notes, use the default. The count is already set. */
 
183
  VBDEBUG(("VbGetDevMusicNotes: using %d default notes\n", count));
 
184
  audio->music_notes = builtin;
 
185
  audio->note_count = count;
 
186
  audio->free_notes_when_done = 0;
 
187
}
 
188
 
 
189
 
 
190
/* Initialization function. Returns context for processing dev-mode delay */
 
191
VbAudioContext* VbAudioOpen(VbCommonParams* cparams) {
 
192
  GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data;
 
193
  VbAudioContext* audio = &au;
 
194
  int use_short = 0;
 
195
  uint64_t a,b;
 
196
 
 
197
  /* Note: may need to allocate things here in future */
 
198
 
 
199
  /* Calibrate audio delay */
 
200
  a = VbExGetTimer();
 
201
  VbExSleepMs(10);
 
202
  b = VbExGetTimer();
 
203
  ticks_per_msec = (b - a) / 10ULL ;
 
204
  VBDEBUG(("VbAudioOpen() - ticks_per_msec is %llu\n", ticks_per_msec));
 
205
 
 
206
  /* Initialize */
 
207
  Memset(audio, 0, sizeof(*audio));
 
208
  audio->background_beep = 1;
 
209
  audio->play_until = b;                /* "zero" starts now */
 
210
 
 
211
  /* See if we have full background sound capability or not. */
 
212
  if (VBERROR_SUCCESS != VbExBeep(0,0)) {
 
213
    VBDEBUG(("VbAudioOpen() - VbExBeep() is limited\n"));
 
214
    audio->background_beep = 0;
 
215
  }
 
216
 
 
217
  /* Prepare to generate audio/delay event. Use a short developer screen delay
 
218
   * if indicated by GBB flags.
 
219
   */
 
220
  if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1
 
221
      && (gbb->flags & GBB_FLAG_DEV_SCREEN_SHORT_DELAY)) {
 
222
    VBDEBUG(("VbAudioOpen() - using short developer screen delay\n"));
 
223
    use_short = 1;
 
224
  }
 
225
 
 
226
  VbGetDevMusicNotes(audio, use_short);
 
227
  VBDEBUG(("VbAudioOpen() - note count %d\n", audio->note_count));
 
228
 
 
229
  return audio;
 
230
}
 
231
 
 
232
/* Caller should loop without extra delay until this returns false */
 
233
int VbAudioLooping(VbAudioContext* audio) {
 
234
  uint64_t now;
 
235
  uint16_t freq = audio->current_frequency;
 
236
  uint16_t msec = 0;
 
237
  int looping = 1;
 
238
 
 
239
#if defined(CONFIG_SANDBOX)
 
240
  return 0;
 
241
#endif
 
242
 
 
243
  now = VbExGetTimer();
 
244
  while (audio->next_note < audio->note_count && now >= audio->play_until) {
 
245
    freq = audio->music_notes[audio->next_note].frequency;
 
246
    msec = audio->music_notes[audio->next_note].msec;
 
247
    audio->play_until += VbMsecToTicks(msec);
 
248
    audio->next_note++;
 
249
  }
 
250
 
 
251
  if (now >= audio->play_until) {
 
252
    looping = 0;
 
253
    freq = 0;
 
254
  }
 
255
 
 
256
  // Do action here.
 
257
  if (audio->background_beep) {
 
258
    if (audio->current_frequency != freq) {
 
259
      VbExBeep(0, freq);
 
260
      audio->current_frequency = freq;
 
261
    }
 
262
  } else if (freq && msec) {
 
263
    VbExBeep(msec, freq);
 
264
    now = VbExGetTimer();
 
265
  }
 
266
 
 
267
  audio->last_time = now;
 
268
  return looping;
 
269
}
 
270
 
 
271
/* Caller should call this prior to booting */
 
272
void VbAudioClose(VbAudioContext* audio) {
 
273
  VbExBeep(0,0);
 
274
  if (audio->free_notes_when_done)
 
275
    VbExFree(audio->music_notes);
 
276
}