Project

General

Profile

RE: Setting the ARM as a USB bulk device » usbctrl.cpp

Michael Williamson, 10/18/2017 11:17 AM

 
1
#include "usbctrl.h"
2
#include "DspParserBase.h"
3
#include "ReportError.h"
4

    
5
#include <errno.h>
6
#include <fcntl.h>
7
#include <unistd.h>
8
#include <memory.h>
9
#include <pthread.h>
10
#include <signal.h>
11
#include <stdlib.h>
12

    
13
#include <sys/types.h>
14
#include <sys/stat.h>
15
#include <sys/ioctl.h>
16
#include <sys/poll.h>
17
#include <stdint.h>
18

    
19
#include <sys/syscall.h>
20
#include <linux/aio_abi.h>
21

    
22
using namespace MityDSP;
23

    
24
extern "C" {
25

    
26
#include <asm/byteorder.h>
27

    
28
#define le16_to_cpu __le16_to_cpu
29

    
30
#include <linux/types.h>
31
#include <linux/usb/gadgetfs.h>
32
#include <linux/usb/ch9.h>
33

    
34
#include "usbstring.h"
35

    
36
#define DRIVER_VENDOR_NUM	0x1EF8 /* Critical Link */
37
#define DRIVER_PRODUCT_NUM	0x1005 /* MityCAM */
38
#define	STRINGID_MFGR		1
39
#define	STRINGID_PRODUCT	2
40
#define	STRINGID_SERIAL		3
41
#define	STRINGID_CONFIG		4
42
#define	STRINGID_INTERFACE	5
43

    
44
#define USB_BUFSIZE (5*1024)
45

    
46
static struct usb_device_descriptor device_desc = {
47
	bLength			: sizeof(device_desc),
48
	bDescriptorType		: USB_DT_DEVICE,
49
	bcdUSB			: __constant_cpu_to_le16(0x0200),
50
	bDeviceClass		: USB_CLASS_VENDOR_SPEC,
51
	bDeviceSubClass		: 0,
52
	bDeviceProtocol		: 0,
53
	bMaxPacketSize0		: 0,
54
	idVendor		: __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
55
	idProduct		: __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
56
	bcdDevice		: __constant_cpu_to_le16(0x0107),
57
	iManufacturer		: STRINGID_MFGR,
58
	iProduct		: STRINGID_PRODUCT,
59
	iSerialNumber		: STRINGID_SERIAL,
60
	bNumConfigurations	: 1,
61
};
62

    
63
#define MAX_USB_POWER	1
64

    
65
static const struct usb_config_descriptor config = {
66
	bLength			: sizeof(config),
67
	bDescriptorType 	: USB_DT_CONFIG,
68
	wTotalLength		: 0,
69
	bNumInterfaces		: 1,
70
	bConfigurationValue	: 3,
71
	iConfiguration		: 0,
72
	bmAttributes		: (USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER),
73
	bMaxPower		: ((MAX_USB_POWER + 1) / 2),
74
};
75

    
76
static const struct usb_interface_descriptor bulk_intf = {
77
	bLength			: sizeof(bulk_intf),
78
	bDescriptorType		: USB_DT_INTERFACE,
79
	bInterfaceNumber	: 0,
80
	bAlternateSetting	: 0,
81
	bNumEndpoints		: 2,
82
	bInterfaceClass		: USB_CLASS_VENDOR_SPEC,
83
	bInterfaceSubClass	: 0,
84
	bInterfaceProtocol	: 0,
85
	iInterface		: STRINGID_INTERFACE,
86
};
87

    
88
static struct usb_endpoint_descriptor fs_source_desc = {
89
	bLength			: USB_DT_ENDPOINT_SIZE,
90
	bDescriptorType		: USB_DT_ENDPOINT,
91
	bEndpointAddress	: USB_DIR_IN | 1,
92
	bmAttributes		: USB_ENDPOINT_XFER_BULK,
93
	wMaxPacketSize		: __constant_cpu_to_le16(64),
94
	bInterval		: 0,
95
	bRefresh		: 0,
96
	bSynchAddress		: 0,
97
};
98

    
99
static struct usb_endpoint_descriptor fs_sink_desc = {
100
	bLength			: USB_DT_ENDPOINT_SIZE,
101
	bDescriptorType		: USB_DT_ENDPOINT,
102
	bEndpointAddress	: USB_DIR_OUT | 2,
103
	bmAttributes		: USB_ENDPOINT_XFER_BULK,
104
	wMaxPacketSize		: __constant_cpu_to_le16(64),
105
	bInterval		: 0,
106
	bRefresh		: 0,
107
	bSynchAddress		: 0,
108
};
109

    
110
static const struct usb_endpoint_descriptor *fs_eps[2] = {
111
	&fs_source_desc,
112
	&fs_sink_desc,
113
};
114

    
115
static struct usb_endpoint_descriptor hs_source_desc = {
116
	bLength			: USB_DT_ENDPOINT_SIZE,
117
	bDescriptorType		: USB_DT_ENDPOINT,
118
	bEndpointAddress	: USB_DIR_IN | 1,
119
	bmAttributes		: USB_ENDPOINT_XFER_BULK,
120
	wMaxPacketSize		: __constant_cpu_to_le16(512),
121
	bInterval		: 0,
122
	bRefresh		: 0,
123
	bSynchAddress		: 0,
124
};
125

    
126
static struct usb_endpoint_descriptor hs_sink_desc = {
127
	bLength			: USB_DT_ENDPOINT_SIZE,
128
	bDescriptorType		: USB_DT_ENDPOINT,
129
	bEndpointAddress	: USB_DIR_OUT | 2,
130
	bmAttributes		: USB_ENDPOINT_XFER_BULK,
131
	wMaxPacketSize		: __constant_cpu_to_le16(512),
132
	bInterval		: 0,
133
	bRefresh		: 0,
134
	bSynchAddress		: 0,
135
};
136

    
137
static const struct usb_endpoint_descriptor *hs_eps[2] = {
138
	&hs_source_desc,
139
	&hs_sink_desc,
140
};
141

    
142
static char serial[64];
143

    
144
static struct usb_string stringtab[] = {
145
	{ STRINGID_MFGR,	"Critical Link, LLC", },
146
	{ STRINGID_PRODUCT,	"MityCAM", },
147
	{ STRINGID_SERIAL,	serial, },
148
	{ STRINGID_CONFIG,	"Config", },
149
	{ STRINGID_INTERFACE,	"Bulk Transfer", },
150
};
151

    
152
static struct usb_gadget_strings strings = {
153
	language	: 0x0409, /* en-us */
154
	strings		: stringtab,
155
};
156

    
157
}
158

    
159
/**
160
 *  Gadget FS Based USB peripheral driver code.
161
 *
162
 *  \param[in] apParser pointer to valid parser for data handling
163
 *  \param[in] anSerial the camera serial number
164
 *  \param[in] apRe pointer to valid report error class
165
 */
