static int occ_setup_sensor_attrs()

in occ/common.c [776:1079]


static int occ_setup_sensor_attrs(struct occ *occ)
{
	unsigned int i, s, num_attrs = 0;
	struct device *dev = occ->bus_dev;
	struct occ_sensors *sensors = &occ->sensors;
	struct occ_attribute *attr;
	struct temp_sensor_2 *temp;
	ssize_t (*show_temp)(struct device *, struct device_attribute *,
			     char *) = occ_show_temp_1;
	ssize_t (*show_freq)(struct device *, struct device_attribute *,
			     char *) = occ_show_freq_1;
	ssize_t (*show_power)(struct device *, struct device_attribute *,
			      char *) = occ_show_power_1;
	ssize_t (*show_caps)(struct device *, struct device_attribute *,
			     char *) = occ_show_caps_1_2;

	switch (sensors->temp.version) {
	case 1:
		num_attrs += (sensors->temp.num_sensors * 2);
		break;
	case 2:
		num_attrs += (sensors->temp.num_sensors * 4);
		show_temp = occ_show_temp_2;
		break;
	case 0x10:
		num_attrs += (sensors->temp.num_sensors * 5);
		show_temp = occ_show_temp_10;
		break;
	default:
		sensors->temp.num_sensors = 0;
	}

	switch (sensors->freq.version) {
	case 2:
		show_freq = occ_show_freq_2;
		fallthrough;
	case 1:
		num_attrs += (sensors->freq.num_sensors * 2);
		break;
	default:
		sensors->freq.num_sensors = 0;
	}

	switch (sensors->power.version) {
	case 2:
		show_power = occ_show_power_2;
		fallthrough;
	case 1:
		num_attrs += (sensors->power.num_sensors * 4);
		break;
	case 0xA0:
		num_attrs += (sensors->power.num_sensors * 16);
		show_power = occ_show_power_a0;
		break;
	default:
		sensors->power.num_sensors = 0;
	}

	switch (sensors->caps.version) {
	case 1:
		num_attrs += (sensors->caps.num_sensors * 7);
		break;
	case 3:
		show_caps = occ_show_caps_3;
		fallthrough;
	case 2:
		num_attrs += (sensors->caps.num_sensors * 8);
		break;
	default:
		sensors->caps.num_sensors = 0;
	}

	switch (sensors->extended.version) {
	case 1:
		num_attrs += (sensors->extended.num_sensors * 3);
		break;
	default:
		sensors->extended.num_sensors = 0;
	}

	occ->attrs = devm_kzalloc(dev, sizeof(*occ->attrs) * num_attrs,
				  GFP_KERNEL);
	if (!occ->attrs)
		return -ENOMEM;

	/* null-terminated list */
	occ->group.attrs = devm_kzalloc(dev, sizeof(*occ->group.attrs) *
					num_attrs + 1, GFP_KERNEL);
	if (!occ->group.attrs)
		return -ENOMEM;

	attr = occ->attrs;

	for (i = 0; i < sensors->temp.num_sensors; ++i) {
		s = i + 1;
		temp = ((struct temp_sensor_2 *)sensors->temp.data) + i;

		snprintf(attr->name, sizeof(attr->name), "temp%d_label", s);
		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_temp, NULL,
					     0, i);
		attr++;

		if (sensors->temp.version == 2 &&
		    temp->fru_type == OCC_FRU_TYPE_VRM) {
			snprintf(attr->name, sizeof(attr->name),
				 "temp%d_alarm", s);
		} else {
			snprintf(attr->name, sizeof(attr->name),
				 "temp%d_input", s);
		}

		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_temp, NULL,
					     1, i);
		attr++;

		if (sensors->temp.version > 1) {
			snprintf(attr->name, sizeof(attr->name),
				 "temp%d_fru_type", s);
			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
						     show_temp, NULL, 2, i);
			attr++;

			snprintf(attr->name, sizeof(attr->name),
				 "temp%d_fault", s);
			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
						     show_temp, NULL, 3, i);
			attr++;

			if (sensors->temp.version == 0x10) {
				snprintf(attr->name, sizeof(attr->name),
					 "temp%d_max", s);
				attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
							     show_temp, NULL,
							     4, i);
				attr++;
			}
		}
	}

	for (i = 0; i < sensors->freq.num_sensors; ++i) {
		s = i + 1;

		snprintf(attr->name, sizeof(attr->name), "freq%d_label", s);
		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_freq, NULL,
					     0, i);
		attr++;

		snprintf(attr->name, sizeof(attr->name), "freq%d_input", s);
		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_freq, NULL,
					     1, i);
		attr++;
	}

	if (sensors->power.version == 0xA0) {
		/*
		 * Special case for many-attribute power sensor. Split it into
		 * a sensor number per power type, emulating several sensors.
		 */
		for (i = 0; i < sensors->power.num_sensors; ++i) {
			unsigned int j;
			unsigned int nr = 0;

			s = (i * 4) + 1;

			for (j = 0; j < 4; ++j) {
				snprintf(attr->name, sizeof(attr->name),
					 "power%d_label", s);
				attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
							     show_power, NULL,
							     nr++, i);
				attr++;

				snprintf(attr->name, sizeof(attr->name),
					 "power%d_average", s);
				attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
							     show_power, NULL,
							     nr++, i);
				attr++;

				snprintf(attr->name, sizeof(attr->name),
					 "power%d_average_interval", s);
				attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
							     show_power, NULL,
							     nr++, i);
				attr++;

				snprintf(attr->name, sizeof(attr->name),
					 "power%d_input", s);
				attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
							     show_power, NULL,
							     nr++, i);
				attr++;

				s++;
			}
		}

		s = (sensors->power.num_sensors * 4) + 1;
	} else {
		for (i = 0; i < sensors->power.num_sensors; ++i) {
			s = i + 1;

			snprintf(attr->name, sizeof(attr->name),
				 "power%d_label", s);
			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
						     show_power, NULL, 0, i);
			attr++;

			snprintf(attr->name, sizeof(attr->name),
				 "power%d_average", s);
			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
						     show_power, NULL, 1, i);
			attr++;

			snprintf(attr->name, sizeof(attr->name),
				 "power%d_average_interval", s);
			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
						     show_power, NULL, 2, i);
			attr++;

			snprintf(attr->name, sizeof(attr->name),
				 "power%d_input", s);
			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
						     show_power, NULL, 3, i);
			attr++;
		}

		s = sensors->power.num_sensors + 1;
	}

	if (sensors->caps.num_sensors >= 1) {
		snprintf(attr->name, sizeof(attr->name), "power%d_label", s);
		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
					     0, 0);
		attr++;

		snprintf(attr->name, sizeof(attr->name), "power%d_cap", s);
		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
					     1, 0);
		attr++;

		snprintf(attr->name, sizeof(attr->name), "power%d_input", s);
		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
					     2, 0);
		attr++;

		snprintf(attr->name, sizeof(attr->name),
			 "power%d_cap_not_redundant", s);
		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
					     3, 0);
		attr++;

		snprintf(attr->name, sizeof(attr->name), "power%d_cap_max", s);
		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
					     4, 0);
		attr++;

		snprintf(attr->name, sizeof(attr->name), "power%d_cap_min", s);
		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
					     5, 0);
		attr++;

		snprintf(attr->name, sizeof(attr->name), "power%d_cap_user",
			 s);
		attr->sensor = OCC_INIT_ATTR(attr->name, 0644, show_caps,
					     occ_store_caps_user, 6, 0);
		attr++;

		if (sensors->caps.version > 1) {
			snprintf(attr->name, sizeof(attr->name),
				 "power%d_cap_user_source", s);
			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
						     show_caps, NULL, 7, 0);
			attr++;
		}
	}

	for (i = 0; i < sensors->extended.num_sensors; ++i) {
		s = i + 1;

		snprintf(attr->name, sizeof(attr->name), "extn%d_label", s);
		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
					     occ_show_extended, NULL, 0, i);
		attr++;

		snprintf(attr->name, sizeof(attr->name), "extn%d_flags", s);
		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
					     occ_show_extended, NULL, 1, i);
		attr++;

		snprintf(attr->name, sizeof(attr->name), "extn%d_input", s);
		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
					     occ_show_extended, NULL, 2, i);
		attr++;
	}

	/* put the sensors in the group */
	for (i = 0; i < num_attrs; ++i) {
		sysfs_attr_init(&occ->attrs[i].sensor.dev_attr.attr);
		occ->group.attrs[i] = &occ->attrs[i].sensor.dev_attr.attr;
	}

	return 0;
}