1 // Copyright 2020 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 //! `sound_card_init` is an user space binary to perform sound card initialization during boot time.
5 //!
6 //!
7 //! # Arguments
8 //!
9 //! * `sound_card_id` - The sound card name, ex: sofcmlmax98390d.
10 //!
11 //! Given the `sound_card_id`, this binary parses the CONF_DIR/<sound_card_id>.yaml to perform per sound card initialization.
12 //! The upstart job of `sound_card_init` is started by the udev event specified in /lib/udev/rules.d/99-sound_card_init.rules.
13 #![deny(missing_docs)]
14 use std::env;
15 use std::error;
16 use std::fmt;
17 use std::process;
18 use std::string::String;
19
20 use getopts::Options;
21 use remain::sorted;
22 use sys_util::{error, info, syslog};
23
24 use amp::AmpBuilder;
25 use dsm::utils::run_time;
26
27 type Result<T> = std::result::Result<T, Error>;
28
29 #[derive(Default)]
30 struct Args {
31 pub sound_card_id: String,
32 pub conf: String,
33 }
34
35 #[sorted]
36 #[derive(Debug)]
37 enum Error {
38 MissingOption(String),
39 ParseArgsFailed(getopts::Fail),
40 }
41
42 impl error::Error for Error {}
43
44 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result45 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46 use Error::*;
47 match self {
48 MissingOption(option) => write!(f, "missing required option: {}", option),
49 ParseArgsFailed(e) => write!(f, "parse_args failed: {}", e),
50 }
51 }
52 }
53
print_usage(opts: &Options)54 fn print_usage(opts: &Options) {
55 let brief = "Usage: sound_card_init [options]".to_owned();
56 print!("{}", opts.usage(&brief));
57 }
58
parse_args() -> Result<Args>59 fn parse_args() -> Result<Args> {
60 let mut opts = Options::new();
61 opts.optopt("", "id", "sound card id", "ID");
62 opts.optopt(
63 "",
64 "conf",
65 "the config file name. It should be $(cros_config /audio/main sound-card-init-conf)",
66 "CONFIG_NAME",
67 );
68 opts.optflag("h", "help", "print help menu");
69 let matches = opts
70 .parse(&env::args().collect::<Vec<_>>()[1..])
71 .map_err(|e| {
72 print_usage(&opts);
73 Error::ParseArgsFailed(e)
74 })?;
75
76 if matches.opt_present("h") {
77 print_usage(&opts);
78 process::exit(0);
79 }
80
81 let sound_card_id = matches
82 .opt_str("id")
83 .ok_or_else(|| Error::MissingOption("id".to_owned()))
84 .map_err(|e| {
85 print_usage(&opts);
86 e
87 })?;
88
89 let conf = matches
90 .opt_str("conf")
91 .ok_or_else(|| Error::MissingOption("conf".to_owned()))
92 .map_err(|e| {
93 print_usage(&opts);
94 e
95 })?;
96
97 Ok(Args {
98 sound_card_id,
99 conf,
100 })
101 }
102
103 /// Parses the CONF_DIR/${args.conf}.yaml and starts the boot time calibration.
sound_card_init(args: &Args) -> std::result::Result<(), Box<dyn error::Error>>104 fn sound_card_init(args: &Args) -> std::result::Result<(), Box<dyn error::Error>> {
105 info!("sound_card_id: {}, conf:{}", args.sound_card_id, args.conf);
106 AmpBuilder::new(&args.sound_card_id, &args.conf)
107 .build()?
108 .boot_time_calibration()?;
109
110 Ok(())
111 }
112
main()113 fn main() {
114 syslog::init().expect("failed to initialize syslog");
115 let args = match parse_args() {
116 Ok(args) => args,
117 Err(e) => {
118 error!("failed to parse arguments: {}", e);
119 return;
120 }
121 };
122
123 match sound_card_init(&args) {
124 Ok(_) => info!("sound_card_init finished successfully."),
125 Err(e) => error!("sound_card_init: {}", e),
126 }
127
128 if let Err(e) = run_time::now_to_file(&args.sound_card_id) {
129 error!("failed to create sound_card_init run time file: {}", e);
130 }
131 }
132