Пример #1
0
static bool check_and_parse_filter(struct be_acct_req *data,
                                   const char *filter,
                                   const char *extra)
{
    /* We will use sizeof() to determine the length of a string so we don't
     * call strlen over and over again with each request. Not a bottleneck,
     * but unnecessary and simple to avoid. */
    static struct {
        const char *name;
        size_t lenght;
        uint32_t type;
    } types[] = {FILTER_TYPE("name", BE_FILTER_NAME),
                 FILTER_TYPE("idnumber", BE_FILTER_IDNUM),
                 FILTER_TYPE(DP_SEC_ID, BE_FILTER_SECID),
                 FILTER_TYPE(DP_CERT, BE_FILTER_CERT),
                 FILTER_TYPE(DP_WILDCARD, BE_FILTER_WILDCARD),
                 {0, 0, 0}};
    int i;

    if (filter == NULL) {
        return false;
    }

    for (i = 0; types[i].name != NULL; i++) {
        if (strncmp(filter, types[i].name, types[i].lenght) == 0) {
            data->filter_type = types[i].type;
            data->filter_value = &filter[types[i].lenght];
            data->extra_value = extra;
            return true;
        }
    }

    if (strcmp(filter, ENUM_INDICATOR) == 0) {
        data->filter_type = BE_FILTER_ENUM;
        data->filter_value = NULL;
        data->extra_value = NULL;
        return true;
    }

    return false;
}
Пример #2
0
static int sun4i_ts_probe(struct platform_device *pdev)
{
	struct sun4i_ts_data *ts;
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct device *hwmon;
	int error;
	u32 reg;
	bool ts_attached;
	u32 tp_sensitive_adjust = 15;
	u32 filter_type = 1;

	ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
	if (!ts)
		return -ENOMEM;

	ts->dev = dev;
	ts->ignore_fifo_data = true;
	ts->temp_data = -1;
	if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts")) {
		/* Allwinner SDK has temperature (C) = (value / 6) - 271 */
		ts->temp_offset = 271000;
		ts->temp_step = 167;
	} else if (of_device_is_compatible(np, "allwinner,sun4i-a10-ts")) {
		/*
		 * The A10 temperature sensor has quite a wide spread, these
		 * parameters are based on the averaging of the calibration
		 * results of 4 completely different boards, with a spread of
		 * temp_step from 0.096 - 0.170 and temp_offset from 176 - 331.
		 */
		ts->temp_offset = 257000;
		ts->temp_step = 133;
	} else {
		/*
		 * The user manuals do not contain the formula for calculating
		 * the temperature. The formula used here is from the AXP209,
		 * which is designed by X-Powers, an affiliate of Allwinner:
		 *
		 *     temperature (C) = (value * 0.1) - 144.7
		 *
		 * Allwinner does not have any documentation whatsoever for
		 * this hardware. Moreover, it is claimed that the sensor
		 * is inaccurate and cannot work properly.
		 */
		ts->temp_offset = 144700;
		ts->temp_step = 100;
	}

	ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
	if (ts_attached) {
		ts->input = devm_input_allocate_device(dev);
		if (!ts->input)
			return -ENOMEM;

		ts->input->name = pdev->name;
		ts->input->phys = "sun4i_ts/input0";
		ts->input->open = sun4i_ts_open;
		ts->input->close = sun4i_ts_close;
		ts->input->id.bustype = BUS_HOST;
		ts->input->id.vendor = 0x0001;
		ts->input->id.product = 0x0001;
		ts->input->id.version = 0x0100;
		ts->input->evbit[0] =  BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
		__set_bit(BTN_TOUCH, ts->input->keybit);
		input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
		input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
		input_set_drvdata(ts->input, ts);
	}

	ts->base = devm_ioremap_resource(dev,
			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
	if (IS_ERR(ts->base))
		return PTR_ERR(ts->base);

	ts->irq = platform_get_irq(pdev, 0);
	error = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts);
	if (error)
		return error;

	/*
	 * Select HOSC clk, clkin = clk / 6, adc samplefreq = clkin / 8192,
	 * t_acq = clkin / (16 * 64)
	 */
	writel(ADC_CLK_SEL(0) | ADC_CLK_DIV(2) | FS_DIV(7) | T_ACQ(63),
	       ts->base + TP_CTRL0);

	/*
	 * tp_sensitive_adjust is an optional property
	 * tp_mode = 0 : only x and y coordinates, as we don't use dual touch
	 */
	of_property_read_u32(np, "allwinner,tp-sensitive-adjust",
			     &tp_sensitive_adjust);
	writel(TP_SENSITIVE_ADJUST(tp_sensitive_adjust) | TP_MODE_SELECT(0),
	       ts->base + TP_CTRL2);

	/*
	 * Enable median and averaging filter, optional property for
	 * filter type.
	 */
	of_property_read_u32(np, "allwinner,filter-type", &filter_type);
	writel(FILTER_EN(1) | FILTER_TYPE(filter_type), ts->base + TP_CTRL3);

	/* Enable temperature measurement, period 1953 (2 seconds) */
	writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR);

	/*
	 * Set stylus up debounce to aprox 10 ms, enable debounce, and
	 * finally enable tp mode.
	 */
	reg = STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1);
	if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts"))
		reg |= SUN6I_TP_MODE_EN(1);
	else
		reg |= TP_MODE_EN(1);
	writel(reg, ts->base + TP_CTRL1);

	/*
	 * The thermal core does not register hwmon devices for DT-based
	 * thermal zone sensors, such as this one.
	 */
	hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
						       ts, sun4i_ts_groups);
	if (IS_ERR(hwmon))
		return PTR_ERR(hwmon);

	devm_thermal_zone_of_sensor_register(ts->dev, 0, ts, &sun4i_ts_tz_ops);

	writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);

	if (ts_attached) {
		error = input_register_device(ts->input);
		if (error) {
			writel(0, ts->base + TP_INT_FIFOC);
			return error;
		}
	}

	platform_set_drvdata(pdev, ts);
	return 0;
}
Пример #3
0
int port_filter_apply(port_t *port, int value) {
    int i, *tmp_values;

    int len = port->filter_len;

    if (len >= port->filter_width) {
        // TODO this could be managed as a ring buffer for better performance

        /* shift filter values to left one place,
         * making space for the new value */
        for (i = 0; i < len - 1; i++) {
            port->filter_values[i] = port->filter_values[i + 1];
        }
        port->filter_values[len - 1] = value;
    }
    else {
        port->filter_values[len = port->filter_len++] = value;
    }

    if (len < 2) {
        return value; /* not enough values for filtering */
    }

    if (port->type == PORT_TYPE_NUMBER) {
        switch (FILTER_TYPE(port)) {
            case FILTER_TYPE_MEDIAN: {
                /* copy the values to a temporary buffer, so that they can be sorted out-of-place */
                tmp_values = malloc(sizeof(int) * len);
                memcpy(tmp_values, port->filter_values, sizeof(int) * len);
                qsort(tmp_values, len, sizeof(int), compare_numbers);
                value = tmp_values[len / 2];
                free(tmp_values);

                return value;
            }

            case FILTER_TYPE_AVERAGE: {
                int avg_value = 0;
                for (i = 0; i < len; i++) {
                    avg_value += port->filter_values[i];
                }

                return avg_value / len;
            }

            default:
                return value;
        }
    }
    else { /* assuming port->type == PORT_TYPE_BOOLEAN */
        // TODO a better approach would be to select an evenly-distributed
        // set of values (e.g. equal to the debounce factor)

        /* simply choose whatever the majority says */
        int counts[2] = {0 /* false */ , 0 /* true */};

        for (i = 0; i < len; i++) {
            counts[port->filter_values[i] & 1]++;
        }

        return counts[1] >= counts[0];
    }
}
Пример #4
0
void port_load(port_t *port, char *data) {
    char *base_ptr = data + CONFIG_OFFS_PORT_BASE + CONFIG_PORT_SIZE * port->port_no;
    char *expr_ptr = data + CONFIG_OFFS_STR_BASE;

    /* description */
    memcpy(port->description, base_ptr + CONFIG_OFFS_PORT_DESC, PORT_MAX_DESC_LEN);
    port->description[PORT_MAX_DESC_LEN - 1] = 0;

    /* unit */
    memcpy(port->unit, base_ptr + CONFIG_OFFS_PORT_UNIT, PORT_MAX_UNIT_LEN);
    port->unit[PORT_MAX_UNIT_LEN - 1] = 0;

    /* flags */
    memcpy(&port->flags, base_ptr + CONFIG_OFFS_PORT_FLAGS, 4);

    /* value */
    memcpy(&port->value, base_ptr + CONFIG_OFFS_PORT_VALUE, 4);

    /* filter */
    port->filter_values = NULL;
    port->filter_width = 0;
    if (!IS_OUTPUT(port)) {
        memcpy(&port->filter_width, base_ptr + CONFIG_OFFS_PORT_FWIDTH, 4);
        if (!port->filter_width) {
            port->filter_width = 2;
        }
        port_filter_set(port, FILTER_TYPE(port), port->filter_width);
    }

    /* custom data */
    memcpy(port->data, base_ptr + CONFIG_OFFS_PORT_DATA, PORT_CUSTOM_DATA_LEN);

    int expr_offs;
    int len;

    port->sexpr = NULL;
    port->expr = NULL;
    port->stransform_write = NULL;
    port->transform_write = NULL;
    port->stransform_read = NULL;
    port->transform_read = NULL;

    if (IS_OUTPUT(port)) {
        /* value expression */
        memcpy(&expr_offs, base_ptr + CONFIG_OFFS_PORT_EXPR, 4);
        if (expr_offs) {
            len = strlen(expr_ptr + expr_offs);
            port->sexpr = malloc(len + 1);
            strcpy(port->sexpr, expr_ptr + expr_offs);
            /* the expression will be parsed later,
             * after all ports will have been loaded */
        }

        /* write transform */
        memcpy(&expr_offs, base_ptr + CONFIG_OFFS_PORT_TRANS_W, 4);
        if (expr_offs) {
            len = strlen(expr_ptr + expr_offs);
            port->stransform_write = malloc(len + 1);
            strcpy(port->stransform_write, expr_ptr + expr_offs);
            /* the expression will be parsed later,
             * after all ports will have been loaded */
        }
    }

    /* read transform */
    memcpy(&expr_offs, base_ptr + CONFIG_OFFS_PORT_TRANS_R, 4);
    if (expr_offs) {
        len = strlen(expr_ptr + expr_offs);
        port->stransform_read = malloc(len + 1);
        strcpy(port->stransform_read, expr_ptr + expr_offs);
        /* the expression will be parsed later,
         * after all ports will have been loaded */
    }

    DEBUG("port %s loaded: description=\"%s\", unit=\"%s\", expression=\"%s\", transform_w=\"%s\", transform_r=\"%s\", flags=0x%08X",
            port->id, port->description, port->unit, port->sexpr ? port->sexpr : "",
            port->stransform_write ? port->stransform_write : "", port->stransform_read ? port->stransform_read : "",
            port->flags);

    /* sequence */
    port->sequence_pos = -1;

    if (port->configure) {
        DEBUG("configuring port %s", port->id);
        port->configure(port);
    }

    if (IS_OUTPUT(port)) {
        if (IS_PERSISTED(port)) {
            port->value = port->value && 1;
            DEBUG("setting port %s to persisted value %d", port->id, port->value);
        }
        else {
            port->value = IS_PULL_UP(port) && 1;
            DEBUG("setting port %s to pull value %d", port->id, port->value);
        }

        port_set_value(port, port->value);
    }
    else { /* input */
        int value = port->read_value(port);
        if (value != UNDEFINED_VALUE) {
            port->value = value;
            if (port->transform_read) {
                port->value = expr_eval(port->transform_read);
            }
            if (FILTER_TYPE(port) && !IS_OUTPUT(port)) {
                port->value = port_filter_apply(port, port->value);
            }
            DEBUG("initialized port %s with read value %d", port->id, port->value && 1);
        }
        else {
            port->value = 0;
            DEBUG("initialized port %s with value 0", port->id);
        }
    }
}
Пример #5
0
static int sun4i_ts_probe(struct platform_device *pdev)
{
	struct sun4i_ts_data *ts;
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct device *hwmon;
	int error;
	bool ts_attached;

	ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
	if (!ts)
		return -ENOMEM;

	ts->dev = dev;
	ts->ignore_fifo_data = true;
	ts->temp_data = -1;

	ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
	if (ts_attached) {
		ts->input = devm_input_allocate_device(dev);
		if (!ts->input)
			return -ENOMEM;

		ts->input->name = pdev->name;
		ts->input->phys = "sun4i_ts/input0";
		ts->input->open = sun4i_ts_open;
		ts->input->close = sun4i_ts_close;
		ts->input->id.bustype = BUS_HOST;
		ts->input->id.vendor = 0x0001;
		ts->input->id.product = 0x0001;
		ts->input->id.version = 0x0100;
		ts->input->evbit[0] =  BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
		__set_bit(BTN_TOUCH, ts->input->keybit);
		input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
		input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
		input_set_drvdata(ts->input, ts);
	}

	ts->base = devm_ioremap_resource(dev,
			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
	if (IS_ERR(ts->base))
		return PTR_ERR(ts->base);

	ts->irq = platform_get_irq(pdev, 0);
	error = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts);
	if (error)
		return error;

	/*
	 * Select HOSC clk, clkin = clk / 6, adc samplefreq = clkin / 8192,
	 * t_acq = clkin / (16 * 64)
	 */
	writel(ADC_CLK_SEL(0) | ADC_CLK_DIV(2) | FS_DIV(7) | T_ACQ(63),
	       ts->base + TP_CTRL0);

	/*
	 * sensitive_adjust = 15 : max, which is not all that sensitive,
	 * tp_mode = 0 : only x and y coordinates, as we don't use dual touch
	 */
	writel(TP_SENSITIVE_ADJUST(15) | TP_MODE_SELECT(0),
	       ts->base + TP_CTRL2);

	/* Enable median filter, type 1 : 5/3 */
	writel(FILTER_EN(1) | FILTER_TYPE(1), ts->base + TP_CTRL3);

	/* Enable temperature measurement, period 1953 (2 seconds) */
	writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR);

	/*
	 * Set stylus up debounce to aprox 10 ms, enable debounce, and
	 * finally enable tp mode.
	 */
	writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1),
	       ts->base + TP_CTRL1);

	hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
						       ts, sun4i_ts_groups);
	if (IS_ERR(hwmon))
		return PTR_ERR(hwmon);

	writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);

	if (ts_attached) {
		error = input_register_device(ts->input);
		if (error) {
			writel(0, ts->base + TP_INT_FIFOC);
			return error;
		}
	}

	platform_set_drvdata(pdev, ts);
	return 0;
}