201 lines
5.5 KiB
C
201 lines
5.5 KiB
C
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||
|
/*
|
||
|
* u_ether_configfs.h
|
||
|
*
|
||
|
* Utility definitions for configfs support in USB Ethernet functions
|
||
|
*
|
||
|
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||
|
* http://www.samsung.com
|
||
|
*
|
||
|
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
|
||
|
*/
|
||
|
|
||
|
#ifndef __U_ETHER_CONFIGFS_H
|
||
|
#define __U_ETHER_CONFIGFS_H
|
||
|
|
||
|
#define USB_ETHERNET_CONFIGFS_ITEM(_f_) \
|
||
|
static void _f_##_attr_release(struct config_item *item) \
|
||
|
{ \
|
||
|
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||
|
\
|
||
|
usb_put_function_instance(&opts->func_inst); \
|
||
|
} \
|
||
|
\
|
||
|
static struct configfs_item_operations _f_##_item_ops = { \
|
||
|
.release = _f_##_attr_release, \
|
||
|
}
|
||
|
|
||
|
#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(_f_) \
|
||
|
static ssize_t _f_##_opts_dev_addr_show(struct config_item *item, \
|
||
|
char *page) \
|
||
|
{ \
|
||
|
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||
|
int result; \
|
||
|
\
|
||
|
mutex_lock(&opts->lock); \
|
||
|
result = gether_get_dev_addr(opts->net, page, PAGE_SIZE); \
|
||
|
mutex_unlock(&opts->lock); \
|
||
|
\
|
||
|
return result; \
|
||
|
} \
|
||
|
\
|
||
|
static ssize_t _f_##_opts_dev_addr_store(struct config_item *item, \
|
||
|
const char *page, size_t len)\
|
||
|
{ \
|
||
|
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||
|
int ret; \
|
||
|
\
|
||
|
mutex_lock(&opts->lock); \
|
||
|
if (opts->refcnt) { \
|
||
|
mutex_unlock(&opts->lock); \
|
||
|
return -EBUSY; \
|
||
|
} \
|
||
|
\
|
||
|
ret = gether_set_dev_addr(opts->net, page); \
|
||
|
mutex_unlock(&opts->lock); \
|
||
|
if (!ret) \
|
||
|
ret = len; \
|
||
|
return ret; \
|
||
|
} \
|
||
|
\
|
||
|
CONFIGFS_ATTR(_f_##_opts_, dev_addr)
|
||
|
|
||
|
#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(_f_) \
|
||
|
static ssize_t _f_##_opts_host_addr_show(struct config_item *item, \
|
||
|
char *page) \
|
||
|
{ \
|
||
|
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||
|
int result; \
|
||
|
\
|
||
|
mutex_lock(&opts->lock); \
|
||
|
result = gether_get_host_addr(opts->net, page, PAGE_SIZE); \
|
||
|
mutex_unlock(&opts->lock); \
|
||
|
\
|
||
|
return result; \
|
||
|
} \
|
||
|
\
|
||
|
static ssize_t _f_##_opts_host_addr_store(struct config_item *item, \
|
||
|
const char *page, size_t len)\
|
||
|
{ \
|
||
|
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||
|
int ret; \
|
||
|
\
|
||
|
mutex_lock(&opts->lock); \
|
||
|
if (opts->refcnt) { \
|
||
|
mutex_unlock(&opts->lock); \
|
||
|
return -EBUSY; \
|
||
|
} \
|
||
|
\
|
||
|
ret = gether_set_host_addr(opts->net, page); \
|
||
|
mutex_unlock(&opts->lock); \
|
||
|
if (!ret) \
|
||
|
ret = len; \
|
||
|
return ret; \
|
||
|
} \
|
||
|
\
|
||
|
CONFIGFS_ATTR(_f_##_opts_, host_addr)
|
||
|
|
||
|
#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(_f_) \
|
||
|
static ssize_t _f_##_opts_qmult_show(struct config_item *item, \
|
||
|
char *page) \
|
||
|
{ \
|
||
|
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||
|
unsigned qmult; \
|
||
|
\
|
||
|
mutex_lock(&opts->lock); \
|
||
|
qmult = gether_get_qmult(opts->net); \
|
||
|
mutex_unlock(&opts->lock); \
|
||
|
return sprintf(page, "%d\n", qmult); \
|
||
|
} \
|
||
|
\
|
||
|
static ssize_t _f_##_opts_qmult_store(struct config_item *item, \
|
||
|
const char *page, size_t len)\
|
||
|
{ \
|
||
|
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||
|
u8 val; \
|
||
|
int ret; \
|
||
|
\
|
||
|
mutex_lock(&opts->lock); \
|
||
|
if (opts->refcnt) { \
|
||
|
ret = -EBUSY; \
|
||
|
goto out; \
|
||
|
} \
|
||
|
\
|
||
|
ret = kstrtou8(page, 0, &val); \
|
||
|
if (ret) \
|
||
|
goto out; \
|
||
|
\
|
||
|
gether_set_qmult(opts->net, val); \
|
||
|
ret = len; \
|
||
|
out: \
|
||
|
mutex_unlock(&opts->lock); \
|
||
|
return ret; \
|
||
|
} \
|
||
|
\
|
||
|
CONFIGFS_ATTR(_f_##_opts_, qmult)
|
||
|
|
||
|
#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(_f_) \
|
||
|
static ssize_t _f_##_opts_ifname_show(struct config_item *item, \
|
||
|
char *page) \
|
||
|
{ \
|
||
|
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||
|
int ret; \
|
||
|
\
|
||
|
mutex_lock(&opts->lock); \
|
||
|
ret = gether_get_ifname(opts->net, page, PAGE_SIZE); \
|
||
|
mutex_unlock(&opts->lock); \
|
||
|
\
|
||
|
return ret; \
|
||
|
} \
|
||
|
\
|
||
|
static ssize_t _f_##_opts_ifname_store(struct config_item *item, \
|
||
|
const char *page, size_t len)\
|
||
|
{ \
|
||
|
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||
|
int ret = -EBUSY; \
|
||
|
\
|
||
|
mutex_lock(&opts->lock); \
|
||
|
if (!opts->refcnt) \
|
||
|
ret = gether_set_ifname(opts->net, page, len); \
|
||
|
mutex_unlock(&opts->lock); \
|
||
|
return ret ?: len; \
|
||
|
} \
|
||
|
\
|
||
|
CONFIGFS_ATTR(_f_##_opts_, ifname)
|
||
|
|
||
|
#define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_) \
|
||
|
static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\
|
||
|
char *page) \
|
||
|
{ \
|
||
|
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||
|
int ret; \
|
||
|
\
|
||
|
mutex_lock(&opts->lock); \
|
||
|
ret = sprintf(page, "%02x\n", opts->_n_); \
|
||
|
mutex_unlock(&opts->lock); \
|
||
|
\
|
||
|
return ret; \
|
||
|
} \
|
||
|
\
|
||
|
static ssize_t _f_##_opts_##_n_##_store(struct config_item *item,\
|
||
|
const char *page, \
|
||
|
size_t len) \
|
||
|
{ \
|
||
|
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||
|
int ret = -EINVAL; \
|
||
|
u8 val; \
|
||
|
\
|
||
|
mutex_lock(&opts->lock); \
|
||
|
if (sscanf(page, "%02hhx", &val) > 0) { \
|
||
|
opts->_n_ = val; \
|
||
|
ret = len; \
|
||
|
} \
|
||
|
mutex_unlock(&opts->lock); \
|
||
|
\
|
||
|
return ret; \
|
||
|
} \
|
||
|
\
|
||
|
CONFIGFS_ATTR(_f_##_opts_, _n_)
|
||
|
|
||
|
#endif /* __U_ETHER_CONFIGFS_H */
|