166
tcUSB::tcUSB(tcDspParserBase* apParser, int anSerial, tcReportError* apRe)
167
: mnEP0Fd(-1)
168
, mnBulkInFd(-1)
169
, mnBulkOutFd(-1)
170
, mpParser(apParser)
171
, mhEP0Thread(pthread_self())
172
, mhBulkThread(pthread_self())
173
, mhStartupThread(pthread_self())
174
, mnBytesIn(0)
175
, mpReportError(apRe)
176
, mbConnected(false)
177
{
178
	sprintf(serial, "%d", anSerial);
179
}
180

    
181
/**
182
 *  Interface destructor 
183
 */
184
tcUSB::~tcUSB(void)
185
{
186
	if (mnEP0Fd >= 0)
187
		close(mnEP0Fd);
188
}
189

    
190
char* tcUSB::build_config(char* cp,
191
	const struct usb_endpoint_descriptor **ep)
192
{
193
	struct usb_config_descriptor *c;
194
	int i;
195

    
196
	c = (struct usb_config_descriptor *)cp;
197

    
198
	memcpy(cp, &config, config.bLength);
199
	cp += config.bLength;
200

    
201
	memcpy(cp, &bulk_intf, bulk_intf.bLength);
202
	cp += bulk_intf.bLength;
203

    
204
	for (i = 0; i < bulk_intf.bNumEndpoints; i++)
205
	{
206
		memcpy(cp, ep[i], USB_DT_ENDPOINT_SIZE);
207
		cp += USB_DT_ENDPOINT_SIZE;
208
	}
209
	c->wTotalLength = __cpu_to_le16(cp - (char*)c);
210
	return cp;
211
}
212

    
213
int tcUSB::Initialize(void)
214
{
215
	char buf[4096], *cp = &buf[0];
216
	int rv, status;
217

    
218
	mnEP0Fd = open("/dev/gadgetfs/musb-hdrc", O_RDWR);
219
	if (mnEP0Fd < 0)
220
	{
221
		return mnEP0Fd;
222
	}
223
	mpReportError->Report("usb device opened\n");
224

    
225
	*(__u32 *)cp = 0;
226
	cp += 4;
227

    
228
	/* write full speed configs */
229
	cp = build_config(cp, fs_eps);
230

    
231
	/* write high speed configs */
232
	cp = build_config(cp, hs_eps);
233

    
234
	/* write device descriptor */
235
	memcpy(cp, &device_desc, sizeof(device_desc));
236
	cp += sizeof(device_desc);
237

    
238
	rv = write(mnEP0Fd, &buf[0], cp - buf);
239
	if (rv < 0)
240
	{
241
		mpReportError->Report("initial write error : %s\n", strerror(errno));
242
		close(mnEP0Fd);
243
		mnEP0Fd = -1;
244
		return mnEP0Fd;
245
	}
246
	else if (rv != (cp - buf))
247
	{
248
		mpReportError->Report("rv mismatch : %d, %d\n", rv, (cp-buf));
249
		close(mnEP0Fd);
250
		mnEP0Fd = -2;
251
		return mnEP0Fd;
252
	}
253

    
254

    
255
	/* spawn the control endpoint reader thread */
256
	pthread_attr_t attr;
257
	rv = pthread_attr_init(&attr);
258

    
259
	status = pthread_create(&mhEP0Thread, &attr, DispatchEP0Handler, (void*)this);
260
	if (status)
261
	{
262
		mpReportError->Report("pthread_create (network poll thread) : %s\n", strerror(errno));
263
		return status;
264
	}
265

    
266
	return 0;
267
}
268

    
269
int tcUSB::StopIO(void)
270
{
271
	if (!pthread_equal(mhBulkThread, mhStartupThread))
272
	{
273
		pthread_cancel(mhBulkThread);
274
		if (pthread_join(mhBulkThread, 0) != 0)
275
		{
276
			mpReportError->Report("Could not stop Bulk Thread");
277
		}
278
		else
279
		{
280
			close(mnBulkOutFd);
281
			mnBulkOutFd = -1;
282
		}
283
		mhBulkThread = mhStartupThread;
284
	}
285
	if (mnBulkInFd >= 0)
286
	{
287
		close(mnBulkInFd);
288
		mnBulkInFd = -1;
289
	}
290
	return 0;
291
}
292

    
293
int tcUSB::StartIO(void)
294
{
295
	int status, rv;
296
	uint32_t bufi[256/4];
297
	char* buf = (char*)&bufi[0];
298
	pthread_attr_t attr;
299

    
300
	rv = pthread_attr_init(&attr);
301

    
302
	/* open up the bulk input endpoint (relative to PC)
303
	 * file descriptor for sending data via put() call */
304
	mnBulkInFd = open("/dev/gadgetfs/ep1in", O_WRONLY);
305
	if (mnBulkInFd < 0) 
306
	{
307
		mpReportError->Report("Could not open ep1in (%s)\n",
308
			strerror(errno));
309
		return -errno;
310
	}
311

    
312
	/* write full speed descriptor in */
313
	*(uint32_t *)buf = 1;
314
	memcpy(buf + 4, &fs_source_desc, USB_DT_ENDPOINT_SIZE);
315

    
316
	/* write high speed descriptor in */
317
	memcpy(buf + 4 + USB_DT_ENDPOINT_SIZE,
318
		&hs_source_desc, USB_DT_ENDPOINT_SIZE);
319

    
320
	/* push it to control framework */
321
	if (write(mnBulkInFd, buf, 4 + 2 * USB_DT_ENDPOINT_SIZE) < 0)
322
	{
323
		mpReportError->Report("Could not setup bulkin descriptors "
324
			" (%s)\n", strerror(errno));
325
		close(mnBulkInFd);
326
		return -errno;
327
	}
328

    
329
	/* open up the bulk output endpoint (relative to PC)
330
	 * file descriptor for receiving app data */
331
	mnBulkOutFd = open("/dev/gadgetfs/ep2out", O_RDWR);
332
	if (mnBulkOutFd < 0)
333
	{
334
		mpReportError->Report("Could not open ep2out (%s)\n",
335
			strerror(errno));
336
		close(mnBulkInFd);
337
		return -errno;
338
	}
339

    
340
	/* write full speed descriptor in */
341
	*(uint32_t *)buf = 1;
342
	memcpy(buf + 4, &fs_sink_desc, USB_DT_ENDPOINT_SIZE);
343

    
344
	/* write high speed descriptor in */
345
	memcpy(buf + 4 + USB_DT_ENDPOINT_SIZE,
346
		&hs_sink_desc, USB_DT_ENDPOINT_SIZE);
347

    
348
	/* push it to control framework */
349
	if (write(mnBulkOutFd, buf, 4 + 2 * USB_DT_ENDPOINT_SIZE) < 0)
350
	{
351
		mpReportError->Report("Could not setup bulkout descriptors "
352
			" (%s)\n", strerror(errno));
353
		close(mnBulkInFd);
354
		close(mnBulkOutFd);
355
		return -errno;
356
	}
357

    
358
	/* spawn the bulk endpoint reader thread */
359
	status = pthread_create(&mhBulkThread, &attr, DispatchBulkInHandler, (void*)this);
360
	if (status)
361
	{
362
		mpReportError->Report("pthread_create (usb poll thread) : %s\n", strerror(errno));
363
	}
364

    
365
	return status;
366
}
367

    
368
void* tcUSB::DispatchEP0Handler(void *apThis)
369
{
370
	tcUSB *lpUSB = (tcUSB *)apThis;
371
	lpUSB->EP0Handler();
372
	return NULL;
373
}
374

    
375
#define USB_REQ_GET_STATE	0xDF
376
#define USB_REQ_CLEAR_INKTEND	0xDF
377
#define USB_REQ_PEEK_BUFF	0xDD
378
#define USB_REQ_POKE_BUFF	0xDC
379
#define USB_REQ_WRITE_SN	0xDB
380
#define USB_REQ_READ_SN		0xDA
381

    
382
int tcUSB::HandleControl(struct usb_ctrlrequest *setup)
383
{
384
	uint16_t value, index, length;
385
	uint8_t buf[256];
386
	int status, tmp;
387

    
388
	value = __le16_to_cpu(setup->wValue);
389
	index = __le16_to_cpu(setup->wIndex);
390
	length = __le16_to_cpu(setup->wLength);
391

    
392
#if 0
393
	printf("Handle Control : %02x.%02x v%04x i%04x %d\n",
394
			setup->bRequestType, setup->bRequest,
395
			value, index, length);
396
#endif
397
	
398
	switch(setup->bRequest)
399
	{
400
	case USB_REQ_GET_DESCRIPTOR:
401
		switch(value >> 8)
402
		{
403
		case USB_DT_STRING:
404
			tmp = value & 0xFF;
405
			if (tmp || index != strings.language)
406
				goto stall;
407
			status = usb_gadget_get_string(&strings, tmp, buf);
408
			if (status < 0)
409
				goto stall;
410
			tmp = status;
411
			if (length < tmp)
412
				tmp = length;
413
			write(mnEP0Fd, buf, tmp);
414
			break;
415
		default:
416
			goto stall;
417
		}
418
		return 0;
419

    
420
	case USB_REQ_SET_CONFIGURATION:
421
		if (setup->bRequestType != USB_DIR_OUT)
422
			goto stall;
423
		if (value)
424
		{
425
			StartIO();
426
		}
427
		else
428
		{
429
			StopIO();
430
		}
431
		status = read(mnEP0Fd, &status, 0);
432
		if (status)
433
			mpReportError->Report("ack SET_CONFIGURATION\n");
434
		return 0;
435

    
436
	case USB_REQ_GET_INTERFACE:
437
		return 0;
438

    
439
	case USB_REQ_SET_INTERFACE:
440
		return 0;
441

    
442
	case USB_REQ_GET_STATE:
443
		for (int i = 0; i < 20; ++i)
444
		{
445
			buf[i] = 0x01;
446
		}
447
		status = write(mnEP0Fd, buf, 20);
448
		if (status < 0)
449
			goto stall;
450
		return 0;
451

    
452
	case USB_REQ_PEEK_BUFF:
453
		for (int i = 0; i < 48; ++i)
454
		{
455
			buf[i] = 0x00;
456
		}
457
		status = write(mnEP0Fd, buf, 48);
458
		if (status < 0)
459
			goto stall;
460
		return 0;
461

    
462
	case USB_REQ_POKE_BUFF:
463
		status = read(mnEP0Fd, &status, 0);
464
		return 0;
465

    
466
	default:
467
		goto stall;
468
	}
469

    
470
stall:
471
	if (setup->bRequestType & USB_DIR_IN)
472
		status = read(mnEP0Fd, &status, 0);
473
	else
474
		status = write(mnEP0Fd, &status, 0);
475

    
476
	if (errno != EL2HLT)
477
		mpReportError->Report("ep0 stall");
478

    
479
	return 0;
480
}
481

    
482
int tcUSB::EP0Handler(void)
483
{
484
	struct pollfd ep0_poll;
485

    
486
	ep0_poll.fd = mnEP0Fd;
487
	ep0_poll.events = POLLIN | POLLOUT | POLLHUP;
488

    
489
	while (true)
490
	{
491
		int	tmp, i, nevent;
492
		struct usb_gadgetfs_event	event[8];
493

    
494
		/* TODO - infinite timeout? */
495
		tmp = poll(&ep0_poll, 1, -1);
496
		if (tmp < 0)
497
		{
498
			mpReportError->Report("%s: poll : %s", __func__, strerror(errno));
499
			break;
500
		}
501

    
502
		tmp = read(mnEP0Fd, &event, sizeof(event));
503
		if (tmp < 0)
504
		{
505
			if (errno == EAGAIN)
506
			{
507
				continue;
508
			}
509
			mpReportError->Report("ep0 read after poll : %s\n", strerror(errno));
510
			goto done;
511
		}
512
		nevent = tmp / sizeof(event[0]);
513
		for(i = 0; i < nevent; ++i)
514
		{
515
			switch(event[i].type)
516
			{
517
			case GADGETFS_NOP:
518
				break;
519
			case GADGETFS_CONNECT:
520
				mbConnected = true;
521
				break;
522
			case GADGETFS_SETUP:
523
				mbConnected = true;
524
				HandleControl(&event[i].u.setup);
525
				break;
526
			case GADGETFS_DISCONNECT:
527
				mbConnected = false;
528
				StopIO();
529
				break;
530
			case GADGETFS_SUSPEND:
531
				break;
532
			default:
533
				mpReportError->Report("unhandled USB event %d\n", event[i].type);
534
				break;
535
			}
536
		}
537
		continue;
538
done:
539
		if (mbConnected)
540
			StopIO();
541
		break;
542
	}
543
	return 0;
544
}
545

    
546
void* tcUSB::DispatchBulkInHandler(void *apThis)
547
{
548
	tcUSB *lpUSB = (tcUSB *)apThis;
549
	lpUSB->BulkInHandler();
550
	return NULL;
551
}
552

    
553
int tcUSB::BulkInHandler(void)
554
{
555
	int	status;
556
	char	buf[USB_BUFSIZE];
557

    
558
	while(true)
559
	{
560
		status = read(mnBulkOutFd, buf, sizeof(buf));
561
		if (status < 0)
562
		{
563
			break;
564
		}
565
		if (status) {
566
			mnBytesIn += status;
567
			mpParser->AddData(buf, status);
568
		}
569
	}
570
	return 0;
571
}
572

    
573
#define USEAIO
574

    
575
#ifdef USEAIO
576
inline int io_setup(unsigned nr, aio_context_t *ctxp)
577
{
578
	return syscall(__NR_io_setup, nr, ctxp);
579
}
580

    
581
inline int io_destroy(aio_context_t ctx)
582
{
583
	return syscall(__NR_io_destroy, ctx);
584
}
585

    
586
inline int io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp)
587
{
588
	return syscall(__NR_io_submit, ctx, nr, iocbpp);
589
}
590

    
591
inline int io_getevents(aio_context_t ctx, long min_nr, long max_nr,
592
			struct io_event *events, struct timespect *timeout)
