1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * u_ether_configfs.h
4  *
5  * Utility definitions for configfs support in USB Ethernet functions
6  *
7  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
8  *		http://www.samsung.com
9  *
10  * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
11  */
12 
13 #ifndef __U_ETHER_CONFIGFS_H
14 #define __U_ETHER_CONFIGFS_H
15 
16 #define USB_ETHERNET_CONFIGFS_ITEM(_f_)					\
17 	static void _f_##_attr_release(struct config_item *item)	\
18 	{								\
19 		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
20 									\
21 		usb_put_function_instance(&opts->func_inst);		\
22 	}								\
23 									\
24 	static struct configfs_item_operations _f_##_item_ops = {	\
25 		.release	= _f_##_attr_release,			\
26 	}
27 
28 #define USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(_f_)			\
29 	static ssize_t _f_##_opts_dev_addr_show(struct config_item *item, \
30 						char *page)		\
31 	{								\
32 		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
33 		int result;						\
34 									\
35 		mutex_lock(&opts->lock);				\
36 		result = gether_get_dev_addr(opts->net, page, PAGE_SIZE); \
37 		mutex_unlock(&opts->lock);				\
38 									\
39 		return result;						\
40 	}								\
41 									\
42 	static ssize_t _f_##_opts_dev_addr_store(struct config_item *item, \
43 						 const char *page, size_t len)\
44 	{								\
45 		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
46 		int ret;						\
47 									\
48 		mutex_lock(&opts->lock);				\
49 		if (opts->refcnt) {					\
50 			mutex_unlock(&opts->lock);			\
51 			return -EBUSY;					\
52 		}							\
53 									\
54 		ret = gether_set_dev_addr(opts->net, page);		\
55 		mutex_unlock(&opts->lock);				\
56 		if (!ret)						\
57 			ret = len;					\
58 		return ret;						\
59 	}								\
60 									\
61 	CONFIGFS_ATTR(_f_##_opts_, dev_addr)
62 
63 #define USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(_f_)			\
64 	static ssize_t _f_##_opts_host_addr_show(struct config_item *item, \
65 						 char *page)		\
66 	{								\
67 		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
68 		int result;						\
69 									\
70 		mutex_lock(&opts->lock);				\
71 		result = gether_get_host_addr(opts->net, page, PAGE_SIZE); \
72 		mutex_unlock(&opts->lock);				\
73 									\
74 		return result;						\
75 	}								\
76 									\
77 	static ssize_t _f_##_opts_host_addr_store(struct config_item *item, \
78 						  const char *page, size_t len)\
79 	{								\
80 		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
81 		int ret;						\
82 									\
83 		mutex_lock(&opts->lock);				\
84 		if (opts->refcnt) {					\
85 			mutex_unlock(&opts->lock);			\
86 			return -EBUSY;					\
87 		}							\
88 									\
89 		ret = gether_set_host_addr(opts->net, page);		\
90 		mutex_unlock(&opts->lock);				\
91 		if (!ret)						\
92 			ret = len;					\
93 		return ret;						\
94 	}								\
95 									\
96 	CONFIGFS_ATTR(_f_##_opts_, host_addr)
97 
98 #define USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(_f_)			\
99 	static ssize_t _f_##_opts_qmult_show(struct config_item *item,	\
100 					     char *page)		\
101 	{								\
102 		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
103 		unsigned qmult;						\
104 									\
105 		mutex_lock(&opts->lock);				\
106 		qmult = gether_get_qmult(opts->net);			\
107 		mutex_unlock(&opts->lock);				\
108 		return sprintf(page, "%d\n", qmult);			\
109 	}								\
110 									\
111 	static ssize_t _f_##_opts_qmult_store(struct config_item *item, \
112 					      const char *page, size_t len)\
113 	{								\
114 		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
115 		u8 val;							\
116 		int ret;						\
117 									\
118 		mutex_lock(&opts->lock);				\
119 		if (opts->refcnt) {					\
120 			ret = -EBUSY;					\
121 			goto out;					\
122 		}							\
123 									\
124 		ret = kstrtou8(page, 0, &val);				\
125 		if (ret)						\
126 			goto out;					\
127 									\
128 		gether_set_qmult(opts->net, val);			\
129 		ret = len;						\
130 out:									\
131 		mutex_unlock(&opts->lock);				\
132 		return ret;						\
133 	}								\
134 									\
135 	CONFIGFS_ATTR(_f_##_opts_, qmult)
136 
137 #define USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(_f_)			\
138 	static ssize_t _f_##_opts_ifname_show(struct config_item *item, \
139 					      char *page)		\
140 	{								\
141 		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
142 		int ret;						\
143 									\
144 		mutex_lock(&opts->lock);				\
145 		ret = gether_get_ifname(opts->net, page, PAGE_SIZE);	\
146 		mutex_unlock(&opts->lock);				\
147 									\
148 		return ret;						\
149 	}								\
150 									\
151 	CONFIGFS_ATTR_RO(_f_##_opts_, ifname)
152 
153 #define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_)			\
154 	static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\
155 					       char *page)		\
156 	{								\
157 		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
158 		int ret;						\
159 									\
160 		mutex_lock(&opts->lock);				\
161 		ret = sprintf(page, "%02x\n", opts->_n_);		\
162 		mutex_unlock(&opts->lock);				\
163 									\
164 		return ret;						\
165 	}								\
166 									\
167 	static ssize_t _f_##_opts_##_n_##_store(struct config_item *item,\
168 						const char *page,	\
169 						size_t len)		\
170 	{								\
171 		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\
172 		int ret;						\
173 		u8 val;							\
174 									\
175 		mutex_lock(&opts->lock);				\
176 		ret = sscanf(page, "%02hhx", &val);			\
177 		if (ret > 0) {						\
178 			opts->_n_ = val;				\
179 			ret = len;					\
180 		}							\
181 		mutex_unlock(&opts->lock);				\
182 									\
183 		return ret;						\
184 	}								\
185 									\
186 	CONFIGFS_ATTR(_f_##_opts_, _n_)
187 
188 #endif /* __U_ETHER_CONFIGFS_H */
189