lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 17 Jan 2018 14:42:19 +0100
From:   Greg KH <greg@...ah.com>
To:     ShuFanLee <leechu729@...il.com>
Cc:     heikki.krogerus@...ux.intel.com, cy_huang@...htek.com,
        shufan_lee@...htek.com, linux-kernel@...r.kernel.org,
        linux-usb@...r.kernel.org
Subject: Re: [PATCH] USB TYPEC: RT1711H Type-C Chip Driver

On Wed, Jan 10, 2018 at 02:59:12PM +0800, ShuFanLee wrote:
> From: ShuFanLee <shufan_lee@...htek.com>
> 
> Richtek RT1711H Type-C chip driver that works with
> Type-C Port Controller Manager to provide USB PD and
> USB Type-C functionalities.
> 
> Signed-off-by: ShuFanLee <shufan_lee@...htek.com>

Minor review of your main structure and your debugfs code and other
stuff, all of which need work:

> ---
>  .../devicetree/bindings/usb/richtek,rt1711h.txt    |   38 +
>  arch/arm64/boot/dts/hisilicon/rt1711h.dtsi         |   11 +
>  drivers/usb/typec/Kconfig                          |    2 +
>  drivers/usb/typec/Makefile                         |    1 +
>  drivers/usb/typec/rt1711h/Kconfig                  |    7 +
>  drivers/usb/typec/rt1711h/Makefile                 |    2 +
>  drivers/usb/typec/rt1711h/rt1711h.c                | 2241 ++++++++++++++++++++
>  drivers/usb/typec/rt1711h/rt1711h.h                |  300 +++
>  8 files changed, 2602 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/usb/richtek,rt1711h.txt
>  create mode 100644 arch/arm64/boot/dts/hisilicon/rt1711h.dtsi
>  create mode 100644 drivers/usb/typec/rt1711h/Kconfig
>  create mode 100644 drivers/usb/typec/rt1711h/Makefile
>  create mode 100644 drivers/usb/typec/rt1711h/rt1711h.c
>  create mode 100644 drivers/usb/typec/rt1711h/rt1711h.h
> 
> diff --git a/Documentation/devicetree/bindings/usb/richtek,rt1711h.txt b/Documentation/devicetree/bindings/usb/richtek,rt1711h.txt
> new file mode 100644
> index 0000000..c28299c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/usb/richtek,rt1711h.txt
> @@ -0,0 +1,38 @@
> +Richtek RT1711H Type-C Port Controller.
> +
> +Required properties:
> +- compatible : Must be "richtek,typec_rt1711h";
> +- reg : Must be 0x4e, it's default slave address of RT1711H.
> +- rt,intr_gpio : IRQ GPIO pin that's connected to RT1711H interrupt.
> +
> +Optional node:
> +- rt,name : Name used for registering IRQ and creating kthread.
> +	    If this property is not specified, "default" will be applied.
> +- rt,def_role : Default port role (TYPEC_SINK(0) or TYPEC_SOURCE(1)).
> +		Set to TYPEC_NO_PREFERRED_ROLE(-1) if no default role.
> +		If this property is not specified, TYPEC_SINK will be applied.
> +- rt,port_type : Port type (TYPEC_PORT_DFP(0), TYPEC_PORT_UFP(1),
> +		 or TYPEC_PORT_DRP(2)). If this property is not specified,
> +		 TYPEC_PORT_DRP will be applied.
> +- rt,max_snk_mv : Maximum acceptable sink voltage in mV.
> +		  If this property is not specified, 5000mV will be applied.
> +- rt,max_snk_ma : Maximum sink current in mA.
> +		  If this property is not specified, 3000mA will be applied.
> +- rt,max_snk_mw : Maximum required sink power in mW.
> +		  If this property is not specified, 15000mW will be applied.
> +- rt,operating_snk_mw : Required operating sink power in mW.
> +			If this property is not specified,
> +			2500mW will be applied.
> +- rt,try_role_hw : True if try.{Src,Snk} is implemented in hardware.
> +		   If this property is not specified, False will be applied.
> +
> +Example:
> +rt1711h@4e {
> +	status = "ok";
> +	compatible = "richtek,typec_rt1711h";
> +	reg = <0x4e>;
> +	rt,intr_gpio = <&gpio26 0 0x0>;
> +	rt,name = "rt1711h";
> +	rt,port_type = <2>; /* 0: DFP, 1: UFP, 2: DRP */
> +	rt,def_role = <0>; /* 0: SNK, 1: SRC, -1: TYPEC_NO_PREFERRED_ROLE */
> +};

