Re: [PATCH RFC v1 1/2] bus: add Wiegand write-only GPIO driver

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

 



On 28/07/2022 11:17, Martin Zaťovič wrote:
> Wiegand is a communication protocol that is still widely used
> especially for access control applications. It utilizes two wires to
> transmit data - D0 and D1, the generic names of which are data-lo and
> data-hi.
> 
> Both data lines are initially pulled up. To send a bit of value 1, the
> D1 line is set low. Similarly to send a bit of value 0, the D0 line is
> set low. Standard Wiegand formats include 26, 36 and 37 bit and they
> reserve the first and last bits for parity. The first(MSB) parity bit
> is set to 1 if the parity of the first half of the payload is odd. The
> last(LSB) parity bit is set to 1 if the parity of the second half of
> the payload even.
> 
> The driver currently supports the 3 standard formats - 26, 36 and 37
> bits. When one of these formats is used, it automatically calculates
> the values of parity bits and appends them to the messages. It also
> offers to set a custom format. Using a custom format, the user is
> responsible for setting the parity bits. The driver offers setting of
> the following sysfs attributes:
> 
> 	pulse_len - length of the low pulse in usec; defaults to 50us
> 	interval_len - length of a whole bit(pulse_len + high phase)
> 	in usec; defaults to 50us
> 	frame_gap - length of the last bit of a frame(pulse_len +
> 	high phase); defaults to interval_len
> 	format - valid values are 0 for custom, 26, 36, 37
> 	custom_payload_len - can be set when using a custom format(0);
> 	0 means all bits of a message will be sent
> 
> Signed-off-by: Martin Zaťovič <m.zatovic1@xxxxxxxxx>
> ---
> The driver was tested on NXP Verdin iMX8MP Plus.
> 
> I would like to kindly ask a few questions:
> 1. Is debug printing of the data being transmitted a valid thing to do?
> Wiegand could potentially be used to transmit sensitive data which
> might get exposed by the debug mode.
> 2. The part of the code, where sysfs files are being created does not
> currently contain freeing of the ones already created on an error. Is
> it better to use goto jumps to free them and exit, or let the driver
> run without some of the attribute files?
> 
> If you have any suggestions to make this patch better, please let me
> know, I am eager to learn. I am very much new to this field, so any
> feedback will be aprreciated.
> ---
>  MAINTAINERS                |   6 +
>  drivers/bus/Kconfig        |  10 +
>  drivers/bus/Makefile       |   1 +
>  drivers/bus/wiegand-gpio.c | 661 +++++++++++++++++++++++++++++++++++++
>  drivers/bus/wiegand-gpio.h |  54 +++
>  5 files changed, 732 insertions(+)
>  create mode 100644 drivers/bus/wiegand-gpio.c
>  create mode 100644 drivers/bus/wiegand-gpio.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 64379c699903..9a519530e44e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -21586,6 +21586,12 @@ L:	linux-rtc@xxxxxxxxxxxxxxx
>  S:	Maintained
>  F:	drivers/rtc/rtc-sd3078.c
>  
> +WIEGAND WRITE-ONLY GPIO DRIVER
> +M:	Martin Zaťovič <m.zatovic1@xxxxxxxxx>
> +S:	Maintained
> +F:	drivers/bus/wiegand-gpio.c
> +F:	drivers/bus/wiegand-gpio.h
> +
>  WIIMOTE HID DRIVER
>  M:	David Rheinsberg <david.rheinsberg@xxxxxxxxx>
>  L:	linux-input@xxxxxxxxxxxxxxx
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index 7bfe998f3514..f7c7d3b24710 100644
> --- a/drivers/bus/Kconfig
> +++ b/drivers/bus/Kconfig
> @@ -231,6 +231,16 @@ config UNIPHIER_SYSTEM_BUS
>  	  Support for UniPhier System Bus, a simple external bus.  This is
>  	  needed to use on-board devices connected to UniPhier SoCs.
>  
> +config WIEGAND_GPIO
> +    tristate "GPIO-based wiegand master (write only)"
> +    depends on OF_GPIO
> +    help
> +      Say y here to enable a driver which uses GPIO pins to send
> +      Wiegand data. Say m to build it as module. Say n to disable
> +      building. The driver utilizes two data lines that need to be
> +      defined as outputs in the device tree - wiegand-data-hi and
> +      wiegand-data-lo.
> +
>  config VEXPRESS_CONFIG
>  	tristate "Versatile Express configuration bus"
>  	default y if ARCH_VEXPRESS
> diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
> index d90eed189a65..cc21530a441f 100644
> --- a/drivers/bus/Makefile
> +++ b/drivers/bus/Makefile
> @@ -36,6 +36,7 @@ obj-$(CONFIG_TI_SYSC)		+= ti-sysc.o
>  obj-$(CONFIG_TS_NBUS)		+= ts-nbus.o
>  obj-$(CONFIG_UNIPHIER_SYSTEM_BUS)	+= uniphier-system-bus.o
>  obj-$(CONFIG_VEXPRESS_CONFIG)	+= vexpress-config.o
> +obj-$(CONFIG_WIEGAND_GPIO)	+= wiegand-gpio.o
>  

This is confusing. You put it in bus, but you just added a single
driver, not a bus driver, right?

If it is not a bus driver, it goes to respective subsystem.

