Re: [PATCH 4/4] ACPI: NHLT: Add query functions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2023-07-12 5:48 PM, Andy Shevchenko wrote:
On Wed, Jul 12, 2023 at 11:10:48AM +0200, Cezary Rojewski wrote:

...

+bool acpi_nhlt_endpoint_match(const struct acpi_nhlt_endpoint *ep,
+			      int link_type, int dev_type, int dir, int bus_id)
+{
+	return ep &&
+	       (link_type < 0 || ep->link_type == link_type) &&
+	       (dev_type < 0 || ep->device_type == dev_type) &&
+	       (dir < 0 || ep->direction == dir) &&
+	       (bus_id < 0 || ep->virtual_bus_id == bus_id);

I think you can split these for better reading.

	if (!ep)
		return false;

	if (link_type >= 0 && ep->link_type != link_type)
		return false;

	if (dev_type >= 0 && ep->device_type != dev_type)
		return false;

	if (dir >= 0 && ep->direction != dir)
		return false;

	if (bus_id >= 0 && ep->virtual_bus_id != bus_id)
		return false;

	return true;

Yes, much more lines, but readability is better in my opinion.
I also believe that code generation on x86_64 will be the same.

While I favor readability over less lines of code, I do not think splitting the conditions makes it easier in this case. Perhaps reverse-christmas-tree? Pivoted around '<'.

	return ep &&
	       (link_type < 0 || ep->link_type == link_type) &&
	       (dev_type < 0 || ep->device_type == dev_type) &&
	       (bus_id < 0 || ep->virtual_bus_id == bus_id) &&
	       (dir < 0 || ep->direction == dir);

In general I'd like to distinguish between conditions that one _has to_ read and understand and those which reader _may_ pass by. Here, we are checking description of an endpoint for equality. Nothing more, nothing less.

+}

...

+struct acpi_nhlt_endpoint *
+acpi_nhlt_find_endpoint(const struct acpi_table_nhlt *tb,
+			int link_type, int dev_type, int dir, int bus_id)
+{
+	struct acpi_nhlt_endpoint *ep;

+	if (!tb)
+		return ERR_PTR(-EINVAL);

Just wondering how often we will have a caller that supplies NULL for tb.

Depends on kernel's philosophy on public API. In general, public API should defend themselves from harmful and illegal callers. However, in low level areas 'illegal' is sometimes mistaken with illogical. In such cases double safety can be dropped.

Or, perhaps you were discussing return value here and ERR_PTR(-EINVAL) could be replaced by something else or even NULL.

+	for_each_nhlt_endpoint(tb, ep)
+		if (acpi_nhlt_endpoint_match(ep, link_type, dev_type, dir, bus_id))
+			return ep;
+	return NULL;
+}

...

+struct acpi_nhlt_format_config *
+acpi_nhlt_endpoint_find_fmtcfg(const struct acpi_nhlt_endpoint *ep,
+			       u16 ch, u32 rate, u16 vbps, u16 bps)
+{
+	struct acpi_nhlt_wave_extensible *wav;
+	struct acpi_nhlt_format_config *fmt;

+	if (!ep)
+		return ERR_PTR(-EINVAL);

Similar Q as above.

+	for_each_nhlt_endpoint_fmtcfg(ep, fmt) {
+		wav = &fmt->format;
+
+		if (wav->channel_count == ch &&
+		    wav->valid_bits_per_sample == vbps &&
+		    wav->bits_per_sample == bps &&
+		    wav->samples_per_sec == rate)

Also can be split, but this one readable in the original form.

As order does not really matter here, perhaps reverse-christmas-tree to improve readability?

		if (wav->valid_bits_per_sample == vpbs &&
		    wav->samples_per_sec == rate &&
		    wav->bits_per_sample == bps &&
		    wav->channel_count == ch)

+			return fmt;
+	}
+
+	return NULL;
+}

...

+struct acpi_nhlt_format_config *
+acpi_nhlt_find_fmtcfg(const struct acpi_table_nhlt *tb,
+		      int link_type, int dev_type, int dir, int bus_id,
+		      u16 ch, u32 rate, u16 vbps, u16 bps)
+{
+	struct acpi_nhlt_format_config *fmt;
+	struct acpi_nhlt_endpoint *ep;

+	if (!tb)
+		return ERR_PTR(-EINVAL);

Same as above.
Looking at them, wouldn't simply returning NULL suffice?

+	for_each_nhlt_endpoint(tb, ep) {
+		if (!acpi_nhlt_endpoint_match(ep, link_type, dev_type, dir, bus_id))
+			continue;
+
+		fmt = acpi_nhlt_endpoint_find_fmtcfg(ep, ch, rate, vbps, bps);
+		if (fmt)
+			return fmt;
+	}
+
+	return NULL;
+}

...

+int acpi_nhlt_endpoint_dmic_count(const struct acpi_nhlt_endpoint *ep)
+{
+	struct acpi_nhlt_vendor_mic_devcfg *vendor_cfg;
+	struct acpi_nhlt_format_config *fmt;
+	struct acpi_nhlt_mic_devcfg *devcfg;
+	u16 max_ch = 0;
+
+	if (!ep || ep->link_type != ACPI_NHLT_PDM)
+		return -EINVAL;
+
+	/* Find max number of channels based on formats configuration. */
+	for_each_nhlt_endpoint_fmtcfg(ep, fmt)
+		max_ch = max(fmt->format.channel_count, max_ch);
+
+	/* If @ep not a mic array, fallback to channels count. */
+	devcfg = acpi_nhlt_endpoint_mic_devcfg(ep);
+	if (!devcfg || devcfg->config_type != ACPI_NHLT_CONFIG_TYPE_MIC_ARRAY)
+		return max_ch;
+
+	switch (devcfg->array_type) {
+	case ACPI_NHLT_SMALL_LINEAR_2ELEMENT:
+	case ACPI_NHLT_BIG_LINEAR_2ELEMENT:
+		return 2;
+
+	case ACPI_NHLT_FIRST_GEOMETRY_LINEAR_4ELEMENT:
+	case ACPI_NHLT_PLANAR_LSHAPED_4ELEMENT:
+	case ACPI_NHLT_SECOND_GEOMETRY_LINEAR_4ELEMENT:
+		return 4;
+
+	case ACPI_NHLT_VENDOR_DEFINED:
+		vendor_cfg = acpi_nhlt_endpoint_vendor_mic_devcfg(ep);
+		if (!vendor_cfg)
+			return -EINVAL;
+		return vendor_cfg->num_mics;
+
+	default:

+		pr_warn("undefined mic array type: %#x\n", devcfg->array_type);

Is this function can ever be called without backing device? If not,
I would supply (ACPI?) device pointer and use dev_warn() instead.

But I'm not sure about this. Up to you, folks.

Given what's our there in the market I wouldn't say it's impossible to encounter such scenario. Could you elaborate on what you meant by "supply device pointer"?

+		return max_ch;
+	}
+}




[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]
  Powered by Linux