dts stuff needs to always be in a separate file so the DT maintainers
can review/ack it.  Split this patch up into smaller pieces please.


> diff --git a/arch/arm64/boot/dts/hisilicon/rt1711h.dtsi b/arch/arm64/boot/dts/hisilicon/rt1711h.dtsi
> new file mode 100644
> index 0000000..4196cc0
> --- /dev/null
> +++ b/arch/arm64/boot/dts/hisilicon/rt1711h.dtsi
> @@ -0,0 +1,11 @@
> +&i2c7 {
> +	rt1711h@4e {
> +		status = "ok";
> +		compatible = "richtek,typec_rt1711h";
> +		reg = <0x4e>;
> +		rt,intr_gpio = <&gpio26 0 0x0>;
> +		rt,name = "rt1711h";
> +		rt,port_type = <2>; /* 0: DFP, 1: UFP, 2: DRP */
> +		rt,def_role = <0>; /* 0: SNK, 1: SRC */
> +	};
> +};
> diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig
> index bcb2744..7bede0b 100644
> --- a/drivers/usb/typec/Kconfig
> +++ b/drivers/usb/typec/Kconfig
> @@ -56,6 +56,8 @@ if TYPEC_TCPM
>  
>  source "drivers/usb/typec/fusb302/Kconfig"
>  
> +source "drivers/usb/typec/rt1711h/Kconfig"
> +
>  config TYPEC_WCOVE
>  	tristate "Intel WhiskeyCove PMIC USB Type-C PHY driver"
>  	depends on ACPI
> diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile
> index bb3138a..e3aaf3c 100644
> --- a/drivers/usb/typec/Makefile
> +++ b/drivers/usb/typec/Makefile
> @@ -2,6 +2,7 @@
>  obj-$(CONFIG_TYPEC)		+= typec.o
>  obj-$(CONFIG_TYPEC_TCPM)	+= tcpm.o
>  obj-y				+= fusb302/
> +obj-$(CONFIG_TYPEC_RT1711H)	+= rt1711h/

Why do you need a whole directory for one file?


>  obj-$(CONFIG_TYPEC_WCOVE)	+= typec_wcove.o
>  obj-$(CONFIG_TYPEC_UCSI)	+= ucsi/
>  obj-$(CONFIG_TYPEC_TPS6598X)	+= tps6598x.o
> diff --git a/drivers/usb/typec/rt1711h/Kconfig b/drivers/usb/typec/rt1711h/Kconfig
> new file mode 100644
> index 0000000..2fbfff5
> --- /dev/null
> +++ b/drivers/usb/typec/rt1711h/Kconfig
> @@ -0,0 +1,7 @@
> +config TYPEC_RT1711H
> +	tristate "Richtek RT1711H Type-C chip driver"
> +	depends on I2C && POWER_SUPPLY
> +	help
> +	  The Richtek RT1711H   Type-C chip driver that works with
> +	  Type-C Port Controller Manager to provide USB PD and USB
> +	  Type-C functionalities.
> diff --git a/drivers/usb/typec/rt1711h/Makefile b/drivers/usb/typec/rt1711h/Makefile
> new file mode 100644
> index 0000000..5fab8ae
> --- /dev/null
> +++ b/drivers/usb/typec/rt1711h/Makefile
> @@ -0,0 +1,2 @@
> +# SPDX-License-Identifier: GPL-2.0
> +obj-$(CONFIG_TYPEC_RT1711H)	+= rt1711h.o
> diff --git a/drivers/usb/typec/rt1711h/rt1711h.c b/drivers/usb/typec/rt1711h/rt1711h.c
> new file mode 100644
> index 0000000..1aef3e8
> --- /dev/null
> +++ b/drivers/usb/typec/rt1711h/rt1711h.c
> @@ -0,0 +1,2241 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright 2017 Richtek Technologh Corp.
> + *
> + * Richtek RT1711H Type-C Chip Driver
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/version.h>
> +#include <linux/err.h>
> +#include <linux/debugfs.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/i2c.h>
> +#include <linux/usb/typec.h>
> +#include <linux/usb/tcpm.h>
> +#include <linux/usb/pd.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/power_supply.h>
> +#include <linux/extcon.h>
> +#include <linux/workqueue.h>
> +#include <linux/kthread.h>
> +#include <linux/cpu.h>
> +#include <linux/alarmtimer.h>
> +#include <linux/sched/clock.h>
> +#include <uapi/linux/sched/types.h>