593
{
594
	return syscall(__NR_io_getevents, ctx, min_nr, max_nr, events, timeout);
595
}
596

    
597
#define NUM_BUFFERS 8
598
aio_context_t ctx;
599
struct iocb iocb[NUM_BUFFERS];
600
static int pingpong = 0;
601
struct io_event events[NUM_BUFFERS];
602
char *buffers[NUM_BUFFERS];
603
#endif
604

    
605
int bufpos = 0;
606
#define BUFFER_SIZE	(64*1024)
607
char buffer[BUFFER_SIZE];
608

    
609
/**
610
 *  Send data via Bulk transfer output endpoint.
611
 */
612
int tcUSB::put(const char* data, int length, int flush)
613
{
614
	int rv, bytes_sent = 0;
615
	int index;
616
	if (length <= 0)
617
	{
618
		/* printf("Length was %d\n", length); */
619
		return 0;
620
	}
621
	if (mbConnected && mnBytesIn && (mnBulkInFd >= 0))
622
	{
623
#ifndef USEAIO
624
		if (bufpos + length > BUFFER_SIZE)
625
		{
626
			rv = write(mnBulkInFd, buffer, bufpos);
627
			bufpos = 0;
628
		}
629
		memcpy(&buffer[bufpos], data, length);
630
		bufpos += length;
631
		if (flush) {
632
			rv = write(mnBulkInFd, &buffer[0], bufpos);
633
			bufpos = 0;
634
		}
635
#else
636
		if (0 == pingpong && !bufpos)
637
		{
638
			for (int i = 0; i < NUM_BUFFERS; ++i)
639
				buffers[i] = (char*)malloc(BUFFER_SIZE);
640

    
641
			rv = io_setup(NUM_BUFFERS+1, &ctx);
642
			if (rv < 0)
643
			{
644
				perror("io_setup");
645
				return -1;
646
			}
647
		}
648
		index = pingpong;
649
		index %= NUM_BUFFERS;
650

    
651
		int recoverbufs = 0; /* number of buffers we will transfer */
652
		int first_buf_size = 0;
653

    
654
		/* if we can't fit this packet in our current buffer, advance to next
655
		 * and note fact by increasing buffer transfer count */
656
		if (bufpos + length > BUFFER_SIZE)
657
		{
658
			recoverbufs++;
659
			index++;
660
			index %= NUM_BUFFERS;
661
			first_buf_size = bufpos;
662
			bufpos = 0;
663
		}
664
		/* if we have to flush, then we must mark this packet to transfer */
665
		if (flush)
666
			recoverbufs++;
667

    
668
		/* if we need to transfer and all our buffers are outstanding, then
669
		 * wait for some to recover */
670
		if (recoverbufs && (pingpong+recoverbufs > NUM_BUFFERS))
671
		{
672
			rv = io_getevents(ctx, recoverbufs, recoverbufs, events, NULL);
673
			if (rv < 0)
674
			{
675
				printf("io_getevents : %d\n", rv);
676
				return -1;
677
			}
678
		}
679

    
680
		/* if two transfers send first packet */
681
		if (first_buf_size)
682
		{
683
			int tmp = index-1;
684
			if (tmp < 0) tmp = NUM_BUFFERS-1;
685
			memset(&iocb[tmp],0,sizeof(iocb[tmp]));
686
			iocb[tmp].aio_fildes = mnBulkInFd;
687
			iocb[tmp].aio_lio_opcode = IOCB_CMD_PWRITE;
688
			iocb[tmp].aio_buf = (__u64)buffers[tmp];
689
			iocb[tmp].aio_nbytes = first_buf_size;
690
			iocb[tmp].aio_offset = 0;
691
			struct iocb *cbs[1];
692
			cbs[0] = &iocb[tmp];
693
			rv = io_submit(ctx, 1, cbs);
694
			if (rv != 1)
695
			{
696
				perror("io_submit\n");
697
				return -1;
698
			}
699
		}
700
		/* copy packet data in... */
701
		memcpy(&buffers[index][bufpos], data, length);
702
		bufpos += length;
703

    
704
		/* if we need to transfer this packet, send it out */
705
		if (flush)
706
		{
707
			memset(&iocb[index],0,sizeof(iocb[index]));
708
			iocb[index].aio_fildes = mnBulkInFd;
709
			iocb[index].aio_lio_opcode = IOCB_CMD_PWRITE;
710
			iocb[index].aio_buf = (__u64)buffers[index];
711
			iocb[index].aio_nbytes = bufpos;
712
			iocb[index].aio_offset = 0;
713
			struct iocb *cbs[1];
714
			cbs[0] = &iocb[index];
715
			bufpos = 0;
716
			rv = io_submit(ctx, 1, cbs);
717
			if (rv != 1)
718
			{
719
				perror("io_submit\n");
720
				return -1;
721
			}
722
		}
723

    
724
		bytes_sent = length;
725
		pingpong += recoverbufs;
726
#endif	
727
	}
728
	else
729
	{
730
		return -1;
731
	}
732
	return bytes_sent;
733
}
734

    
(1-1/4) Go to top
Add picture from clipboard (Maximum size: 1 GB)