MCUXpresso_LPC55S69/boards/lpcxpresso55s69/usb_examples/usb_device_printer_virtual_plain_text/bm/cm33_core0/usb_device_printer.c
2022-04-08 22:42:47 +08:00

681 lines
28 KiB
C

/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "usb_device_config.h"
#include "usb.h"
#include "usb_device.h"
#include "usb_device_class.h"
#if ((defined(USB_DEVICE_CONFIG_PRINTER)) && (USB_DEVICE_CONFIG_PRINTER > 0U))
#include "usb_device_printer.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_printer_struct_t
s_PrinterHandle[USB_DEVICE_CONFIG_PRINTER];
/*******************************************************************************
* Code
******************************************************************************/
static usb_status_t USB_DevicePrinterAllocateHandle(usb_device_printer_struct_t **printerHandle)
{
uint8_t index;
for (index = 0; index < USB_DEVICE_CONFIG_PRINTER; ++index)
{
if (s_PrinterHandle[index].deviceHandle == NULL)
{
*printerHandle = &(s_PrinterHandle[index]);
return kStatus_USB_Success;
}
}
return kStatus_USB_Busy;
}
static usb_status_t USB_DevicePrinterFreeHandle(usb_device_printer_struct_t *printerHandle)
{
/* ensure that printerHandle is not NULL before calling this function */
printerHandle->deviceHandle = NULL;
printerHandle->classConfig = NULL;
printerHandle->alternate = 0xFFu;
printerHandle->configuration = 0;
printerHandle->interfaceNumber = 0;
return kStatus_USB_Success;
}
/*!
* @brief bulk IN endpoint callback function.
*
* This callback function is used to notify upper layer the transfer result of a transfer.
* This callback pointer is passed when the bulk IN pipe initialized.
*
* @param handle The device handle. It equals the value returned from USB_DeviceInit.
* @param message The result of the bulk IN pipe transfer.
* @param callbackParam The parameter for this callback. It is same with
* usb_device_endpoint_callback_struct_t::callbackParam.
* In the class, the value is the printer class handle.
*
* @retval kStatus_USB_Success The transfer is successful.
* @retval kStatus_USB_InvalidHandle The device handle not be found.
*/
static usb_status_t USB_DevicePrinterBulkInCallback(usb_device_handle handle,
usb_device_endpoint_callback_message_struct_t *message,
void *callbackParam)
{
usb_device_printer_struct_t *printerHandle = (usb_device_printer_struct_t *)callbackParam;
usb_status_t status = kStatus_USB_Error;
if (callbackParam == NULL)
{
return kStatus_USB_InvalidHandle;
}
printerHandle->bulkInBusy = 0U;
if ((NULL != printerHandle->classConfig) && (NULL != printerHandle->classConfig->classCallback))
{
/* Notify the application data received by calling the printer class callback.
ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
it is from the second parameter of classInit */
status = printerHandle->classConfig->classCallback((class_handle_t)printerHandle,
kUSB_DevicePrinterEventSendResponse, message);
}
return status;
}
/*!
* @brief bulk OUT endpoint callback function.
*
* This callback function is used to notify upper layer the transfer result of a transfer.
* This callback pointer is passed when the bulk OUT pipe initialized.
*
* @param handle The device handle. It equals the value returned from USB_DeviceInit.
* @param message The result of the bulk OUT pipe transfer.
* @param callbackParam The parameter for this callback. It is same with
* usb_device_endpoint_callback_struct_t::callbackParam.
* In the class, the value is the printer class handle.
*
* @retval kStatus_USB_Success The transfer is successful.
* @retval kStatus_USB_InvalidHandle The device handle not be found.
*/
static usb_status_t USB_DevicePrinterBulkOutCallback(usb_device_handle handle,
usb_device_endpoint_callback_message_struct_t *message,
void *callbackParam)
{
usb_device_printer_struct_t *printerHandle = (usb_device_printer_struct_t *)callbackParam;
usb_status_t status = kStatus_USB_Error;
if (printerHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
printerHandle->bulkOutBusy = 0U;
if ((NULL != printerHandle->classConfig) && (NULL != printerHandle->classConfig->classCallback))
{
/* ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
it is from the second parameter of classInit */
status = printerHandle->classConfig->classCallback((class_handle_t)printerHandle,
kUSB_DevicePrinterEventRecvResponse, message);
}
return status;
}
/*!
* @brief Initialize the endpoints of the printer class.
*
* This callback function is used to initialize the endpoints of the printer class.
*
* @param printerHandle The device printer class handle. It equals the value returned from
* usb_device_class_config_struct_t::classHandle.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DevicePrinterEndpointsInit(usb_device_printer_struct_t *printerHandle)
{
/* ensure that printerHandle is not NULL before calling this function */
usb_device_interface_list_t *configInterfaceList;
usb_device_interface_struct_t *interface = NULL;
usb_status_t status = kStatus_USB_Error;
uint8_t interfaceIndex;
uint8_t index;
/* return error when configuration is invalid (0 or more than the configuration number) */
if ((printerHandle->configuration == 0U) ||
(printerHandle->configuration > printerHandle->classConfig->classInfomation->configurations))
{
return status;
}
configInterfaceList =
&(printerHandle->classConfig->classInfomation->interfaceList[printerHandle->configuration - 1U]);
for (interfaceIndex = 0; interfaceIndex < configInterfaceList->count; ++interfaceIndex)
{
if (USB_DEVICE_CONFIG_PRINTER_CLASS_CODE == configInterfaceList->interfaces[interfaceIndex].classCode)
{
/* index means the alternate interface's index here */
for (index = 0; index < configInterfaceList->interfaces[interfaceIndex].count; ++index)
{
if (configInterfaceList->interfaces[interfaceIndex].interface[index].alternateSetting ==
printerHandle->alternate)
{
interface = &(configInterfaceList->interfaces[interfaceIndex].interface[index]);
break;
}
}
printerHandle->interfaceNumber = configInterfaceList->interfaces[interfaceIndex].interfaceNumber;
break;
}
}
if (interface == NULL)
{
return status;
}
/* Keep new interface handle. */
printerHandle->interfaceHandle = interface;
/* Initialize the endpoints of the new interface. */
/* index means the endpoint's index here */
for (index = 0; index < interface->endpointList.count; ++index)
{
usb_device_endpoint_init_struct_t epInitStruct;
usb_device_endpoint_callback_struct_t epCallback;
epInitStruct.zlt = 0U;
epInitStruct.interval = interface->endpointList.endpoint[index].interval;
epInitStruct.endpointAddress = interface->endpointList.endpoint[index].endpointAddress;
epInitStruct.maxPacketSize = interface->endpointList.endpoint[index].maxPacketSize;
epInitStruct.transferType = interface->endpointList.endpoint[index].transferType;
if (((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT) == USB_IN)
{
epCallback.callbackFn = USB_DevicePrinterBulkInCallback;
printerHandle->bulkInPipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
printerHandle->bulkInPipeStall = 0U;
printerHandle->bulkInPipeDataLen = 0U;
}
else
{
epCallback.callbackFn = USB_DevicePrinterBulkOutCallback;
printerHandle->bulkOutPipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
printerHandle->bulkOutPipeStall = 0U;
printerHandle->bulkOutPipeDataLen = 0U;
}
epCallback.callbackParam = printerHandle;
status = USB_DeviceInitEndpoint(printerHandle->deviceHandle, &epInitStruct, &epCallback);
}
return status;
}
/*!
* @brief De-initialize the endpoints of the printer class.
*
* This callback function is used to de-initialize the endpoints of the printer class.
*
* @param printerHandle The device printer class handle. It equals the value returned from
* usb_device_class_config_struct_t::classHandle.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DevicePrinterEndpointsDeinit(usb_device_printer_struct_t *printerHandle)
{
/* ensure that printerHandle is not NULL before calling this function */
usb_status_t status = kStatus_USB_Error;
uint8_t index;
/* return directly when the interfaceHandle is NULL, it means USB_DevicePrinterEndpointsInit is not called */
if (printerHandle->interfaceHandle == NULL)
{
return kStatus_USB_Success;
}
for (index = 0; index < printerHandle->interfaceHandle->endpointList.count; ++index)
{
status = USB_DeviceDeinitEndpoint(printerHandle->deviceHandle,
printerHandle->interfaceHandle->endpointList.endpoint[index].endpointAddress);
}
printerHandle->interfaceHandle = NULL;
return status;
}
usb_status_t USB_DevicePrinterInit(uint8_t controllerId,
usb_device_class_config_struct_t *config,
class_handle_t *handle)
{
usb_device_handle deviceHandle;
usb_device_printer_struct_t *printerHandle = NULL;
usb_status_t status;
OSA_SR_ALLOC();
/* get the controller's device handle */
status = USB_DeviceClassGetDeviceHandle(controllerId, &deviceHandle);
if (status != kStatus_USB_Success)
{
return status;
}
if (deviceHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
/* Allocate a printer class handle. */
OSA_ENTER_CRITICAL();
status = USB_DevicePrinterAllocateHandle(&printerHandle);
printerHandle->deviceHandle = deviceHandle; /* this printer instance is used */
OSA_EXIT_CRITICAL();
if (status != kStatus_USB_Success)
{
return status;
}
printerHandle->classConfig = config;
printerHandle->alternate = 0xFFU;
printerHandle->configuration = 0U;
printerHandle->interfaceNumber = 0U;
printerHandle->interfaceHandle = NULL;
*handle = (class_handle_t)printerHandle;
return status;
}
usb_status_t USB_DevicePrinterDeinit(class_handle_t handle)
{
usb_status_t status;
usb_device_printer_struct_t *printerHandle = (usb_device_printer_struct_t *)handle;
if (NULL == handle)
{
return kStatus_USB_InvalidHandle;
}
status = USB_DevicePrinterEndpointsDeinit(printerHandle);
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if (kStatus_USB_Success != USB_DevicePrinterFreeHandle(printerHandle))
{
return kStatus_USB_Error;
}
#else
(void)USB_DevicePrinterFreeHandle(printerHandle);
#endif
return status;
}
usb_status_t USB_DevicePrinterEvent(void *handle, uint32_t event, void *param)
{
usb_status_t status = kStatus_USB_Error;
usb_device_printer_struct_t *printerHandle = (usb_device_printer_struct_t *)handle;
uint16_t temp16;
uint8_t temp8;
usb_device_class_event_t eventCode = (usb_device_class_event_t)event;
if ((handle == NULL) || (param == NULL))
{
return kStatus_USB_InvalidHandle;
}
switch (eventCode)
{
case kUSB_DeviceClassEventDeviceReset:
/* de-initialize printer instance */
printerHandle->interfaceHandle = NULL;
printerHandle->alternate = 0xFFU;
printerHandle->configuration = 0U;
printerHandle->interfaceNumber = 0U;
printerHandle->bulkInBusy = 0U;
printerHandle->bulkOutBusy = 0U;
status = kStatus_USB_Success;
break;
case kUSB_DeviceClassEventSetConfiguration:
temp8 = *((uint8_t *)param);
if (printerHandle->classConfig == NULL)
{
break;
}
if (temp8 == printerHandle->configuration)
{
status = kStatus_USB_Success;
break;
}
/* De-initialize the endpoints when current configuration is none zero. */
if (printerHandle->configuration != 0U)
{
status = USB_DevicePrinterEndpointsDeinit(printerHandle);
}
/* Save new configuration. */
printerHandle->configuration = temp8;
printerHandle->alternate = 0U;
printerHandle->bulkInBusy = 0U;
printerHandle->bulkOutBusy = 0U;
/* Initialize the endpoints of the new current configuration */
status = USB_DevicePrinterEndpointsInit(printerHandle);
break;
case kUSB_DeviceClassEventSetInterface:
if (printerHandle->classConfig == NULL)
{
break;
}
/* Get the new alternate setting of the interface */
temp16 = *((uint16_t *)param);
/* Get the alternate setting value */
temp8 = (uint8_t)(temp16 & 0xFFU);
/* Whether the interface belongs to the class. */
if (printerHandle->interfaceNumber != ((uint8_t)(temp16 >> 8U)))
{
break;
}
/* Only handle new alternate setting. */
if (temp8 == printerHandle->alternate)
{
status = kStatus_USB_Success;
break;
}
/* De-initialize old endpoints */
status = USB_DevicePrinterEndpointsDeinit(printerHandle);
printerHandle->alternate = temp8;
printerHandle->bulkInBusy = 0U;
printerHandle->bulkOutBusy = 0U;
/* Initialize new endpoints */
status = USB_DevicePrinterEndpointsInit(printerHandle);
break;
case kUSB_DeviceClassEventSetEndpointHalt:
if ((printerHandle->classConfig == NULL) || (printerHandle->interfaceHandle == NULL))
{
break;
}
/* Get the endpoint address */
temp8 = *((uint8_t *)param);
for (temp16 = 0; temp16 < printerHandle->interfaceHandle->endpointList.count; ++temp16)
{
if (temp8 == printerHandle->interfaceHandle->endpointList.endpoint[temp16].endpointAddress)
{
/* Only stall the endpoint belongs to the class */
if (USB_IN == ((printerHandle->interfaceHandle->endpointList.endpoint[temp16].endpointAddress &
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))
{
printerHandle->bulkInPipeStall = 1U;
}
else
{
printerHandle->bulkOutPipeStall = 1U;
}
status = USB_DeviceStallEndpoint(printerHandle->deviceHandle, temp8);
break;
}
}
break;
case kUSB_DeviceClassEventClearEndpointHalt:
if ((printerHandle->classConfig == NULL) || (printerHandle->interfaceHandle == NULL))
{
break;
}
/* Get the endpoint address */
temp8 = *((uint8_t *)param);
for (temp16 = 0; temp16 < printerHandle->interfaceHandle->endpointList.count; ++temp16)
{
if (temp8 == printerHandle->interfaceHandle->endpointList.endpoint[temp16].endpointAddress)
{
/* Only un-stall the endpoint belongs to the class */
status = USB_DeviceUnstallEndpoint(printerHandle->deviceHandle, temp8);
if (USB_IN == (((temp8)&USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))
{
if (0U != printerHandle->bulkInPipeStall)
{
printerHandle->bulkInPipeStall = 0U;
if ((uint8_t *)USB_INVALID_TRANSFER_BUFFER != printerHandle->bulkInPipeDataBuffer)
{
status = USB_DeviceSendRequest(
printerHandle->deviceHandle,
(printerHandle->interfaceHandle->endpointList.endpoint[temp16].endpointAddress &
USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK),
printerHandle->bulkInPipeDataBuffer, printerHandle->bulkInPipeDataLen);
if (kStatus_USB_Success != status)
{
usb_device_endpoint_callback_message_struct_t endpointCallbackMessage;
endpointCallbackMessage.buffer = printerHandle->bulkInPipeDataBuffer;
endpointCallbackMessage.length = printerHandle->bulkInPipeDataLen;
endpointCallbackMessage.isSetup = 0U;
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if (kStatus_USB_Success !=
USB_DevicePrinterBulkInCallback(printerHandle->deviceHandle,
(void *)&endpointCallbackMessage, handle))
{
return kStatus_USB_Error;
}
#else
(void)USB_DevicePrinterBulkInCallback(printerHandle->deviceHandle,
(void *)&endpointCallbackMessage, handle);
#endif
}
printerHandle->bulkInPipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
printerHandle->bulkInPipeDataLen = 0U;
}
}
}
else
{
if (printerHandle->bulkOutPipeStall == 1U)
{
printerHandle->bulkOutPipeStall = 0U;
if ((uint8_t *)USB_INVALID_TRANSFER_BUFFER != printerHandle->bulkOutPipeDataBuffer)
{
status = USB_DeviceRecvRequest(
printerHandle->deviceHandle,
(printerHandle->interfaceHandle->endpointList.endpoint[temp16].endpointAddress &
USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK),
printerHandle->bulkOutPipeDataBuffer, printerHandle->bulkOutPipeDataLen);
if (kStatus_USB_Success != status)
{
usb_device_endpoint_callback_message_struct_t endpointCallbackMessage;
endpointCallbackMessage.buffer = printerHandle->bulkOutPipeDataBuffer;
endpointCallbackMessage.length = printerHandle->bulkOutPipeDataLen;
endpointCallbackMessage.isSetup = 0U;
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if (kStatus_USB_Success !=
USB_DevicePrinterBulkInCallback(printerHandle->deviceHandle,
(void *)&endpointCallbackMessage, handle))
{
return kStatus_USB_Error;
}
#else
(void)USB_DevicePrinterBulkInCallback(printerHandle->deviceHandle,
(void *)&endpointCallbackMessage, handle);
#endif
}
printerHandle->bulkOutPipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
printerHandle->bulkOutPipeDataLen = 0U;
}
}
}
break;
}
}
break;
case kUSB_DeviceClassEventClassRequest:
{
/* Handle the printer class specific request. */
usb_device_control_request_struct_t *controlRequest = (usb_device_control_request_struct_t *)param;
usb_device_printer_class_request_t classRequest;
if ((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) !=
USB_REQUEST_TYPE_RECIPIENT_INTERFACE)
{
break;
}
classRequest.interface = (uint8_t)(controlRequest->setup->wIndex >> 8);
if (classRequest.interface != printerHandle->interfaceNumber)
{
break;
}
classRequest.alternateSetting = (uint8_t)(controlRequest->setup->wIndex);
status = kStatus_USB_InvalidRequest;
switch (controlRequest->setup->bRequest)
{
case USB_DEVICE_PRINTER_GET_DEVICE_ID:
/* GET_DEVICE_ID */
if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
USB_REQUEST_TYPE_DIR_IN) &&
(controlRequest->setup->wLength != 0U))
{
classRequest.configIndex = (uint8_t)controlRequest->setup->wValue;
/* ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
it is from the second parameter of classInit */
status = printerHandle->classConfig->classCallback(
(class_handle_t)printerHandle, kUSB_DevicePrinterEventGetDeviceId, &classRequest);
controlRequest->buffer = classRequest.buffer;
controlRequest->length = classRequest.length;
}
break;
case USB_DEVICE_PRINTER_GET_PORT_STATUS:
/* GET_PORT_STATUS */
if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
USB_REQUEST_TYPE_DIR_IN) &&
(controlRequest->setup->wLength == 1U))
{
/* ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
it is from the second parameter of classInit */
status = printerHandle->classConfig->classCallback(
(class_handle_t)printerHandle, kUSB_DevicePrinterEventGetPortStatus, &classRequest);
controlRequest->buffer = classRequest.buffer;
controlRequest->length = classRequest.length;
}
break;
case USB_DEVICE_PRINTER_SOFT_RESET:
if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
USB_REQUEST_TYPE_DIR_OUT) &&
(controlRequest->setup->wLength == 0U))
{
/* reset BULK_IN/OUT endpoint and inform application */
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if ((kStatus_USB_Success != USB_DevicePrinterEndpointsDeinit(printerHandle)) ||
(kStatus_USB_Success != USB_DevicePrinterEndpointsInit(printerHandle)))
{
return kStatus_USB_Error;
}
#else
(void)USB_DevicePrinterEndpointsDeinit(printerHandle);
(void)USB_DevicePrinterEndpointsInit(printerHandle);
#endif
/* ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
it is from the second parameter of classInit */
status = printerHandle->classConfig->classCallback(
(class_handle_t)printerHandle, kUSB_DevicePrinterEventSoftReset, &classRequest);
}
break;
default:
/*no action*/
break;
}
break;
}
default:
/*no action*/
break;
}
return status;
}
usb_status_t USB_DevicePrinterSend(class_handle_t handle, uint8_t ep, uint8_t *buffer, uint32_t length)
{
usb_device_printer_struct_t *printerHandle = (usb_device_printer_struct_t *)handle;
usb_status_t status;
if (NULL == handle)
{
return kStatus_USB_InvalidHandle;
}
if (1U == printerHandle->bulkInBusy)
{
return kStatus_USB_Busy;
}
printerHandle->bulkInBusy = 1U;
if (0U != printerHandle->bulkInPipeStall)
{
printerHandle->bulkInPipeDataBuffer = buffer;
printerHandle->bulkInPipeDataLen = length;
return kStatus_USB_Success;
}
status = USB_DeviceSendRequest(printerHandle->deviceHandle, ep, buffer, length);
if (kStatus_USB_Success != status)
{
printerHandle->bulkInBusy = 0U;
}
return status;
}
usb_status_t USB_DevicePrinterRecv(class_handle_t handle, uint8_t ep, uint8_t *buffer, uint32_t length)
{
usb_device_printer_struct_t *printerHandle = (usb_device_printer_struct_t *)handle;
usb_status_t status = kStatus_USB_Error;
if (NULL == handle)
{
return kStatus_USB_InvalidHandle;
}
if (0U != printerHandle->bulkOutBusy)
{
return kStatus_USB_Busy;
}
printerHandle->bulkOutBusy = 1U;
if (0U != printerHandle->bulkOutPipeStall)
{
printerHandle->bulkOutPipeDataBuffer = buffer;
printerHandle->bulkOutPipeDataLen = length;
return kStatus_USB_Success;
}
status = USB_DeviceRecvRequest(printerHandle->deviceHandle, ep, buffer, length);
if (kStatus_USB_Success != status)
{
printerHandle->bulkOutBusy = 0U;
}
return status;
}
#endif