/***************************************************************************
 * Copyright (c) 2024 Microsoft Corporation
 * Copyright (c) 2026-present Eclipse ThreadX contributors
 *
 * This program and the accompanying materials are made available under the
 * terms of the MIT License which is available at
 * https://opensource.org/licenses/MIT.
 *
 * SPDX-License-Identifier: MIT
 **************************************************************************/

/**************************************************************************/
/**************************************************************************/
/**                                                                       */
/** USBX Component                                                        */
/**                                                                       */
/**   Device Printer Class                                                */
/**                                                                       */
/**************************************************************************/
/**************************************************************************/

/**************************************************************************/
/*                                                                        */
/*  COMPONENT DEFINITION                                   RELEASE        */
/*                                                                        */
/*    ux_device_class_printer.h                           PORTABLE C      */
/*                                                           6.3.0        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Chaoqiong Xiao, Microsoft Corporation                               */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This file defines the equivalences for the USBX Device Class        */
/*    Printer component.                                                  */
/*                                                                        */
/**************************************************************************/

#ifndef UX_DEVICE_CLASS_PRINTER_H
#define UX_DEVICE_CLASS_PRINTER_H

/* Determine if a C++ compiler is being used.  If so, ensure that standard
   C is used to process the API information.  */

#ifdef   __cplusplus