This last #include should not be needed.  If it does, you are doing
something really wrong...

> +
> +#include "rt1711h.h"

Why a .h file for a single .c file?

> +
> +#define RT1711H_DRV_VERSION	"1.0.3"

When code is in the kernel tree, versions mean nothing, you will note
that no other USB driver has them, right?  Please remove.


> +
> +#define LOG_BUFFER_ENTRIES	1024
> +#define LOG_BUFFER_ENTRY_SIZE	128 /* 128 char per line */
> +
> +enum {
> +	RT1711H_DBG_LOG = 0,
> +	RT1711H_DBG_REGS,
> +	RT1711H_DBG_REG_ADDR,
> +	RT1711H_DBG_DATA,
> +	RT1711H_DBG_MAX,
> +};
> +
> +struct rt1711h_dbg_info {
> +	struct rt1711h_chip *chip;
> +	int id;
> +};
> +
> +
> +struct rt1711h_chip {
> +	struct i2c_client *i2c;
> +	struct device *dev;
> +	uint16_t did;

kernel types are u16, u32, u8, and the like, not uint16_t, those are for
userspace code only.

Yeah, other drivers do it, but you shouldn't :)


> +	int irq_gpio;
> +	int irq;
> +	char *name;
> +	struct tcpc_dev tcpc_dev;
> +	struct tcpc_config tcpc_cfg;
> +	struct tcpm_port *tcpm_port;
> +	struct regulator *vbus;
> +	struct extcon_dev *extcon;
> +
> +	/* IRQ */
> +	struct kthread_worker irq_worker;
> +	struct kthread_work irq_work;
> +	struct task_struct *irq_worker_task;

3 things for an irq handler?  That feels wrong.

> +	atomic_t poll_count;

Like I said before, why is this an atomic?

> +	struct delayed_work poll_work;
> +
> +	/* LPM */
> +	struct delayed_work wakeup_work;
> +	struct alarm wakeup_timer;
> +	struct mutex wakeup_lock;
> +	enum typec_cc_pull lpm_pull;
> +	bool wakeup_once;
> +	bool low_rp_duty_cntdown;
> +	bool cable_only;
> +	bool lpm;
> +
> +	/* I2C */
> +	atomic_t i2c_busy;
> +	atomic_t pm_suspend;

Why are these atomic?  You know that doesn't mean they do not need
locking, right?

> +
> +	/* psy + psy status */
> +	struct power_supply *psy;
> +	u32 current_limit;
> +	u32 supply_voltage;
> +
> +	/* lock for sharing chip states */
> +	struct mutex lock;

How many locks do you have in this structure?  You should only need 1.

> +
> +	/* port status */
> +	bool vconn_on;
> +	bool vbus_on;
> +	bool charge_on;
> +	bool vbus_present;
> +	enum typec_cc_polarity polarity;
> +	enum typec_cc_status cc1;
> +	enum typec_cc_status cc2;
> +	enum typec_role pwr_role;
> +	bool drp_toggling;
> +
> +#ifdef CONFIG_DEBUG_FS
> +	struct dentry *dbgdir;
> +	struct rt1711h_dbg_info dbg_info[RT1711H_DBG_MAX];
> +	struct dentry *dbg_files[RT1711H_DBG_MAX];
> +	int dbg_regidx;
> +	struct mutex dbgops_lock;
> +	/* lock for log buffer access */
> +	struct mutex logbuffer_lock;
> +	int logbuffer_head;
> +	int logbuffer_tail;
> +	u8 *logbuffer[LOG_BUFFER_ENTRIES];
> +#endif /* CONFIG_DEBUG_FS */

That's a lot of stuff jsut for debugfs.  Why do you care about #define
at all?  The code should not.

And another 2 locks?  Ick, no.


> +};
> +
> +/*
> + * Logging & debugging
> + */
> +
> +#ifdef CONFIG_DEBUG_FS
> +
> +static int rt1711h_reg_block_read(struct rt1711h_chip *chip, uint8_t reg,
> +	int len, uint8_t *data);
> +static int rt1711h_reg_block_write(struct rt1711h_chip *chip, uint8_t reg,
> +	int len, const uint8_t *data);
> +
> +struct reg_desc {
> +	uint8_t addr;
> +	uint8_t size;
> +};
> +#define DECL_REG(_addr, _size) {.addr = _addr, .size = _size}
> +
> +static struct reg_desc rt1711h_reg_desc[] = {
> +	DECL_REG(RT1711H_REG_VID, 2),
> +	DECL_REG(RT1711H_REG_PID, 2),
> +	DECL_REG(RT1711H_REG_DID, 2),
> +	DECL_REG(RT1711H_REG_TYPEC_REV, 2),
> +	DECL_REG(RT1711H_REG_PD_REV, 2),
> +	DECL_REG(RT1711H_REG_PDIF_REV, 2),
> +	DECL_REG(RT1711H_REG_ALERT, 2),
> +	DECL_REG(RT1711H_REG_ALERT_MASK, 2),
> +	DECL_REG(RT1711H_REG_POWER_STATUS_MASK, 1),
> +	DECL_REG(RT1711H_REG_FAULT_STATUS_MASK, 1),
> +	DECL_REG(RT1711H_REG_TCPC_CTRL, 1),
> +	DECL_REG(RT1711H_REG_ROLE_CTRL, 1),
> +	DECL_REG(RT1711H_REG_FAULT_CTRL, 1),
> +	DECL_REG(RT1711H_REG_POWER_CTRL, 1),
> +	DECL_REG(RT1711H_REG_CC_STATUS, 1),
> +	DECL_REG(RT1711H_REG_POWER_STATUS, 1),
> +	DECL_REG(RT1711H_REG_FAULT_STATUS, 1),
> +	DECL_REG(RT1711H_REG_COMMAND, 1),
> +	DECL_REG(RT1711H_REG_MSG_HDR_INFO, 1),
> +	DECL_REG(RT1711H_REG_RX_DETECT, 1),
> +	DECL_REG(RT1711H_REG_RX_BYTE_CNT, 1),
> +	DECL_REG(RT1711H_REG_RX_BUF_FRAME_TYPE, 1),
> +	DECL_REG(RT1711H_REG_RX_HDR, 2),
> +	DECL_REG(RT1711H_REG_RX_DATA, 1),
> +	DECL_REG(RT1711H_REG_TRANSMIT, 1),
> +	DECL_REG(RT1711H_REG_TX_BYTE_CNT, 1),
> +	DECL_REG(RT1711H_REG_TX_HDR, 2),
> +	DECL_REG(RT1711H_REG_TX_DATA, 1),
> +	DECL_REG(RT1711H_REG_CLK_CTRL2, 1),
> +	DECL_REG(RT1711H_REG_CLK_CTRL3, 1),
> +	DECL_REG(RT1711H_REG_BMC_CTRL, 1),
> +	DECL_REG(RT1711H_REG_BMCIO_RXDZSEL, 1),
> +	DECL_REG(RT1711H_REG_VCONN_CLIMITEN, 1),
> +	DECL_REG(RT1711H_REG_RT_STATUS, 1),
> +	DECL_REG(RT1711H_REG_RT_INT, 1),
> +	DECL_REG(RT1711H_REG_RT_MASK, 1),
> +	DECL_REG(RT1711H_REG_IDLE_CTRL, 1),
> +	DECL_REG(RT1711H_REG_INTRST_CTRL, 1),
> +	DECL_REG(RT1711H_REG_WATCHDOG_CTRL, 1),
> +	DECL_REG(RT1711H_REG_I2CRST_CTRL, 1),
> +	DECL_REG(RT1711H_REG_SWRESET, 1),
> +	DECL_REG(RT1711H_REG_TTCPC_FILTER, 1),
> +	DECL_REG(RT1711H_REG_DRP_TOGGLE_CYCLE, 1),
> +	DECL_REG(RT1711H_REG_DRP_DUTY_CTRL, 1),
> +	DECL_REG(RT1711H_REG_BMCIO_RXDZEN, 1),
> +};
> +
> +static const char *rt1711h_dbg_filename[RT1711H_DBG_MAX] = {
> +	"log", "regs", "reg_addr", "data",
> +};
> +
> +static bool rt1711h_log_full(struct rt1711h_chip *chip)
> +{
> +	return chip->logbuffer_tail ==
> +		(chip->logbuffer_head + 1) % LOG_BUFFER_ENTRIES;
> +}
> +
> +static void _rt1711h_log(struct rt1711h_chip *chip, const char *fmt,
> +			 va_list args)
> +{
> +	char tmpbuffer[LOG_BUFFER_ENTRY_SIZE];
> +	u64 ts_nsec = local_clock();
> +	unsigned long rem_nsec;
> +
> +	if (!chip->logbuffer[chip->logbuffer_head]) {
> +		chip->logbuffer[chip->logbuffer_head] =
> +		devm_kzalloc(chip->dev, LOG_BUFFER_ENTRY_SIZE, GFP_KERNEL);
> +		if (!chip->logbuffer[chip->logbuffer_head])
> +			return;
> +	}
> +
> +	vsnprintf(tmpbuffer, sizeof(tmpbuffer), fmt, args);
> +
> +	mutex_lock(&chip->logbuffer_lock);
> +
> +	if (rt1711h_log_full(chip)) {
> +		chip->logbuffer_head = max(chip->logbuffer_head - 1, 0);
> +		strlcpy(tmpbuffer, "overflow", sizeof(tmpbuffer));
> +	}
> +
> +	if (chip->logbuffer_head < 0 ||
> +		chip->logbuffer_head >= LOG_BUFFER_ENTRIES) {
> +		dev_warn(chip->dev, "%s bad log buffer index %d\n", __func__,
> +			chip->logbuffer_head);
> +		goto abort;
> +	}
> +
> +	if (!chip->logbuffer[chip->logbuffer_head]) {
> +		dev_warn(chip->dev, "%s log buffer index %d is NULL\n",
> +			__func__, chip->logbuffer_head);
> +		goto abort;
> +	}
> +
> +	rem_nsec = do_div(ts_nsec, 1000000000);
> +	scnprintf(chip->logbuffer[chip->logbuffer_head], LOG_BUFFER_ENTRY_SIZE,
> +		"[%5lu.%06lu] %s", (unsigned long)ts_nsec, rem_nsec / 1000,
> +		  tmpbuffer);
> +	chip->logbuffer_head = (chip->logbuffer_head + 1) % LOG_BUFFER_ENTRIES;
> +
> +abort:
> +	mutex_unlock(&chip->logbuffer_lock);
> +}
> +
> +static void rt1711h_log(struct rt1711h_chip *chip,
> +	const char *fmt, ...)
> +{
> +	va_list args;
> +
> +	va_start(args, fmt);
> +	_rt1711h_log(chip, fmt, args);
> +	va_end(args);
> +}
> +
> +static int rt1711h_log_show(struct rt1711h_chip *chip, struct seq_file *s)
> +{
> +	int tail;
> +
> +	mutex_lock(&chip->logbuffer_lock);
> +	tail = chip->logbuffer_tail;
> +	while (tail != chip->logbuffer_head) {
> +		seq_printf(s, "%s", chip->logbuffer[tail]);
> +		tail = (tail + 1) % LOG_BUFFER_ENTRIES;
> +	}
> +	if (!seq_has_overflowed(s))
> +		chip->logbuffer_tail = tail;
> +	mutex_unlock(&chip->logbuffer_lock);
> +
> +	return 0;
> +}
> +
> +static int rt1711h_regs_show(struct rt1711h_chip *chip, struct seq_file *s)
> +{
> +	int ret = 0;
> +	int i = 0, j = 0;
> +	struct reg_desc *desc = NULL;
> +	uint8_t regval[2] = {0};
> +
> +	for (i = 0; i < ARRAY_SIZE(rt1711h_reg_desc); i++) {
> +		desc = &rt1711h_reg_desc[i];
> +		ret = rt1711h_reg_block_read(chip, desc->addr, desc->size,
> +			regval);
> +		if (ret < 0) {
> +			dev_err(chip->dev, "%s read reg0x%02X fail\n",
> +				__func__, desc->addr);
> +			continue;
> +		}
> +
> +		seq_printf(s, "reg0x%02x:0x", desc->addr);
> +		for (j = 0; j < desc->size; j++)
> +			seq_printf(s, "%02x,", regval[j]);
> +		seq_puts(s, "\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static inline int rt1711h_reg_addr_show(struct rt1711h_chip *chip,
> +	struct seq_file *s)
> +{
> +	struct reg_desc *desc = &rt1711h_reg_desc[chip->dbg_regidx];
> +
> +	seq_printf(s, "0x%02x\n", desc->addr);
> +	return 0;
> +}
> +
> +static inline int rt1711h_data_show(struct rt1711h_chip *chip,
> +	struct seq_file *s)
> +{
> +	int ret = 0, i = 0;
> +	struct reg_desc *desc = &rt1711h_reg_desc[chip->dbg_regidx];
> +	uint8_t regval[2] = {0};
> +
> +	ret = rt1711h_reg_block_read(chip, desc->addr, desc->size, regval);
> +	if (ret < 0)
> +		return ret;
> +
> +	seq_printf(s, "reg0x%02x=0x", desc->addr);
> +	for (i = 0; i < desc->size; i++)
> +		seq_printf(s, "%02x,", regval[i]);
> +	seq_puts(s, "\n");
> +	return 0;
> +}
> +
> +static int rt1711h_dbg_show(struct seq_file *s, void *v)
> +{
> +	int ret = 0;
> +	struct rt1711h_dbg_info *info = (struct rt1711h_dbg_info *)s->private;
> +	struct rt1711h_chip *chip = info->chip;
> +
> +	mutex_lock(&chip->dbgops_lock);
> +	switch (info->id) {
> +	case RT1711H_DBG_LOG:
> +		ret = rt1711h_log_show(chip, s);
> +		break;
> +	case RT1711H_DBG_REGS:
> +		ret = rt1711h_regs_show(chip, s);
> +		break;
> +	case RT1711H_DBG_REG_ADDR:
> +		ret = rt1711h_reg_addr_show(chip, s);
> +		break;
> +	case RT1711H_DBG_DATA:
> +		ret = rt1711h_data_show(chip, s);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	mutex_unlock(&chip->dbgops_lock);
> +	return ret;
> +}
> +
> +static int rt1711h_dbg_open(struct inode *inode, struct file *file)
> +{
> +	if (file->f_mode & FMODE_READ)
> +		return single_open(file, rt1711h_dbg_show, inode->i_private);
> +	file->private_data = inode->i_private;
> +	return 0;
> +}
> +
> +static int get_parameters(char *buf, long int *param1, int num_of_par)
> +{
> +	char *token;
> +	int base, cnt;
> +
> +	token = strsep(&buf, " ");
> +
> +	for (cnt = 0; cnt < num_of_par; cnt++) {
> +		if (token != NULL) {
> +			if ((token[1] == 'x') || (token[1] == 'X'))
> +				base = 16;
> +			else
> +				base = 10;
> +
> +			if (kstrtoul(token, base, &param1[cnt]) != 0)
> +				return -EINVAL;
> +
> +			token = strsep(&buf, " ");
> +		} else
> +			return -EINVAL;
> +	}
> +	return 0;
> +}

What is this function doing?  What is your debugfs files for?

> +
> +static int get_datas(const char *buf, const int length,
> +	unsigned char *data_buffer, unsigned char data_length)
> +{
> +	int i, ptr;
> +	long int value;
> +	char token[5];
> +
> +	token[0] = '0';
> +	token[1] = 'x';
> +	token[4] = 0;
> +	if (buf[0] != '0' || buf[1] != 'x')
> +		return -EINVAL;
> +
> +	ptr = 2;
> +	for (i = 0; (i < data_length) && (ptr + 2 <= length); i++) {
> +		token[2] = buf[ptr++];
> +		token[3] = buf[ptr++];
> +		ptr++;
> +		if (kstrtoul(token, 16, &value) != 0)
> +			return -EINVAL;
> +		data_buffer[i] = value;
> +	}
> +	return 0;
> +}
> +
> +static int rt1711h_regaddr2idx(uint8_t reg_addr)
> +{
> +	int i = 0;
> +	struct reg_desc *desc = NULL;
> +
> +	for (i = 0; i < ARRAY_SIZE(rt1711h_reg_desc); i++) {
> +		desc = &rt1711h_reg_desc[i];
> +		if (desc->addr == reg_addr)
> +			return i;
> +	}
> +	return -EINVAL;
> +}
> +
> +static ssize_t rt1711h_dbg_write(struct file *file, const char __user *ubuf,
> +	size_t count, loff_t *ppos)
> +{
> +	int ret = 0;
> +	struct rt1711h_dbg_info *info =
> +		(struct rt1711h_dbg_info *)file->private_data;
> +	struct rt1711h_chip *chip = info->chip;
> +	struct reg_desc *desc = NULL;
> +	char lbuf[128];
> +	long int param[5];
> +	unsigned char reg_data[2] = {0};
> +
> +	if (count > sizeof(lbuf) - 1)
> +		return -EFAULT;
> +
> +	ret = copy_from_user(lbuf, ubuf, count);
> +	if (ret)
> +		return -EFAULT;
> +	lbuf[count] = '\0';
> +
> +	mutex_lock(&chip->dbgops_lock);
> +	switch (info->id) {
> +	case RT1711H_DBG_REG_ADDR:
> +		ret = get_parameters(lbuf, param, 1);
> +		if (ret < 0) {
> +			dev_err(chip->dev, "%s get param fail\n", __func__);
> +			ret = -EINVAL;
> +			goto out;
> +		}
> +		ret = rt1711h_regaddr2idx(param[0]);
> +		if (ret < 0) {
> +			dev_err(chip->dev, "%s addr2idx fail\n", __func__);
> +			ret = -EINVAL;
> +			goto out;
> +		}
> +		chip->dbg_regidx = ret;
> +		break;
> +	case RT1711H_DBG_DATA:
> +		desc = &rt1711h_reg_desc[chip->dbg_regidx];
> +		if ((desc->size - 1) * 3 + 5 != count) {
> +			dev_err(chip->dev, "%s incorrect input length\n",
> +				__func__);
> +			ret = -EINVAL;
> +			goto out;
> +		}
> +		ret = get_datas((char *)ubuf, count, reg_data, desc->size);
> +		if (ret < 0) {
> +			dev_err(chip->dev, "%s get data fail\n", __func__);
> +			ret = -EINVAL;
> +			goto out;
> +		}
> +		ret = rt1711h_reg_block_write(chip, desc->addr, desc->size,
> +			reg_data);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +out:
> +	mutex_unlock(&chip->dbgops_lock);
> +	return ret < 0 ? ret : count;
> +}
> +
> +static int rt1711h_dbg_release(struct inode *inode, struct file *file)
> +{
> +	if (file->f_mode & FMODE_READ)
> +		return single_release(inode, file);
> +	return 0;
> +}
> +
> +static const struct file_operations rt1711h_dbg_ops = {
> +	.open		= rt1711h_dbg_open,
> +	.llseek		= seq_lseek,
> +	.read		= seq_read,
> +	.write		= rt1711h_dbg_write,
> +	.release	= rt1711h_dbg_release,
> +};
> +
> +
> +static int rt1711h_debugfs_init(struct rt1711h_chip *chip)
> +{
> +	int ret = 0, i = 0;
> +	struct rt1711h_dbg_info *info = NULL;
> +	int len = 0;
> +	char *dirname = NULL;
> +
> +	mutex_init(&chip->logbuffer_lock);
> +	mutex_init(&chip->dbgops_lock);
> +	len = strlen(dev_name(chip->dev));
> +	dirname = devm_kzalloc(chip->dev, len + 9, GFP_KERNEL);
> +	if (!dirname)
> +		return -ENOMEM;
> +	snprintf(dirname, len + 9, "rt1711h-%s", dev_name(chip->dev));
> +	if (!chip->dbgdir) {
> +		chip->dbgdir = debugfs_create_dir(dirname, NULL);
> +		if (!chip->dbgdir)
> +			return -ENOMEM;

No need to ever check the return value of debugfs_ calls, you should not
care and can always use the value to any future debugfs calls, if you
really need it.

> +	}
> +
> +	for (i = 0; i < RT1711H_DBG_MAX; i++) {
> +		info = &chip->dbg_info[i];

static array of debug info?  That feels odd.

> +		info->chip = chip;
> +		info->id = i;
> +		chip->dbg_files[i] = debugfs_create_file(
> +			rt1711h_dbg_filename[i], S_IFREG | 0444,
> +			chip->dbgdir, info, &rt1711h_dbg_ops);
> +		if (!chip->dbg_files[i]) {
> +			ret = -EINVAL;

Like here, you don't need this, and you don't need to care about the
return value.

> +			goto err;
> +		}
> +	}
> +
> +	return 0;
> +err:
> +	debugfs_remove_recursive(chip->dbgdir);
> +	return ret;

Why do you care about an error here?  Your code should not do anything
different if debugfs stuff does not work or if it does.  It's debugging
only.

> +}
> +
> +static void rt1711h_debugfs_exit(struct rt1711h_chip *chip)
> +{
> +	debugfs_remove_recursive(chip->dbgdir);

See, you didn't need those file handles :)

thanks,

greg k-h

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