> +DEVICE_ATTR_RW(pulse_len);
> +DEVICE_ATTR_RW(interval_len);
> +DEVICE_ATTR_RW(frame_gap);
> +DEVICE_ATTR_RW(format);
> +DEVICE_ATTR_RW(payload_len);
> +
> +static int wiegand_gpio_dev_probe(struct platform_device *pdev)
> +{
> +	int rc;
> +	struct wiegand_gpio_device *wiegand_gpio;
> +	struct wiegand_gpio_platform_data *pdata = pdev->dev.platform_data;
> +
> +	if (!pdata) {
> +		if (IS_ERR(pdata))
> +			return PTR_ERR(pdata);

Why? How is this going to bind? Who provides pdata? Who provides error
pdata?!?

> +	}
> +
> +	wiegand_gpio = kzalloc(sizeof(struct wiegand_gpio_device), GFP_KERNEL);

devm, sizeof(*wiegand_gpio)

> +	if (!wiegand_gpio)
> +		return -ENOMEM;
> +
> +	wiegand_gpio->dev = &pdev->dev;
> +
> +	/* Initialize character device */
> +	cdev_init(&wiegand_gpio->cdev, &wiegand_gpio_fops);
> +	wiegand_gpio->cdev.owner = THIS_MODULE;
> +
> +	rc = cdev_add(&wiegand_gpio->cdev, MKDEV(MAJOR(base_devno),
> +				pdev->id == -1 ? 0 : pdev->id), 1);
> +	if (rc < 0) {
> +		dev_err(&pdev->dev, "Failed to allocate cdev: %d\n", rc);
> +		kfree(wiegand_gpio);
> +		return rc;
> +	}
> +
> +	wiegand_gpio->dev->devt = wiegand_gpio->cdev.dev;
> +	mutex_init(&wiegand_gpio->mutex);
> +
> +	/* Get GPIO lines using device tree bindings. */
> +	wiegand_gpio->gpio_data_lo = devm_gpiod_get(wiegand_gpio->dev,
> +			"wiegand-data-lo", GPIOD_OUT_HIGH);
> +	if (IS_ERR(wiegand_gpio->gpio_data_lo)) {
> +		dev_info(wiegand_gpio->dev,
> +			"Failed to get wiegand-data-lo pin.\n");
> +		return PTR_ERR(wiegand_gpio->gpio_data_lo);

No, return dev_err_probe().

> +	}
> +	wiegand_gpio->gpio_data_hi = devm_gpiod_get(wiegand_gpio->dev,
> +			"wiegand-data-hi", GPIOD_OUT_HIGH);
> +	if (IS_ERR(wiegand_gpio->gpio_data_hi)) {
> +		dev_info(wiegand_gpio->dev,
> +			"Failed to get wiegand-data-hi pin.\n");
> +		return PTR_ERR(wiegand_gpio->gpio_data_hi);

return dev_err_probe()

> +	}
> +
> +	memcpy(&wiegand_gpio->setup, &WIEGAND_SETUP,
> +			sizeof(struct wiegand_setup));
> +
> +	platform_set_drvdata(pdev, wiegand_gpio);
> +
> +	dev_info(&pdev->dev, "devno=%d:%d\n",
> +		 MAJOR(wiegand_gpio->dev->devt),
> +		 MINOR(wiegand_gpio->dev->devt));
> +
> +	rc = device_create_file(wiegand_gpio->dev, &dev_attr_pulse_len);
> +	rc |= device_create_file(wiegand_gpio->dev, &dev_attr_interval_len);
> +	rc |= device_create_file(wiegand_gpio->dev, &dev_attr_frame_gap);
> +	rc |= device_create_file(wiegand_gpio->dev, &dev_attr_format);
> +	rc |= device_create_file(wiegand_gpio->dev,
> +				&dev_attr_payload_len);
> +	if (rc != 0)
> +		dev_warn(&pdev->dev,
> +				"Failed to register attribute files(%d)\n", rc);
> +
> +	return 0;
> +}
> +
> +static int wiegand_gpio_dev_remove(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct wiegand_gpio_device *wiegand_gpio = platform_get_drvdata(pdev);
> +
> +	device_remove_file(dev, &dev_attr_pulse_len);
> +	device_remove_file(dev, &dev_attr_interval_len);
> +	device_remove_file(dev, &dev_attr_frame_gap);
> +	device_remove_file(dev, &dev_attr_format);
> +	device_remove_file(dev, &dev_attr_payload_len);
> +	cdev_del(&wiegand_gpio->cdev);
> +	kfree(wiegand_gpio);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id wiegand_gpio_dt_idtable[] = {
> +	{ .compatible = "wiegand-gpio" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, wiegand_gpio_dt_idtable);
> +#endif
> +
> +static struct platform_driver wiegand_gpio_driver = {
> +	.probe		= wiegand_gpio_dev_probe,
> +	.remove		= wiegand_gpio_dev_remove,
> +	.driver		= {
> +		.owner	= THIS_MODULE,

This is not needed. Do you see it in any driver?

> +		.name	= "wiegand-gpio",
> +		.of_match_table = of_match_ptr(wiegand_gpio_dt_idtable),
> +	}
> +};
> +MODULE_ALIAS("platform:wiegand-gpio");
> +

Best regards,
Krzysztof



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux