mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
5.5 KiB
200 lines
5.5 KiB
/* 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 <[email protected]> |
|
*/ |
|
|
|
#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 */
|
|
|