StillImageClassHost.c 14 KB
Newer Older
1 2
/*
             LUFA Library
3
     Copyright (C) Dean Camera, 2011.
4

5
  dean [at] fourwalledcubicle [dot] com
6
           www.lufa-lib.org
7 8 9
*/

/*
10
  Copyright 2011  Dean Camera (dean [at] fourwalledcubicle [dot] com)
11

12
  Permission to use, copy, modify, distribute, and sell this
13
  software and its documentation for any purpose is hereby granted
14
  without fee, provided that the above copyright notice appear in
15
  all copies and that both that the copyright notice and this
16 17 18
  permission notice and warranty disclaimer appear in supporting
  documentation, and that the name of the author not be used in
  advertising or publicity pertaining to distribution of the
19 20 21 22 23 24 25 26 27 28 29 30 31
  software without specific, written prior permission.

  The author disclaim all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

#define  __INCLUDE_FROM_USB_DRIVER
32 33
#include "../../Core/USBMode.h"

34 35 36
#if defined(USB_CAN_BE_HOST)

#define  __INCLUDE_FROM_SI_DRIVER
37
#define  __INCLUDE_FROM_STILLIMAGE_HOST_C
38
#include "StillImageClassHost.h"
39

40 41
uint8_t SI_Host_ConfigurePipes(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
                               uint16_t ConfigDescriptorSize,
42
                               void* ConfigDescriptorData)
43
{
44 45 46 47
	USB_Descriptor_Endpoint_t*  DataINEndpoint      = NULL;
	USB_Descriptor_Endpoint_t*  DataOUTEndpoint     = NULL;
	USB_Descriptor_Endpoint_t*  EventsEndpoint      = NULL;
	USB_Descriptor_Interface_t* StillImageInterface = NULL;
48

49
	memset(&SIInterfaceInfo->State, 0x00, sizeof(SIInterfaceInfo->State));
50

51
	if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
52
	  return SI_ENUMERROR_InvalidConfigDescriptor;
53

54
	while (!(DataINEndpoint) || !(DataOUTEndpoint) || !(EventsEndpoint))
55
	{
56 57
		if (!(StillImageInterface) ||
		    USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
58
		                              DCOMP_SI_Host_NextSIInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
59
		{
60
			if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
Dean Camera's avatar
Dean Camera committed
61
			                              DCOMP_SI_Host_NextSIInterface) != DESCRIPTOR_SEARCH_COMP_Found)
62
			{
63
				return SI_ENUMERROR_NoCompatibleInterfaceFound;
64
			}
65

66
			StillImageInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
67

68 69 70
			DataINEndpoint  = NULL;
			DataOUTEndpoint = NULL;
			EventsEndpoint  = NULL;
71 72 73 74 75 76

			continue;
		}

		USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);

77
		if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
78 79 80 81 82
		{
			if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
			  EventsEndpoint = EndpointData;
			else
			  DataINEndpoint = EndpointData;
83 84 85
		}
		else
		{
86 87 88
			DataOUTEndpoint = EndpointData;
		}
	}
89

90 91
	for (uint8_t PipeNum = 1; PipeNum < PIPE_TOTAL_PIPES; PipeNum++)
	{
92 93 94 95 96 97 98
		uint16_t Size;
		uint8_t  Type;
		uint8_t  Token;
		uint8_t  EndpointAddress;
		uint8_t  InterruptPeriod;
		bool     DoubleBanked;

99 100
		if (PipeNum == SIInterfaceInfo->Config.DataINPipeNumber)
		{
101 102 103 104 105 106
			Size            = DataINEndpoint->EndpointSize;
			EndpointAddress = DataINEndpoint->EndpointAddress;
			Token           = PIPE_TOKEN_IN;
			Type            = EP_TYPE_BULK;
			DoubleBanked    = SIInterfaceInfo->Config.DataINPipeDoubleBank;
			InterruptPeriod = 0;
107

108 109 110 111
			SIInterfaceInfo->State.DataINPipeSize = DataINEndpoint->EndpointSize;
		}
		else if (PipeNum == SIInterfaceInfo->Config.DataOUTPipeNumber)
		{
112 113 114 115 116 117
			Size            = DataOUTEndpoint->EndpointSize;
			EndpointAddress = DataOUTEndpoint->EndpointAddress;
			Token           = PIPE_TOKEN_OUT;
			Type            = EP_TYPE_BULK;
			DoubleBanked    = SIInterfaceInfo->Config.DataOUTPipeDoubleBank;
			InterruptPeriod = 0;
118

119
			SIInterfaceInfo->State.DataOUTPipeSize = DataOUTEndpoint->EndpointSize;
120
		}
121 122
		else if (PipeNum == SIInterfaceInfo->Config.EventsPipeNumber)
		{
123 124 125 126 127 128
			Size            = EventsEndpoint->EndpointSize;
			EndpointAddress = EventsEndpoint->EndpointAddress;
			Token           = PIPE_TOKEN_IN;
			Type            = EP_TYPE_INTERRUPT;
			DoubleBanked    = SIInterfaceInfo->Config.EventsPipeDoubleBank;
			InterruptPeriod = EventsEndpoint->PollingIntervalMS;
129

130 131
			SIInterfaceInfo->State.EventsPipeSize = EventsEndpoint->EndpointSize;
		}
132 133 134 135 136 137 138 139 140 141 142 143 144
		else
		{
			continue;
		}
		
		if (!(Pipe_ConfigurePipe(PipeNum, Type, Token, EndpointAddress, Size,
		                         DoubleBanked ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE)))
		{
			return SI_ENUMERROR_PipeConfigurationFailed;
		}
		
		if (InterruptPeriod)
		  Pipe_SetInterruptPeriod(InterruptPeriod);
145 146
	}

147
	SIInterfaceInfo->State.InterfaceNumber = StillImageInterface->InterfaceNumber;
148
	SIInterfaceInfo->State.IsActive = true;
149

150 151 152
	return SI_ENUMERROR_NoError;
}

153
uint8_t DCOMP_SI_Host_NextSIInterface(void* const CurrentDescriptor)
154
{
155 156 157
	USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);

	if (Header->Type == DTYPE_Interface)
158
	{
159
		USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
160

161 162 163
		if ((Interface->Class    == SI_CSCP_StillImageClass)    &&
		    (Interface->SubClass == SI_CSCP_StillImageSubclass) &&
		    (Interface->Protocol == SI_CSCP_BulkOnlyProtocol))
164 165 166 167
		{
			return DESCRIPTOR_SEARCH_Found;
		}
	}
168

169 170 171
	return DESCRIPTOR_SEARCH_NotFound;
}

172
uint8_t DCOMP_SI_Host_NextSIInterfaceEndpoint(void* const CurrentDescriptor)
173
{
174 175 176
	USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);

	if (Header->Type == DTYPE_Endpoint)
177
	{
178
		USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
179

180
		uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
181 182

		if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
183
		    (!(Pipe_IsEndpointBound(Endpoint->EndpointAddress))))
184 185 186 187
		{
			return DESCRIPTOR_SEARCH_Found;
		}
	}
188
	else if (Header->Type == DTYPE_Interface)
189 190 191 192 193 194 195
	{
		return DESCRIPTOR_SEARCH_Fail;
	}

	return DESCRIPTOR_SEARCH_NotFound;
}

196
uint8_t SI_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
197
                                PIMA_Container_t* const PIMAHeader)
198 199
{
	uint8_t ErrorCode;
200

201 202 203 204
	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
	  return PIPE_RWSTREAM_DeviceDisconnected;

	if (SIInterfaceInfo->State.IsSessionOpen)
205
	  PIMAHeader->TransactionID = cpu_to_le32(SIInterfaceInfo->State.TransactionID++);
206 207 208 209

	Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
	Pipe_Unfreeze();

210
	if ((ErrorCode = Pipe_Write_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NULL)) != PIPE_RWSTREAM_NoError)
211
	  return ErrorCode;
212

213 214 215 216
	uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0));

	if (ParamBytes)
	{
217
		if ((ErrorCode = Pipe_Write_Stream_LE(&PIMAHeader->Params, ParamBytes, NULL)) != PIPE_RWSTREAM_NoError)
218 219
		  return ErrorCode;
	}
220

Dean Camera's avatar
Dean Camera committed
221
	Pipe_ClearOUT();
222
	Pipe_Freeze();
223

224 225 226
	return PIPE_RWSTREAM_NoError;
}

227
uint8_t SI_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
228
                                   PIMA_Container_t* const PIMAHeader)
229
{
230
	uint16_t TimeoutMSRem        = SI_COMMAND_DATA_TIMEOUT_MS;
231
	uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber();
232 233 234 235 236 237

	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
	  return PIPE_RWSTREAM_DeviceDisconnected;

	Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
	Pipe_Unfreeze();
238

239
	while (!(Pipe_IsINReceived()))
240
	{
241
		uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber();
242

243
		if (CurrentFrameNumber != PreviousFrameNumber)
244
		{
245
			PreviousFrameNumber = CurrentFrameNumber;
246

247 248
			if (!(TimeoutMSRem--))
			  return PIPE_RWSTREAM_Timeout;
249
		}
250

251 252 253 254 255 256
		Pipe_Freeze();
		Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
		Pipe_Unfreeze();

		if (Pipe_IsStalled())
		{
257
			USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
258 259 260 261 262 263 264 265 266
			return PIPE_RWSTREAM_PipeStalled;
		}

		Pipe_Freeze();
		Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
		Pipe_Unfreeze();

		if (Pipe_IsStalled())
		{
267
			USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
268 269
			return PIPE_RWSTREAM_PipeStalled;
		}
270

271 272 273
		if (USB_HostState == HOST_STATE_Unattached)
		  return PIPE_RWSTREAM_DeviceDisconnected;
	}
274

275
	Pipe_Read_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NULL);
276

277
	if (PIMAHeader->Type == CPU_TO_LE16(PIMA_CONTAINER_ResponseBlock))
278 279 280 281
	{
		uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0));

		if (ParamBytes)
282
		  Pipe_Read_Stream_LE(&PIMAHeader->Params, ParamBytes, NULL);
283

284 285
		Pipe_ClearIN();
	}
286

287
	Pipe_Freeze();
288

289 290 291
	return PIPE_RWSTREAM_NoError;
}

292 293 294
uint8_t SI_Host_SendData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
                         void* Buffer,
                         const uint16_t Bytes)
295 296 297 298 299 300 301 302
{
	uint8_t ErrorCode;

	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
	  return PIPE_RWSTREAM_DeviceDisconnected;

	Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
	Pipe_Unfreeze();
303

304
	ErrorCode = Pipe_Write_Stream_LE(Buffer, Bytes, NULL);
305 306 307

	Pipe_ClearOUT();
	Pipe_Freeze();
308

309 310 311
	return ErrorCode;
}

312 313 314
uint8_t SI_Host_ReadData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
                         void* Buffer,
                         const uint16_t Bytes)
315 316 317 318 319 320 321 322 323
{
	uint8_t ErrorCode;

	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
	  return PIPE_RWSTREAM_DeviceDisconnected;

	Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
	Pipe_Unfreeze();

324
	ErrorCode = Pipe_Read_Stream_LE(Buffer, Bytes, NULL);
325 326

	Pipe_Freeze();
327

328 329 330
	return ErrorCode;
}

331
bool SI_Host_IsEventReceived(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
332 333 334 335 336 337 338 339
{
	bool IsEventReceived = false;

	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
	  return false;

	Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipeNumber);
	Pipe_Unfreeze();
340

341 342
	if (Pipe_BytesInPipe())
	  IsEventReceived = true;
343

344
	Pipe_Freeze();
345

346 347 348
	return IsEventReceived;
}

349
uint8_t SI_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
350
                                   PIMA_Container_t* const PIMAHeader)
351 352 353 354 355 356 357 358
{
	uint8_t ErrorCode;

	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
	  return PIPE_RWSTREAM_DeviceDisconnected;

	Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipeNumber);
	Pipe_Unfreeze();
359

360
	ErrorCode = Pipe_Read_Stream_LE(PIMAHeader, sizeof(PIMA_Container_t), NULL);
361

362 363
	Pipe_ClearIN();
	Pipe_Freeze();
364

365 366 367
	return ErrorCode;
}

368
uint8_t SI_Host_OpenSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
369 370
{
	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
371
	  return PIPE_RWSTREAM_DeviceDisconnected;
372 373 374 375 376 377

	uint8_t ErrorCode;

	SIInterfaceInfo->State.TransactionID = 0;
	SIInterfaceInfo->State.IsSessionOpen = false;

378
	PIMA_Container_t PIMABlock = (PIMA_Container_t)
379
		{
380 381 382 383
			.DataLength    = CPU_TO_LE32(PIMA_COMMAND_SIZE(1)),
			.Type          = CPU_TO_LE16(PIMA_CONTAINER_CommandBlock),
			.Code          = CPU_TO_LE16(0x1002),
			.Params        = {CPU_TO_LE32(1)},
384
		};
385

386
	if ((ErrorCode = SI_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
387
	  return ErrorCode;
388

389
	if ((ErrorCode = SI_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
390
	  return ErrorCode;
391

392
	if ((PIMABlock.Type != CPU_TO_LE16(PIMA_CONTAINER_ResponseBlock)) || (PIMABlock.Code != CPU_TO_LE16(0x2001)))
393
	  return SI_ERROR_LOGICAL_CMD_FAILED;
394

395 396 397 398 399
	SIInterfaceInfo->State.IsSessionOpen = true;

	return PIPE_RWSTREAM_NoError;
}

400
uint8_t SI_Host_CloseSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
401 402
{
	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
403
	  return PIPE_RWSTREAM_DeviceDisconnected;
404 405 406

	uint8_t ErrorCode;

407
	PIMA_Container_t PIMABlock = (PIMA_Container_t)
408
		{
409 410 411 412
			.DataLength    = CPU_TO_LE32(PIMA_COMMAND_SIZE(1)),
			.Type          = CPU_TO_LE16(PIMA_CONTAINER_CommandBlock),
			.Code          = CPU_TO_LE16(0x1003),
			.Params        = {CPU_TO_LE32(1)},
413
		};
414

415
	if ((ErrorCode = SI_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
416
	  return ErrorCode;
417

418
	if ((ErrorCode = SI_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
419 420 421 422
	  return ErrorCode;

	SIInterfaceInfo->State.IsSessionOpen = false;

423
	if ((PIMABlock.Type != CPU_TO_LE16(PIMA_CONTAINER_ResponseBlock)) || (PIMABlock.Code != CPU_TO_LE16(0x2001)))
424 425 426 427 428
	  return SI_ERROR_LOGICAL_CMD_FAILED;

	return PIPE_RWSTREAM_NoError;
}

429 430 431 432
uint8_t SI_Host_SendCommand(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
                            const uint16_t Operation,
                            const uint8_t TotalParams,
                            uint32_t* const Params)
433 434
{
	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
435
	  return PIPE_RWSTREAM_DeviceDisconnected;
436 437 438

	uint8_t ErrorCode;

439
	PIMA_Container_t PIMABlock = (PIMA_Container_t)
440
		{
441 442 443
			.DataLength    = cpu_to_le32(PIMA_COMMAND_SIZE(TotalParams)),
			.Type          = CPU_TO_LE16(PIMA_CONTAINER_CommandBlock),
			.Code          = cpu_to_le16(Operation),
444
		};
445

446
	memcpy(&PIMABlock.Params, Params, sizeof(uint32_t) * TotalParams);
447

448
	if ((ErrorCode = SI_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
449 450 451 452 453
	  return ErrorCode;

	return PIPE_RWSTREAM_NoError;
}

454
uint8_t SI_Host_ReceiveResponse(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
455 456
{
	uint8_t ErrorCode;
457
	PIMA_Container_t PIMABlock;
458 459

	if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
460
	  return PIPE_RWSTREAM_DeviceDisconnected;
461

462
	if ((ErrorCode = SI_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
463 464
	  return ErrorCode;

465
	if ((PIMABlock.Type != CPU_TO_LE16(PIMA_CONTAINER_ResponseBlock)) || (PIMABlock.Code != CPU_TO_LE16(0x2001)))
466
	  return SI_ERROR_LOGICAL_CMD_FAILED;
467

468 469 470 471
	return PIPE_RWSTREAM_NoError;
}

#endif
472