| 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 | 
 |