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 | static ssize_t _f_##_opts_ifname_store(struct config_item *item, \ |
152 | const char *page, size_t len)\ |
153 | { \ |
154 | struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ |
155 | int ret = -EBUSY; \ |
156 | \ |
157 | mutex_lock(&opts->lock); \ |
158 | if (!opts->refcnt) \ |
159 | ret = gether_set_ifname(opts->net, page, len); \ |
160 | mutex_unlock(&opts->lock); \ |
161 | return ret ?: len; \ |
162 | } \ |
163 | \ |
164 | CONFIGFS_ATTR(_f_##_opts_, ifname) |
165 | |
166 | #define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_) \ |
167 | static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\ |
168 | char *page) \ |
169 | { \ |
170 | struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ |
171 | int ret; \ |
172 | \ |
173 | mutex_lock(&opts->lock); \ |
174 | ret = sprintf(page, "%02x\n", opts->_n_); \ |
175 | mutex_unlock(&opts->lock); \ |
176 | \ |
177 | return ret; \ |
178 | } \ |
179 | \ |
180 | static ssize_t _f_##_opts_##_n_##_store(struct config_item *item,\ |
181 | const char *page, \ |
182 | size_t len) \ |
183 | { \ |
184 | struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ |
185 | int ret = -EINVAL; \ |
186 | u8 val; \ |
187 | \ |
188 | mutex_lock(&opts->lock); \ |
189 | if (sscanf(page, "%02hhx", &val) > 0) { \ |
190 | opts->_n_ = val; \ |
191 | ret = len; \ |
192 | } \ |
193 | mutex_unlock(&opts->lock); \ |
194 | \ |
195 | return ret; \ |
196 | } \ |
197 | \ |
198 | CONFIGFS_ATTR(_f_##_opts_, _n_) |
199 | |
200 | #endif /* __U_ETHER_CONFIGFS_H */ |
201 | |