summaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/u_ether.h
blob: fb23d1fde8eb52701cab66b6b1103423d63e13de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/*
 * u_ether.h -- interface to USB gadget "ethernet link" utilities
 *
 * Copyright (C) 2003-2005,2008 David Brownell
 * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
 * Copyright (C) 2008 Nokia Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#ifndef __U_ETHER_H
#define __U_ETHER_H

#include <linux/err.h>
#include <linux/if_ether.h>
#include <linux/usb/composite.h>
#include <linux/usb/cdc.h>

#include "gadget_chips.h"

#define QMULT_DEFAULT 5

/*
 * dev_addr: initial value
 * changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx"
 * host_addr: this address is invisible to ifconfig
 */
#define USB_ETHERNET_MODULE_PARAMETERS() \
	static unsigned qmult = QMULT_DEFAULT;				\
	module_param(qmult, uint, S_IRUGO|S_IWUSR);			\
	MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed");\
									\
	static char *dev_addr;						\
	module_param(dev_addr, charp, S_IRUGO);				\
	MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");		\
									\
	static char *host_addr;						\
	module_param(host_addr, charp, S_IRUGO);			\
	MODULE_PARM_DESC(host_addr, "Host Ethernet Address")

struct eth_dev;

/*
 * This represents the USB side of an "ethernet" link, managed by a USB
 * function which provides control and (maybe) framing.  Two functions
 * in different configurations could share the same ethernet link/netdev,
 * using different host interaction models.
 *
 * There is a current limitation that only one instance of this link may
 * be present in any given configuration.  When that's a problem, network
 * layer facilities can be used to package multiple logical links on this
 * single "physical" one.
 */
struct gether {
	struct usb_function		func;

	/* updated by gether_{connect,disconnect} */
	struct eth_dev			*ioport;

	/* endpoints handle full and/or high speeds */
	struct usb_ep			*in_ep;
	struct usb_ep			*out_ep;

	bool				is_zlp_ok;

	u16				cdc_filter;

	/* hooks for added framing, as needed for RNDIS and EEM. */
	u32				header_len;
	/* NCM requires fixed size bundles */
	bool				is_fixed;
	u32				fixed_out_len;
	u32				fixed_in_len;
	struct sk_buff			*(*wrap)(struct gether *port,
						struct sk_buff *skb);
	int				(*unwrap)(struct gether *port,
						struct sk_buff *skb,
						struct sk_buff_head *list);

	/* called on network open/close */
	void				(*open)(struct gether *);
	void				(*close)(struct gether *);
};

#define	DEFAULT_FILTER	(USB_CDC_PACKET_TYPE_BROADCAST \
			|USB_CDC_PACKET_TYPE_ALL_MULTICAST \
			|USB_CDC_PACKET_TYPE_PROMISCUOUS \
			|USB_CDC_PACKET_TYPE_DIRECTED)

/* variant of gether_setup that allows customizing network device name */
struct eth_dev *gether_setup_name(struct usb_gadget *g,
		const char *dev_addr, const char *host_addr,
		u8 ethaddr[ETH_ALEN], unsigned qmult, const char *netname);

/* netdev setup/teardown as directed by the gadget driver */
/* gether_setup - initialize one ethernet-over-usb link
 * @g: gadget to associated with these links
 * @ethaddr: NULL, or a buffer in which the ethernet address of the
 *	host side of the link is recorded
 * Context: may sleep
 *
 * This sets up the single network link that may be exported by a
 * gadget driver using this framework.  The link layer addresses are
 * set up using module parameters.
 *
 * Returns negative errno, or zero on success
 */
static inline struct eth_dev *gether_setup(struct usb_gadget *g,
		const char *dev_addr, const char *host_addr,
		u8 ethaddr[ETH_ALEN], unsigned qmult)
{
	return gether_setup_name(g, dev_addr, host_addr, ethaddr, qmult, "usb");
}

/*
 * variant of gether_setup_default that allows customizing
 * network device name
 */
struct net_device *gether_setup_name_default(const char *netname);

/*
 * gether_register_netdev - register the net device
 * @net: net device to register
 *
 * Registers the net device associated with this ethernet-over-usb link
 *
 */
int gether_register_netdev(struct net_device *net);

/* gether_setup_default - initialize one ethernet-over-usb link
 * Context: may sleep
 *
 * This sets up the single network link that may be exported by a
 * gadget driver using this framework.  The link layer addresses
 * are set to random values.
 *
 * Returns negative errno, or zero on success
 */
static inline struct net_device *gether_setup_default(void)
{
	return gether_setup_name_default("usb");
}

/**
 * gether_set_gadget - initialize one ethernet-over-usb link with a gadget
 * @net: device representing this link
 * @g: the gadget to initialize with
 *
 * This associates one ethernet-over-usb link with a gadget.
 */
void gether_set_gadget(struct net_device *net, struct usb_gadget *g);

