/* * Only for really core code. See moduleparam.h for the normal way. * * Force the alignment so the compiler doesn't space elements of the * obs_kernel_param "array" too far apart in .init.setup. */ #define __setup_param(str, unique_id, fn, early) \ static const char __setup_str_##unique_id[] __initconst \ __aligned(1) = str; \ static struct obs_kernel_param __setup_##unique_id \ __used __section(".init.setup") \ __aligned(__alignof__(struct obs_kernel_param)) \ = { __setup_str_##unique_id, fn, early }
/* * NOTE: __setup functions return values: * @fn returns 1 (or non-zero) if the option argument is "handled" * and returns 0 if the option argument is "not handled". */ #define __setup(str, fn) \ __setup_param(str, fn, fn, 0)
/* * NOTE: @fn is as per module_param, not __setup! * I.e., @fn returns 0 for no error or non-zero for error * (possibly @fn returns a -errno value, but it does not matter). * Emits warning if @fn returns non-zero. */ #define early_param(str, fn) \ __setup_param(str, fn, fn, 1)
/* early_param wrapper for setup_earlycon() */ staticint __init param_setup_earlycon(char *buf) { int err;
/* Just 'earlycon' is a valid param for devicetree and ACPI SPCR. */ if (!buf || !buf[0]) { if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) { earlycon_acpi_spcr_enable = true; return0; } elseif (!buf) { return early_init_dt_scan_chosen_stdout(); } }
/* early_param wrapper for setup_earlycon() */ staticint __init param_setup_earlycon(char *buf) { int err;
/* Just 'earlycon' is a valid param for devicetree and ACPI SPCR. */ if (!buf || !buf[0]) { if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) { earlycon_acpi_spcr_enable = true; return0; } elseif (!buf) { return early_init_dt_scan_chosen_stdout(); } }
/** * setup_earlycon - match and register earlycon console * @buf: earlycon param string * * Registers the earlycon console matching the earlycon specified * in the param string @buf. Acceptable param strings are of the form * <name>,io|mmio|mmio32|mmio32be,<addr>,<options> * <name>,0x<addr>,<options> * <name>,<options> * <name> * * Only for the third form does the earlycon setup() method receive the * <options> string in the 'options' parameter; all other forms set * the parameter to NULL. * * Returns 0 if an attempt to register the earlycon was made, * otherwise negative error code */ int __init setup_earlycon(char *buf) { conststructearlycon_id *match; bool empty_compatible = true;
if (!buf || !buf[0]) return -EINVAL;
if (console_is_registered(&early_con)) return -EALREADY;
again: for (match = __earlycon_table; match < __earlycon_table_end; match++) { size_t len = strlen(match->name);
if (strncmp(buf, match->name, len)) continue;
/* prefer entries with empty compatible */ if (empty_compatible && *match->compatible) continue;
if (buf[len]) { if (buf[len] != ',') continue; buf += len + 1; } else buf = NULL;
return register_earlycon(buf, match); }
if (empty_compatible) { empty_compatible = false; goto again; }
structearlycon_id { char name[15]; char name_term; /* In case compiler didn't '\0' term name */ char compatible[128]; int (*setup)(struct earlycon_device *, constchar *options); };
其中, name_term成员是为了name字符串以\0为结尾。
继续回到setup_earlycon函数:
/** * setup_earlycon - match and register earlycon console * @buf: earlycon param string * * Registers the earlycon console matching the earlycon specified * in the param string @buf. Acceptable param strings are of the form * <name>,io|mmio|mmio32|mmio32be,<addr>,<options> * <name>,0x<addr>,<options> * <name>,<options> * <name> * * Only for the third form does the earlycon setup() method receive the * <options> string in the 'options' parameter; all other forms set * the parameter to NULL. * * Returns 0 if an attempt to register the earlycon was made, * otherwise negative error code */ int __init setup_earlycon(char *buf) { conststructearlycon_id *match; bool empty_compatible = true;
if (!buf || !buf[0]) return -EINVAL;
if (console_is_registered(&early_con)) return -EALREADY;
again: for (match = __earlycon_table; match < __earlycon_table_end; match++) { size_t len = strlen(match->name);
if (strncmp(buf, match->name, len)) continue;
/* prefer entries with empty compatible */ if (empty_compatible && *match->compatible) continue;
if (buf[len]) { if (buf[len] != ',') continue; buf += len + 1; } else buf = NULL;
return register_earlycon(buf, match); }
if (empty_compatible) { empty_compatible = false; goto again; }
/** * uart_parse_earlycon - Parse earlycon options * @p: ptr to 2nd field (ie., just beyond '<name>,') * @iotype: ptr for decoded iotype (out) * @addr: ptr for decoded mapbase/iobase (out) * @options: ptr for <options> field; %NULL if not present (out) * * Decodes earlycon kernel command line parameters of the form: * * earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options> * * console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options> * * The optional form: * * earlycon=<name>,0x<addr>,<options> * * console=<name>,0x<addr>,<options> * * is also accepted; the returned @iotype will be %UPIO_MEM. * * Returns: 0 on success or -%EINVAL on failure */ intuart_parse_earlycon(char *p, unsignedchar *iotype, resource_size_t *addr, char **options) { if (strncmp(p, "mmio,", 5) == 0) { *iotype = UPIO_MEM; p += 5; } elseif (strncmp(p, "mmio16,", 7) == 0) { *iotype = UPIO_MEM16; p += 7; } elseif (strncmp(p, "mmio32,", 7) == 0) { *iotype = UPIO_MEM32; p += 7; } elseif (strncmp(p, "mmio32be,", 9) == 0) { *iotype = UPIO_MEM32BE; p += 9; } elseif (strncmp(p, "mmio32native,", 13) == 0) { *iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ? UPIO_MEM32BE : UPIO_MEM32; p += 13; } elseif (strncmp(p, "io,", 3) == 0) { *iotype = UPIO_PORT; p += 3; } elseif (strncmp(p, "0x", 2) == 0) { *iotype = UPIO_MEM; } else { return -EINVAL; }
/* * Before you replace it with kstrtoull(), think about options separator * (',') it will not tolerate */ *addr = simple_strtoull(p, NULL, 0); p = strchr(p, ','); if (p) p++;