Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f466c635 authored by Andrzej Pietrasiewicz's avatar Andrzej Pietrasiewicz Committed by Felipe Balbi
Browse files

usb: gadget: f_rndis: convert to new function interface with backward compatibility



Converting rndis to the new function interface requires converting
the USB rndis' function code and its users.

This patch converts the f_rndis.c to the new function interface.

The file is now compiled into a separate usb_f_rndis.ko module.

The old function interface is provided by means of a preprocessor
conditional directives. After all users are converted, the old interface
can be removed.

Signed-off-by: default avatarAndrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 02832e56
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -526,6 +526,9 @@ config USB_F_EEM
config USB_F_SUBSET
	tristate

config USB_F_RNDIS
	tristate

choice
	tristate "USB Gadget Drivers"
	default USB_ETH
+2 −0
Original line number Diff line number Diff line
@@ -58,6 +58,8 @@ usb_f_eem-y := f_eem.o
obj-$(CONFIG_USB_F_EEM)		+= usb_f_eem.o
usb_f_ecm_subset-y		:= f_subset.o
obj-$(CONFIG_USB_F_SUBSET)	+= usb_f_ecm_subset.o
usb_f_rndis-y			:= f_rndis.o
obj-$(CONFIG_USB_F_RNDIS)	+= usb_f_rndis.o

#
# USB gadget drivers
+1 −0
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ static inline bool has_rndis(void)
#include "u_ecm.h"
#include "u_gether.h"
#ifdef	USB_ETH_RNDIS
#define USB_FRNDIS_INCLUDED
#include "f_rndis.c"
#include "rndis.h"
#endif
+175 −28
Original line number Diff line number Diff line
@@ -17,15 +17,16 @@

#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/etherdevice.h>

#include <linux/atomic.h>

#include "u_ether.h"
#include "u_rndis.h"
#include "rndis.h"


/*
 * This function is an RNDIS Ethernet port -- a Microsoft protocol that's
 * been promoted instead of the standard CDC Ethernet.  The published RNDIS
@@ -655,6 +656,13 @@ static void rndis_close(struct gether *geth)

/*-------------------------------------------------------------------------*/

/* Some controllers can't support RNDIS ... */
static inline bool can_support_rndis(struct usb_configuration *c)
{
	/* everything else is *presumably* fine */
	return true;
}

/* ethernet function driver setup/binding */

static int
@@ -665,6 +673,45 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
	int			status;
	struct usb_ep		*ep;

#ifndef USB_FRNDIS_INCLUDED
	struct f_rndis_opts *rndis_opts;

	if (!can_support_rndis(c))
		return -EINVAL;

	rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst);

	/*
	 * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
	 * configurations are bound in sequence with list_for_each_entry,
	 * in each configuration its functions are bound in sequence
	 * with list_for_each_entry, so we assume no race condition
	 * with regard to rndis_opts->bound access
	 */
	if (!rndis_opts->bound) {
		gether_set_gadget(rndis_opts->net, cdev->gadget);
		status = gether_register_netdev(rndis_opts->net);
		if (status)
			return status;
		rndis_opts->bound = true;
	}
#endif

	if (rndis_string_defs[0].id == 0) {
		/* ... and setup RNDIS itself */
		status = rndis_init();
		if (status < 0)
			return status;

		status = usb_string_ids_tab(c->cdev, rndis_string_defs);
		if (status)
			return status;

		rndis_control_intf.iInterface = rndis_string_defs[0].id;
		rndis_data_intf.iInterface = rndis_string_defs[1].id;
		rndis_iad_descriptor.iFunction = rndis_string_defs[2].id;
	}

	/* allocate instance-specific interface IDs */
	status = usb_interface_id(c, f);
	if (status < 0)
@@ -741,10 +788,12 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
	rndis->port.open = rndis_open;
	rndis->port.close = rndis_close;

#ifdef USB_FRNDIS_INCLUDED
	status = rndis_register(rndis_response_available, rndis);
	if (status < 0)
		goto fail;
	rndis->config = status;
#endif

	rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
	rndis_set_host_mac(rndis->config, rndis->ethaddr);
@@ -787,8 +836,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
	return status;
}

#ifdef USB_FRNDIS_INCLUDED

static void
rndis_unbind(struct usb_configuration *c, struct usb_function *f)
rndis_old_unbind(struct usb_configuration *c, struct usb_function *f)
{
	struct f_rndis		*rndis = func_to_rndis(f);

@@ -804,13 +855,6 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
	kfree(rndis);
}

/* Some controllers can't support RNDIS ... */
static inline bool can_support_rndis(struct usb_configuration *c)
{
	/* everything else is *presumably* fine */
	return true;
}

int
rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
		u32 vendorID, const char *manufacturer, struct eth_dev *dev)