/**
 * gether_set_dev_addr - initialize an ethernet-over-usb link with eth address
 * @net: device representing this link
 * @dev_addr: eth address of this device
 *
 * This sets the device-side Ethernet address of this ethernet-over-usb link
 * if dev_addr is correct.
 * Returns negative errno if the new address is incorrect.
 */
int gether_set_dev_addr(struct net_device *net, const char *dev_addr);

/**
 * gether_get_dev_addr - get an ethernet-over-usb link eth address
 * @net: device representing this link
 * @dev_addr: place to store device's eth address
 * @len: length of the @dev_addr buffer
 *
 * This gets the device-side Ethernet address of this ethernet-over-usb link.
 * Returns zero on success, else negative errno.
 */
int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len);

/**
 * gether_set_host_addr - initialize an ethernet-over-usb link with host address
 * @net: device representing this link
 * @host_addr: eth address of the host
 *
 * This sets the host-side Ethernet address of this ethernet-over-usb link
 * if host_addr is correct.
 * Returns negative errno if the new address is incorrect.
 */
int gether_set_host_addr(struct net_device *net, const char *host_addr);

/**
 * gether_get_host_addr - get an ethernet-over-usb link host address
 * @net: device representing this link
 * @host_addr: place to store eth address of the host
 * @len: length of the @host_addr buffer
 *
 * This gets the host-side Ethernet address of this ethernet-over-usb link.
 * Returns zero on success, else negative errno.
 */
int gether_get_host_addr(struct net_device *net, char *host_addr, int len);

/**
 * gether_get_host_addr_cdc - get an ethernet-over-usb link host address
 * @net: device representing this link
 * @host_addr: place to store eth address of the host
 * @len: length of the @host_addr buffer
 *
 * This gets the CDC formatted host-side Ethernet address of this
 * ethernet-over-usb link.
 * Returns zero on success, else negative errno.
 */
int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len);

/**
 * gether_get_host_addr_u8 - get an ethernet-over-usb link host address
 * @net: device representing this link
 * @host_mac: place to store the eth address of the host
 *
 * This gets the binary formatted host-side Ethernet address of this
 * ethernet-over-usb link.
 */
void gether_get_host_addr_u8(struct net_device *net, u8 host_mac[ETH_ALEN]);

/**
 * gether_set_qmult - initialize an ethernet-over-usb link with a multiplier
 * @net: device representing this link
 * @qmult: queue multiplier
 *
 * This sets the queue length multiplier of this ethernet-over-usb link.
 * For higher speeds use longer queues.
 */
void gether_set_qmult(struct net_device *net, unsigned qmult);

/**
 * gether_get_qmult - get an ethernet-over-usb link multiplier
 * @net: device representing this link
 *
 * This gets the queue length multiplier of this ethernet-over-usb link.
 */
unsigned gether_get_qmult(struct net_device *net);

/**
 * gether_get_ifname - get an ethernet-over-usb link interface name
 * @net: device representing this link
 * @name: place to store the interface name
 * @len: length of the @name buffer
 *
 * This gets the interface name of this ethernet-over-usb link.
 * Returns zero on success, else negative errno.
 */
int gether_get_ifname(struct net_device *net, char *name, int len);

void gether_cleanup(struct eth_dev *dev);

/* connect/disconnect is handled by individual functions */
struct net_device *gether_connect(struct gether *);
void gether_disconnect(struct gether *);

/* Some controllers can't support CDC Ethernet (ECM) ... */
static inline bool can_support_ecm(struct usb_gadget *gadget)
{
	if (!gadget_supports_altsettings(gadget))
		return false;

	/* Everything else is *presumably* fine ... but this is a bit
	 * chancy, so be **CERTAIN** there are no hardware issues with
	 * your controller.  Add it above if it can't handle CDC.
	 */
	return true;
}

/* each configuration may bind one instance of an ethernet link */
int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
		struct eth_dev *dev);
int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
		struct eth_dev *dev);

#ifdef USB_ETH_RNDIS

int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
		u32 vendorID, const char *manufacturer, struct eth_dev *dev);

#else

static inline int
rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
		u32 vendorID, const char *manufacturer, struct eth_dev *dev)
{
	return 0;
}

#endif

/**
 * rndis_bind_config - add RNDIS network link to a configuration
 * @c: the configuration to support the network link
 * @ethaddr: a buffer in which the ethernet address of the host side
 *	side of the link was recorded
 * Context: single threaded during gadget setup
 *
 * Returns zero on success, else negative errno.
 *
 * Caller must have called @gether_setup().  Caller is also responsible
 * for calling @gether_cleanup() before module unload.
 */
static inline int rndis_bind_config(struct usb_configuration *c,
		u8 ethaddr[ETH_ALEN], struct eth_dev *dev)
{
	return rndis_bind_config_vendor(c, ethaddr, 0, NULL, dev);
}


#endif /* __U_ETHER_H */