Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
  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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
/*
 * Copyright (C) 2003-2008 Takahiro Hirofuchi
 *
 * This 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.
 *
 * This is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
 * USA.
 */

#ifndef __VHCI_COMMON_H
#define __VHCI_COMMON_H


#include <linux/version.h>
#include <linux/usb.h>
#include <asm/byteorder.h>
#include <net/sock.h>

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

/*
 * define macros to print messages
 */

/**
 * udbg - print debug messages if CONFIG_USB_DEBUG is defined
 * @fmt:
 * @args:
 */

#ifdef CONFIG_USB_DEBUG

#define udbg(fmt, args...)						\
	do {								\
		printk(KERN_DEBUG "%-10s:(%s,%d) %s: " fmt,		\
			(in_interrupt() ? "interrupt" : (current)->comm),\
			__FILE__, __LINE__, __func__, ##args);	\
	} while (0)

#else  /* CONFIG_USB_DEBUG */

#define udbg(fmt, args...)		do { } while (0)

#endif /* CONFIG_USB_DEBUG */


enum {
	usbip_debug_xmit	= (1 << 0),
	usbip_debug_sysfs	= (1 << 1),
	usbip_debug_urb		= (1 << 2),
	usbip_debug_eh		= (1 << 3),

	usbip_debug_stub_cmp	= (1 << 8),
	usbip_debug_stub_dev	= (1 << 9),
	usbip_debug_stub_rx	= (1 << 10),
	usbip_debug_stub_tx	= (1 << 11),

	usbip_debug_vhci_rh	= (1 << 8),
	usbip_debug_vhci_hc	= (1 << 9),
	usbip_debug_vhci_rx	= (1 << 10),
	usbip_debug_vhci_tx	= (1 << 11),
	usbip_debug_vhci_sysfs  = (1 << 12)
};

#define dbg_flag_xmit		(usbip_debug_flag & usbip_debug_xmit)
#define dbg_flag_vhci_rh	(usbip_debug_flag & usbip_debug_vhci_rh)
#define dbg_flag_vhci_hc	(usbip_debug_flag & usbip_debug_vhci_hc)
#define dbg_flag_vhci_rx	(usbip_debug_flag & usbip_debug_vhci_rx)
#define dbg_flag_vhci_tx	(usbip_debug_flag & usbip_debug_vhci_tx)
#define dbg_flag_vhci_sysfs	(usbip_debug_flag & usbip_debug_vhci_sysfs)
#define dbg_flag_stub_rx	(usbip_debug_flag & usbip_debug_stub_rx)
#define dbg_flag_stub_tx	(usbip_debug_flag & usbip_debug_stub_tx)

extern unsigned long usbip_debug_flag;
extern struct device_attribute dev_attr_usbip_debug;

#define dbg_with_flag(flag, fmt, args...)		\
	do {						\
		if (flag & usbip_debug_flag)		\
			udbg(fmt , ##args);		\
	} while (0)

#define dbg_sysfs(fmt, args...)		\
	dbg_with_flag(usbip_debug_sysfs, fmt , ##args)
#define dbg_xmit(fmt, args...)		\
	dbg_with_flag(usbip_debug_xmit, fmt , ##args)
#define dbg_urb(fmt, args...)		\
	dbg_with_flag(usbip_debug_urb, fmt , ##args)
#define dbg_eh(fmt, args...)		\
	dbg_with_flag(usbip_debug_eh, fmt , ##args)

#define dbg_vhci_rh(fmt, args...)	\
	dbg_with_flag(usbip_debug_vhci_rh, fmt , ##args)
#define dbg_vhci_hc(fmt, args...)	\
	dbg_with_flag(usbip_debug_vhci_hc, fmt , ##args)
#define dbg_vhci_rx(fmt, args...)	\
	dbg_with_flag(usbip_debug_vhci_rx, fmt , ##args)
#define dbg_vhci_tx(fmt, args...)	\
	dbg_with_flag(usbip_debug_vhci_tx, fmt , ##args)
#define dbg_vhci_sysfs(fmt, args...)	\
	dbg_with_flag(usbip_debug_vhci_sysfs, fmt , ##args)

#define dbg_stub_cmp(fmt, args...)	\
	dbg_with_flag(usbip_debug_stub_cmp, fmt , ##args)
#define dbg_stub_rx(fmt, args...)	\
	dbg_with_flag(usbip_debug_stub_rx, fmt , ##args)
#define dbg_stub_tx(fmt, args...)	\
	dbg_with_flag(usbip_debug_stub_tx, fmt , ##args)


/**
 * uerr - print error messages
 * @fmt:
 * @args:
 */
#define uerr(fmt, args...)						\
	do {								\
		printk(KERN_ERR "%-10s: ***ERROR*** (%s,%d) %s: " fmt,	\
			(in_interrupt() ? "interrupt" : (current)->comm),\
			__FILE__, __LINE__, __func__, ##args);	\
	} while (0)

/**
 * uinfo - print information messages
 * @fmt:
 * @args:
 */
#define uinfo(fmt, args...)					\
	do {							\
		printk(KERN_INFO "usbip: " fmt , ## args);	\
	} while (0)


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

/*
 * USB/IP request headers.
 * Currently, we define 4 request types:
 *
 *  - CMD_SUBMIT transfers a USB request, corresponding to usb_submit_urb().
 *    (client to server)
 *  - RET_RETURN transfers the result of CMD_SUBMIT.
 *    (server to client)
 *  - CMD_UNLINK transfers an unlink request of a pending USB request.
 *    (client to server)
 *  - RET_UNLINK transfers the result of CMD_UNLINK.
 *    (server to client)
 *
 * Note: The below request formats are based on the USB subsystem of Linux. Its
 * details will be defined when other implementations come.
 *
 *
 */

/*
 * A basic header followed by other additional headers.
 */
struct usbip_header_basic {
#define USBIP_CMD_SUBMIT	0x0001
#define USBIP_CMD_UNLINK	0x0002
#define USBIP_RET_SUBMIT	0x0003
#define USBIP_RET_UNLINK	0x0004
	__u32 command;

	 /* sequencial number which identifies requests.
	  * incremented per connections */
	__u32 seqnum;

	/* devid is used to specify a remote USB device uniquely instead
	 * of busnum and devnum in Linux. In the case of Linux stub_driver,
	 * this value is ((busnum << 16) | devnum) */
	__u32 devid;

#define USBIP_DIR_OUT	0
#define USBIP_DIR_IN 	1
	__u32 direction;
	__u32 ep;     /* endpoint number */
} __attribute__ ((packed));

/*
 * An additional header for a CMD_SUBMIT packet.
 */
struct usbip_header_cmd_submit {
	/* these values are basically the same as in a URB. */

	/* the same in a URB. */
	__u32 transfer_flags;

	/* set the following data size (out),
	 * or expected reading data size (in) */
	__s32 transfer_buffer_length;

	/* it is difficult for usbip to sync frames (reserved only?) */
	__s32 start_frame;

	/* the number of iso descriptors that follows this header */
	__s32 number_of_packets;

	/* the maximum time within which this request works in a host
	 * controller of a server side */
	__s32 interval;

	/* set setup packet data for a CTRL request */
	unsigned char setup[8];
} __attribute__ ((packed));

/*
 * An additional header for a RET_SUBMIT packet.
 */
struct usbip_header_ret_submit {
	__s32 status;
	__s32 actual_length; /* returned data length */
	__s32 start_frame; /* ISO and INT */
	__s32 number_of_packets;  /* ISO only */
	__s32 error_count; /* ISO only */
} __attribute__ ((packed));

/*
 * An additional header for a CMD_UNLINK packet.
 */
struct usbip_header_cmd_unlink {
	__u32 seqnum; /* URB's seqnum which will be unlinked */
} __attribute__ ((packed));


/*
 * An additional header for a RET_UNLINK packet.
 */
struct usbip_header_ret_unlink {
	__s32 status;
} __attribute__ ((packed));


/* the same as usb_iso_packet_descriptor but packed for pdu */
struct usbip_iso_packet_descriptor {
	__u32 offset;
	__u32 length;            /* expected length */
	__u32 actual_length;
	__u32 status;
} __attribute__ ((packed));


/*
 * All usbip packets use a common header to keep code simple.
 */
struct usbip_header {
	struct usbip_header_basic base;

	union {
		struct usbip_header_cmd_submit	cmd_submit;
		struct usbip_header_ret_submit	ret_submit;
		struct usbip_header_cmd_unlink	cmd_unlink;
		struct usbip_header_ret_unlink	ret_unlink;
	} u;
} __attribute__ ((packed));




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


int usbip_xmit(int, struct socket *, char *, int, int);
int usbip_sendmsg(struct socket *, struct msghdr *, int);


static inline int interface_to_busnum(struct usb_interface *interface)
{
	struct usb_device *udev = interface_to_usbdev(interface);
	return udev->bus->busnum;
}

static inline int interface_to_devnum(struct usb_interface *interface)
{
	struct usb_device *udev = interface_to_usbdev(interface);
	return udev->devnum;
}

static inline int interface_to_infnum(struct usb_interface *interface)
{
	return interface->cur_altsetting->desc.bInterfaceNumber;
}

#if 0
int setnodelay(struct socket *);
int setquickack(struct socket *);
int setkeepalive(struct socket *socket);
void setreuse(struct socket *);
#endif

struct socket *sockfd_to_socket(unsigned int);
int set_sockaddr(struct socket *socket, struct sockaddr_storage *ss);

void usbip_dump_urb(struct urb *purb);
void usbip_dump_header(struct usbip_header *pdu);


struct usbip_device;

struct usbip_task {
	struct task_struct *thread;
	struct completion thread_done;
	char *name;
	void (*loop_ops)(struct usbip_task *);
};

enum usbip_side {
	USBIP_VHCI,
	USBIP_STUB,
};

enum usbip_status {
	/* sdev is available. */
	SDEV_ST_AVAILABLE = 0x01,
	/* sdev is now used. */
	SDEV_ST_USED,
	/* sdev is unusable because of a fatal error. */
	SDEV_ST_ERROR,

	/* vdev does not connect a remote device. */
	VDEV_ST_NULL,
	/* vdev is used, but the USB address is not assigned yet */
	VDEV_ST_NOTASSIGNED,
	VDEV_ST_USED,
	VDEV_ST_ERROR
};

/* a common structure for stub_device and vhci_device */
struct usbip_device {
	enum usbip_side side;

	enum usbip_status status;

	/* lock for status */
	spinlock_t lock;

	struct socket *tcp_socket;

	struct usbip_task tcp_rx;
	struct usbip_task tcp_tx;

	/* event handler */
#define USBIP_EH_SHUTDOWN	(1 << 0)
#define USBIP_EH_BYE		(1 << 1)
#define USBIP_EH_RESET		(1 << 2)
#define USBIP_EH_UNUSABLE	(1 << 3)

#define SDEV_EVENT_REMOVED	(USBIP_EH_SHUTDOWN | USBIP_EH_RESET | USBIP_EH_BYE)
#define	SDEV_EVENT_DOWN		(USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
#define	SDEV_EVENT_ERROR_TCP	(USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
#define	SDEV_EVENT_ERROR_SUBMIT	(USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
#define	SDEV_EVENT_ERROR_MALLOC	(USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE)

#define	VDEV_EVENT_REMOVED	(USBIP_EH_SHUTDOWN | USBIP_EH_BYE)
#define	VDEV_EVENT_DOWN		(USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
#define	VDEV_EVENT_ERROR_TCP	(USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
#define	VDEV_EVENT_ERROR_MALLOC	(USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE)

	unsigned long event;
	struct usbip_task eh;
	wait_queue_head_t eh_waitq;

	struct eh_ops {
		void (*shutdown)(struct usbip_device *);
		void (*reset)(struct usbip_device *);
		void (*unusable)(struct usbip_device *);
	} eh_ops;
};


void usbip_task_init(struct usbip_task *ut, char *,
				void (*loop_ops)(struct usbip_task *));

void usbip_start_threads(struct usbip_device *ud);
void usbip_stop_threads(struct usbip_device *ud);
int usbip_thread(void *param);

void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd,
								int pack);

void usbip_header_correct_endian(struct usbip_header *pdu, int send);
/* some members of urb must be substituted before. */
int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb);
/* some members of urb must be substituted before. */
int usbip_recv_iso(struct usbip_device *ud, struct urb *urb);
void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen);


/* usbip_event.c */
void usbip_start_eh(struct usbip_device *ud);
void usbip_stop_eh(struct usbip_device *ud);
void usbip_event_add(struct usbip_device *ud, unsigned long event);
int usbip_event_happend(struct usbip_device *ud);


#endif