@@ -818,24 +862,6 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
	struct f_rndis	*rndis;
	int		status;

	if (!can_support_rndis(c) || !ethaddr)
		return -EINVAL;

	if (rndis_string_defs[0].id == 0) {
		/* ... and setup RNDIS itself */
		status = rndis_init();
		if (status < 0)
			return status;

		status = usb_string_ids_tab(c->cdev, rndis_string_defs);
		if (status)
			return status;

		rndis_control_intf.iInterface = rndis_string_defs[0].id;
		rndis_data_intf.iInterface = rndis_string_defs[1].id;
		rndis_iad_descriptor.iFunction = rndis_string_defs[2].id;
	}

	/* allocate and initialize one new instance */
	status = -ENOMEM;
	rndis = kzalloc(sizeof *rndis, GFP_KERNEL);
@@ -859,7 +885,7 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
	rndis->port.func.strings = rndis_strings;
	/* descriptors are per-instance copies */
	rndis->port.func.bind = rndis_bind;
	rndis->port.func.unbind = rndis_unbind;
	rndis->port.func.unbind = rndis_old_unbind;
	rndis->port.func.set_alt = rndis_set_alt;
	rndis->port.func.setup = rndis_setup;
	rndis->port.func.disable = rndis_disable;
@@ -872,3 +898,124 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
	}
	return status;
}

#else

void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)
{
	struct f_rndis_opts *opts;

	opts = container_of(f, struct f_rndis_opts, func_inst);
	if (opts->bound)
		gether_cleanup(netdev_priv(opts->net));
	else
		free_netdev(opts->net);
	opts->borrowed_net = opts->bound = true;
	opts->net = net;
}
EXPORT_SYMBOL(rndis_borrow_net);

static void rndis_free_inst(struct usb_function_instance *f)
{
	struct f_rndis_opts *opts;

	opts = container_of(f, struct f_rndis_opts, func_inst);
	if (!opts->borrowed_net) {
		if (opts->bound)
			gether_cleanup(netdev_priv(opts->net));
		else
			free_netdev(opts->net);
	}
	kfree(opts);
}

static struct usb_function_instance *rndis_alloc_inst(void)
{
	struct f_rndis_opts *opts;

	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
	if (!opts)
		return ERR_PTR(-ENOMEM);

	opts->func_inst.free_func_inst = rndis_free_inst;
	opts->net = gether_setup_default();
	if (IS_ERR(opts->net))
		return ERR_CAST(opts->net);

	return &opts->func_inst;
}

static void rndis_free(struct usb_function *f)
{
	struct f_rndis *rndis;

	rndis = func_to_rndis(f);
	rndis_deregister(rndis->config);
	kfree(rndis);
}

static void rndis_unbind(struct usb_configuration *c, struct usb_function *f)
{
	struct f_rndis		*rndis = func_to_rndis(f);

	rndis_exit();
	rndis_string_defs[0].id = 0;
	usb_free_all_descriptors(f);

	kfree(rndis->notify_req->buf);
	usb_ep_free_request(rndis->notify, rndis->notify_req);
}

static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
{
	struct f_rndis	*rndis;
	struct f_rndis_opts *opts;
	int status;

	/* allocate and initialize one new instance */
	rndis = kzalloc(sizeof(*rndis), GFP_KERNEL);
	if (!rndis) {
		rndis_exit();
		return ERR_PTR(-ENOMEM);
	}

	opts = container_of(fi, struct f_rndis_opts, func_inst);

	gether_get_host_addr_u8(opts->net, rndis->ethaddr);
	rndis->vendorID = opts->vendor_id;
	rndis->manufacturer = opts->manufacturer;

	rndis->port.ioport = netdev_priv(opts->net);
	/* RNDIS activates when the host changes this filter */
	rndis->port.cdc_filter = 0;

	/* RNDIS has special (and complex) framing */
	rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
	rndis->port.wrap = rndis_add_header;
	rndis->port.unwrap = rndis_rm_hdr;

	rndis->port.func.name = "rndis";
	rndis->port.func.strings = rndis_strings;
	/* descriptors are per-instance copies */
	rndis->port.func.bind = rndis_bind;
	rndis->port.func.unbind = rndis_unbind;
	rndis->port.func.set_alt = rndis_set_alt;
	rndis->port.func.setup = rndis_setup;
	rndis->port.func.disable = rndis_disable;
	rndis->port.func.free_func = rndis_free;

	status = rndis_register(rndis_response_available, rndis);
	if (status < 0) {
		kfree(rndis);
		return ERR_PTR(status);
	}
	rndis->config = status;

	return &rndis->port.func;
}

DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Brownell");

#endif
+1 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#define USB_FSUBSET_INCLUDED
#  include "f_subset.c"
#  ifdef USB_ETH_RNDIS
#    define USB_FRNDIS_INCLUDED
#    include "f_rndis.c"
#    include "rndis.h"
#  endif
Loading