/* Yes, C++ compiler is present.  Use standard C.  */
extern   "C" {

#endif

/* Internal option: enable the basic USBX error checking. This define is typically used
   while debugging application.  */
#if defined(UX_ENABLE_ERROR_CHECKING) && !defined(UX_DEVICE_CLASS_PRINTER_ENABLE_ERROR_CHECKING)
#define UX_DEVICE_CLASS_PRINTER_ENABLE_ERROR_CHECKING
#endif


/* Option: defined, it enables zero copy support (works if PRINTER owns endpoint buffer).
    Defined, it enables zero copy for bulk in/out endpoints (write/read). In this case, the endpoint
    buffer is not allocated in class, application must provide the buffer for read/write, and the
    buffer must meet device controller driver (DCD) buffer requirements (e.g., aligned and cache
    safe if buffer is for DMA).
 */
/* #define UX_DEVICE_CLASS_PRINTER_ZERO_COPY  */


/* Defined, _write is pending ZLP automatically (complete transfer) after buffer is sent.  */

/* #define UX_DEVICE_CLASS_PRINTER_WRITE_AUTO_ZLP  */


/* Option: bulk out endpoint / read buffer size, must be larger than max packet size in framework, and aligned in 4-bytes.  */
#ifndef UX_DEVICE_CLASS_PRINTER_READ_BUFFER_SIZE
#define UX_DEVICE_CLASS_PRINTER_READ_BUFFER_SIZE                         512
#endif

/* Option: bulk in endpoint / write buffer size, must be larger than max packet size in framework, and aligned in 4-bytes.  */
#ifndef UX_DEVICE_CLASS_PRINTER_WRITE_BUFFER_SIZE
#define UX_DEVICE_CLASS_PRINTER_WRITE_BUFFER_SIZE                        UX_SLAVE_REQUEST_DATA_MAX_LENGTH
#endif


/* Internal: check if class own endpoint buffer  */
#if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) &&                                   \
    (!defined(UX_DEVICE_CLASS_PRINTER_ZERO_COPY))
#define UX_DEVICE_CLASS_PRINTER_OWN_ENDPOINT_BUFFER
#endif


/* Define Printer Class USB Class constants.  */
#define UX_DEVICE_CLASS_PRINTER_CLASS                                    7

#define UX_DEVICE_CLASS_PRINTER_SUBCLASS                                 1

#define UX_DEVICE_CLASS_PRINTER_PROTOCOL_UNIDIRECTIONAL                  1
#define UX_DEVICE_CLASS_PRINTER_PROTOCOL_BIDIRECTIONAL                   2
#define UX_DEVICE_CLASS_PRINTER_PROTOCOL_1284_4_COMPATIBLE_BIDIR         3


/* Device Printer Requests */
#define UX_DEVICE_CLASS_PRINTER_GET_DEVICE_ID                            0x00
#define UX_DEVICE_CLASS_PRINTER_GET_PORT_STATUS                          0x01
#define UX_DEVICE_CLASS_PRINTER_SOFT_RESET                               0x02


/* Printer Port Status.  */
#define UX_DEVICE_CLASS_PRINTER_PAPER_EMPTY                             (1u << 5)
#define UX_DEVICE_CLASS_PRINTER_SELECT                                  (1u << 4)
#define UX_DEVICE_CLASS_PRINTER_NOT_ERROR                               (1u << 3)


/* Printer IOCTL code.  */
#define UX_DEVICE_CLASS_PRINTER_IOCTL_PORT_STATUS_SET                   1
#define UX_DEVICE_CLASS_PRINTER_IOCTL_READ_TIMEOUT_SET                  2
#define UX_DEVICE_CLASS_PRINTER_IOCTL_WRITE_TIMEOUT_SET                 3

#if defined(UX_DEVICE_STANDALONE)

/* Printer read state machine states.  */
#define UX_DEVICE_CLASS_PRINTER_READ_START                              (UX_STATE_STEP + 1)
#define UX_DEVICE_CLASS_PRINTER_READ_WAIT                               (UX_STATE_STEP + 2)

/* Printer write state machine states.  */
#define UX_DEVICE_CLASS_PRINTER_WRITE_START                             (UX_STATE_STEP + 1)
#define UX_DEVICE_CLASS_PRINTER_WRITE_WAIT                              (UX_STATE_STEP + 2)
#endif

/* Define Device Printer Class Calling Parameter structure */

typedef struct UX_DEVICE_CLASS_PRINTER_PARAMETER_STRUCT
{
    UCHAR                   *ux_device_class_printer_device_id; /* IEEE 1284 string, first 2 big endian length.  */
    VOID                    (*ux_device_class_printer_instance_activate)(VOID *);
    VOID                    (*ux_device_class_printer_instance_deactivate)(VOID *);
    VOID                    (*ux_device_class_printer_soft_reset)(VOID *);
} UX_DEVICE_CLASS_PRINTER_PARAMETER;


/* Define Printer Class structure.  */

typedef struct UX_DEVICE_CLASS_PRINTER_STRUCT
{
    UX_SLAVE_INTERFACE      *ux_device_class_printer_interface;
    UX_SLAVE_ENDPOINT       *ux_device_class_printer_endpoint_out;
    UX_SLAVE_ENDPOINT       *ux_device_class_printer_endpoint_in;
#if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
    UCHAR                   *ux_device_class_printer_endpoint_buffer;
#endif
    ULONG                   ux_device_class_printer_port_status;
    UX_DEVICE_CLASS_PRINTER_PARAMETER
                            ux_device_class_printer_parameter;
#if !defined(UX_DEVICE_STANDALONE)
    UX_MUTEX                ux_device_class_printer_endpoint_out_mutex;
    UX_MUTEX                ux_device_class_printer_endpoint_in_mutex;
#else
    UCHAR                  *ux_device_class_printer_read_buffer;
    ULONG                   ux_device_class_printer_read_requested_length;
    ULONG                   ux_device_class_printer_read_transfer_length;
    ULONG                   ux_device_class_printer_read_actual_length;
    UINT                    ux_device_class_printer_read_status;
    UINT                    ux_device_class_printer_read_state;

    UCHAR                  *ux_device_class_printer_write_buffer;
    ULONG                   ux_device_class_printer_write_transfer_length;
    ULONG                   ux_device_class_printer_write_host_length;
    ULONG                   ux_device_class_printer_write_requested_length;
    ULONG                   ux_device_class_printer_write_actual_length;
    UINT                    ux_device_class_printer_write_status;
    UINT                    ux_device_class_printer_write_state;
#endif
} UX_DEVICE_CLASS_PRINTER;

/* Define PRINTER endpoint buffer settings (when PRINTER owns buffer).  */
#define UX_DEVICE_CLASS_PRINTER_ENDPOINT_BUFFER_SIZE_CALC_OVERFLOW \
    (UX_OVERFLOW_CHECK_ADD_ULONG(UX_DEVICE_CLASS_PRINTER_READ_BUFFER_SIZE,      \
                                 UX_DEVICE_CLASS_PRINTER_WRITE_BUFFER_SIZE))
#define UX_DEVICE_CLASS_PRINTER_ENDPOINT_BUFFER_SIZE    (UX_DEVICE_CLASS_PRINTER_READ_BUFFER_SIZE + UX_DEVICE_CLASS_PRINTER_WRITE_BUFFER_SIZE)
#define UX_DEVICE_CLASS_PRINTER_READ_BUFFER(ecm)        ((ecm)->ux_device_class_printer_endpoint_buffer)
#define UX_DEVICE_CLASS_PRINTER_WRITE_BUFFER(ecm)       (UX_DEVICE_CLASS_PRINTER_READ_BUFFER(ecm) + UX_DEVICE_CLASS_PRINTER_READ_BUFFER_SIZE)


/* Define Device Printer Class prototypes.  */

UINT  _ux_device_class_printer_activate(UX_SLAVE_CLASS_COMMAND *command);
UINT  _ux_device_class_printer_control_request(UX_SLAVE_CLASS_COMMAND *command);
UINT  _ux_device_class_printer_deactivate(UX_SLAVE_CLASS_COMMAND *command);
UINT  _ux_device_class_printer_entry(UX_SLAVE_CLASS_COMMAND *command);
UINT  _ux_device_class_printer_initialize(UX_SLAVE_CLASS_COMMAND *command);
UINT  _ux_device_class_printer_uninitialize(UX_SLAVE_CLASS_COMMAND *command);

VOID  _ux_device_class_printer_soft_reset(UX_DEVICE_CLASS_PRINTER *printer);

UINT  _ux_device_class_printer_write(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
                                ULONG requested_length, ULONG *actual_length);
UINT  _ux_device_class_printer_read(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
                                ULONG requested_length, ULONG *actual_length);

UINT  _ux_device_class_printer_ioctl(UX_DEVICE_CLASS_PRINTER *printer, ULONG ioctl_function,
                                    VOID *parameter);

UINT  _ux_device_class_printer_write_run(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
                                ULONG requested_length, ULONG *actual_length);
UINT  _ux_device_class_printer_read_run(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
                                ULONG requested_length, ULONG *actual_length);

UINT  _uxe_device_class_printer_initialize(UX_SLAVE_CLASS_COMMAND *command);
UINT  _uxe_device_class_printer_read(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
                                ULONG requested_length, ULONG *actual_length);
UINT  _uxe_device_class_printer_write(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
                                ULONG requested_length, ULONG *actual_length);
UINT  _uxe_device_class_printer_ioctl(UX_DEVICE_CLASS_PRINTER *printer, ULONG ioctl_function,
                                    VOID *parameter);
UINT  _uxe_device_class_printer_write_run(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
                                ULONG requested_length, ULONG *actual_length);
UINT  _uxe_device_class_printer_read_run(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
                                ULONG requested_length, ULONG *actual_length);

/* Define Device Printer Class API prototypes.  */
#if defined(UX_DEVICE_CLASS_PRINTER_ENABLE_ERROR_CHECKING)

#define ux_device_class_printer_entry               _ux_device_class_printer_entry
#define ux_device_class_printer_read                _uxe_device_class_printer_read
#define ux_device_class_printer_write               _uxe_device_class_printer_write
#define ux_device_class_printer_ioctl               _uxe_device_class_printer_ioctl
#define ux_device_class_printer_read_run            _uxe_device_class_printer_read_run
#define ux_device_class_printer_write_run           _uxe_device_class_printer_write_run

#else

#define ux_device_class_printer_entry               _ux_device_class_printer_entry
#define ux_device_class_printer_read                _ux_device_class_printer_read
#define ux_device_class_printer_write               _ux_device_class_printer_write
#define ux_device_class_printer_ioctl               _ux_device_class_printer_ioctl
#define ux_device_class_printer_read_run            _ux_device_class_printer_read_run
#define ux_device_class_printer_write_run           _ux_device_class_printer_write_run

#endif

/* Determine if a C++ compiler is being used.  If so, complete the standard
   C conditional started above.  */
#ifdef __cplusplus
}
#endif

#endif /* UX_DEVICE_CLASS_PRINTER_H */
