162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * u_ether_configfs.h
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Utility definitions for configfs support in USB Ethernet functions
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (c) 2013 Samsung Electronics Co., Ltd.
862306a36Sopenharmony_ci *		http://www.samsung.com
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#ifndef __U_ETHER_CONFIGFS_H
1462306a36Sopenharmony_ci#define __U_ETHER_CONFIGFS_H
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define USB_ETHERNET_CONFIGFS_ITEM(_f_)					\
1762306a36Sopenharmony_ci	static void _f_##_attr_release(struct config_item *item)	\
1862306a36Sopenharmony_ci	{								\
1962306a36Sopenharmony_ci		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
2062306a36Sopenharmony_ci									\
2162306a36Sopenharmony_ci		usb_put_function_instance(&opts->func_inst);		\
2262306a36Sopenharmony_ci	}								\
2362306a36Sopenharmony_ci									\
2462306a36Sopenharmony_ci	static struct configfs_item_operations _f_##_item_ops = {	\
2562306a36Sopenharmony_ci		.release	= _f_##_attr_release,			\
2662306a36Sopenharmony_ci	}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(_f_)			\
2962306a36Sopenharmony_ci	static ssize_t _f_##_opts_dev_addr_show(struct config_item *item, \
3062306a36Sopenharmony_ci						char *page)		\
3162306a36Sopenharmony_ci	{								\
3262306a36Sopenharmony_ci		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
3362306a36Sopenharmony_ci		int result;						\
3462306a36Sopenharmony_ci									\
3562306a36Sopenharmony_ci		mutex_lock(&opts->lock);				\
3662306a36Sopenharmony_ci		result = gether_get_dev_addr(opts->net, page, PAGE_SIZE); \
3762306a36Sopenharmony_ci		mutex_unlock(&opts->lock);				\
3862306a36Sopenharmony_ci									\
3962306a36Sopenharmony_ci		return result;						\
4062306a36Sopenharmony_ci	}								\
4162306a36Sopenharmony_ci									\
4262306a36Sopenharmony_ci	static ssize_t _f_##_opts_dev_addr_store(struct config_item *item, \
4362306a36Sopenharmony_ci						 const char *page, size_t len)\
4462306a36Sopenharmony_ci	{								\
4562306a36Sopenharmony_ci		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
4662306a36Sopenharmony_ci		int ret;						\
4762306a36Sopenharmony_ci									\
4862306a36Sopenharmony_ci		mutex_lock(&opts->lock);				\
4962306a36Sopenharmony_ci		if (opts->refcnt) {					\
5062306a36Sopenharmony_ci			mutex_unlock(&opts->lock);			\
5162306a36Sopenharmony_ci			return -EBUSY;					\
5262306a36Sopenharmony_ci		}							\
5362306a36Sopenharmony_ci									\
5462306a36Sopenharmony_ci		ret = gether_set_dev_addr(opts->net, page);		\
5562306a36Sopenharmony_ci		mutex_unlock(&opts->lock);				\
5662306a36Sopenharmony_ci		if (!ret)						\
5762306a36Sopenharmony_ci			ret = len;					\
5862306a36Sopenharmony_ci		return ret;						\
5962306a36Sopenharmony_ci	}								\
6062306a36Sopenharmony_ci									\
6162306a36Sopenharmony_ci	CONFIGFS_ATTR(_f_##_opts_, dev_addr)
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(_f_)			\
6462306a36Sopenharmony_ci	static ssize_t _f_##_opts_host_addr_show(struct config_item *item, \
6562306a36Sopenharmony_ci						 char *page)		\
6662306a36Sopenharmony_ci	{								\
6762306a36Sopenharmony_ci		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
6862306a36Sopenharmony_ci		int result;						\
6962306a36Sopenharmony_ci									\
7062306a36Sopenharmony_ci		mutex_lock(&opts->lock);				\
7162306a36Sopenharmony_ci		result = gether_get_host_addr(opts->net, page, PAGE_SIZE); \
7262306a36Sopenharmony_ci		mutex_unlock(&opts->lock);				\
7362306a36Sopenharmony_ci									\
7462306a36Sopenharmony_ci		return result;						\
7562306a36Sopenharmony_ci	}								\
7662306a36Sopenharmony_ci									\
7762306a36Sopenharmony_ci	static ssize_t _f_##_opts_host_addr_store(struct config_item *item, \
7862306a36Sopenharmony_ci						  const char *page, size_t len)\
7962306a36Sopenharmony_ci	{								\
8062306a36Sopenharmony_ci		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
8162306a36Sopenharmony_ci		int ret;						\
8262306a36Sopenharmony_ci									\
8362306a36Sopenharmony_ci		mutex_lock(&opts->lock);				\
8462306a36Sopenharmony_ci		if (opts->refcnt) {					\
8562306a36Sopenharmony_ci			mutex_unlock(&opts->lock);			\
8662306a36Sopenharmony_ci			return -EBUSY;					\
8762306a36Sopenharmony_ci		}							\
8862306a36Sopenharmony_ci									\
8962306a36Sopenharmony_ci		ret = gether_set_host_addr(opts->net, page);		\
9062306a36Sopenharmony_ci		mutex_unlock(&opts->lock);				\
9162306a36Sopenharmony_ci		if (!ret)						\
9262306a36Sopenharmony_ci			ret = len;					\
9362306a36Sopenharmony_ci		return ret;						\
9462306a36Sopenharmony_ci	}								\
9562306a36Sopenharmony_ci									\
9662306a36Sopenharmony_ci	CONFIGFS_ATTR(_f_##_opts_, host_addr)
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(_f_)			\
9962306a36Sopenharmony_ci	static ssize_t _f_##_opts_qmult_show(struct config_item *item,	\
10062306a36Sopenharmony_ci					     char *page)		\
10162306a36Sopenharmony_ci	{								\
10262306a36Sopenharmony_ci		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
10362306a36Sopenharmony_ci		unsigned qmult;						\
10462306a36Sopenharmony_ci									\
10562306a36Sopenharmony_ci		mutex_lock(&opts->lock);				\
10662306a36Sopenharmony_ci		qmult = gether_get_qmult(opts->net);			\
10762306a36Sopenharmony_ci		mutex_unlock(&opts->lock);				\
10862306a36Sopenharmony_ci		return sprintf(page, "%d\n", qmult);			\
10962306a36Sopenharmony_ci	}								\
11062306a36Sopenharmony_ci									\
11162306a36Sopenharmony_ci	static ssize_t _f_##_opts_qmult_store(struct config_item *item, \
11262306a36Sopenharmony_ci					      const char *page, size_t len)\
11362306a36Sopenharmony_ci	{								\
11462306a36Sopenharmony_ci		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
11562306a36Sopenharmony_ci		u8 val;							\
11662306a36Sopenharmony_ci		int ret;						\
11762306a36Sopenharmony_ci									\
11862306a36Sopenharmony_ci		mutex_lock(&opts->lock);				\
11962306a36Sopenharmony_ci		if (opts->refcnt) {					\
12062306a36Sopenharmony_ci			ret = -EBUSY;					\
12162306a36Sopenharmony_ci			goto out;					\
12262306a36Sopenharmony_ci		}							\
12362306a36Sopenharmony_ci									\
12462306a36Sopenharmony_ci		ret = kstrtou8(page, 0, &val);				\
12562306a36Sopenharmony_ci		if (ret)						\
12662306a36Sopenharmony_ci			goto out;					\
12762306a36Sopenharmony_ci									\
12862306a36Sopenharmony_ci		gether_set_qmult(opts->net, val);			\
12962306a36Sopenharmony_ci		ret = len;						\
13062306a36Sopenharmony_ciout:									\
13162306a36Sopenharmony_ci		mutex_unlock(&opts->lock);				\
13262306a36Sopenharmony_ci		return ret;						\
13362306a36Sopenharmony_ci	}								\
13462306a36Sopenharmony_ci									\
13562306a36Sopenharmony_ci	CONFIGFS_ATTR(_f_##_opts_, qmult)
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(_f_)			\
13862306a36Sopenharmony_ci	static ssize_t _f_##_opts_ifname_show(struct config_item *item, \
13962306a36Sopenharmony_ci					      char *page)		\
14062306a36Sopenharmony_ci	{								\
14162306a36Sopenharmony_ci		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
14262306a36Sopenharmony_ci		int ret;						\
14362306a36Sopenharmony_ci									\
14462306a36Sopenharmony_ci		mutex_lock(&opts->lock);				\
14562306a36Sopenharmony_ci		ret = gether_get_ifname(opts->net, page, PAGE_SIZE);	\
14662306a36Sopenharmony_ci		mutex_unlock(&opts->lock);				\
14762306a36Sopenharmony_ci									\
14862306a36Sopenharmony_ci		return ret;						\
14962306a36Sopenharmony_ci	}								\
15062306a36Sopenharmony_ci									\
15162306a36Sopenharmony_ci	static ssize_t _f_##_opts_ifname_store(struct config_item *item, \
15262306a36Sopenharmony_ci					       const char *page, size_t len)\
15362306a36Sopenharmony_ci	{								\
15462306a36Sopenharmony_ci		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
15562306a36Sopenharmony_ci		int ret = -EBUSY;					\
15662306a36Sopenharmony_ci									\
15762306a36Sopenharmony_ci		mutex_lock(&opts->lock);				\
15862306a36Sopenharmony_ci		if (!opts->refcnt)					\
15962306a36Sopenharmony_ci			ret = gether_set_ifname(opts->net, page, len);	\
16062306a36Sopenharmony_ci		mutex_unlock(&opts->lock);				\
16162306a36Sopenharmony_ci		return ret ?: len;					\
16262306a36Sopenharmony_ci	}								\
16362306a36Sopenharmony_ci									\
16462306a36Sopenharmony_ci	CONFIGFS_ATTR(_f_##_opts_, ifname)
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_)			\
16762306a36Sopenharmony_ci	static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\
16862306a36Sopenharmony_ci					       char *page)		\
16962306a36Sopenharmony_ci	{								\
17062306a36Sopenharmony_ci		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
17162306a36Sopenharmony_ci		int ret;						\
17262306a36Sopenharmony_ci									\
17362306a36Sopenharmony_ci		mutex_lock(&opts->lock);				\
17462306a36Sopenharmony_ci		ret = sprintf(page, "%02x\n", opts->_n_);		\
17562306a36Sopenharmony_ci		mutex_unlock(&opts->lock);				\
17662306a36Sopenharmony_ci									\
17762306a36Sopenharmony_ci		return ret;						\
17862306a36Sopenharmony_ci	}								\
17962306a36Sopenharmony_ci									\
18062306a36Sopenharmony_ci	static ssize_t _f_##_opts_##_n_##_store(struct config_item *item,\
18162306a36Sopenharmony_ci						const char *page,	\
18262306a36Sopenharmony_ci						size_t len)		\
18362306a36Sopenharmony_ci	{								\
18462306a36Sopenharmony_ci		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
18562306a36Sopenharmony_ci		int ret = -EINVAL;					\
18662306a36Sopenharmony_ci		u8 val;							\
18762306a36Sopenharmony_ci									\
18862306a36Sopenharmony_ci		mutex_lock(&opts->lock);				\
18962306a36Sopenharmony_ci		if (sscanf(page, "%02hhx", &val) > 0) {			\
19062306a36Sopenharmony_ci			opts->_n_ = val;				\
19162306a36Sopenharmony_ci			ret = len;					\
19262306a36Sopenharmony_ci		}							\
19362306a36Sopenharmony_ci		mutex_unlock(&opts->lock);				\
19462306a36Sopenharmony_ci									\
19562306a36Sopenharmony_ci		return ret;						\
19662306a36Sopenharmony_ci	}								\
19762306a36Sopenharmony_ci									\
19862306a36Sopenharmony_ci	CONFIGFS_ATTR(_f_##_opts_, _n_)
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci#endif /* __U_ETHER_CONFIGFS_H */
201