All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ruien Zhang <zhangruien@bytedance.com>
To: peter.maydell@linaro.org, richard.henderson@linaro.org,
	kraxel@redhat.com, eblake@redhat.com, pbonzini@redhat.com,
	berrange@redhat.com
Cc: qemu-devel@nongnu.org, zhangruien <zhangruien@bytedance.com>
Subject: [PATCH 2/2] usb-printer: Introduce USB printer class
Date: Thu, 13 Jan 2022 19:56:59 +0800	[thread overview]
Message-ID: <20220113115659.72788-3-zhangruien@bytedance.com> (raw)
In-Reply-To: <20220113115659.72788-1-zhangruien@bytedance.com>

From: zhangruien <zhangruien@bytedance.com>

The USB printer device emulation is currently provided with:

1) Definitions and corresponding action handlers of class-specific
   requests with essential descriptors in USB Printer Class
   Specification 1.1 [1].

2) Extended definitions of interface protocol and class-specific
   descriptors in IPP-over-USB protocol 1.0 [2].

A usb printer device can be assembled with the following example of
command-line arguments:

    -device piix4-usb-uhci,id=uhci,bus=pci.0 \
    -device usb-printer,id=usb-printer0,printerdev=printer0,bus=uhci.0,terminal=printer \
    -printerdev builtin,id=printer0

[1]: https://www.usb.org/sites/default/files/usbprint11a021811.pdf
[2]: https://www.usb.org/document-library/ipp-protocol-10

Signed-off-by: zhangruien <zhangruien@bytedance.com>
---
 docs/system/devices/usb.rst |   3 +
 hw/usb/Kconfig              |   5 +
 hw/usb/dev-printer.c        | 423 ++++++++++++++++++++++++++++++++++++++++++++
 hw/usb/meson.build          |   1 +
 hw/usb/trace-events         |  11 ++
 include/hw/usb/printer.h    |  93 ++++++++++
 6 files changed, 536 insertions(+)
 create mode 100644 hw/usb/dev-printer.c
 create mode 100644 include/hw/usb/printer.h

diff --git a/docs/system/devices/usb.rst b/docs/system/devices/usb.rst
index afb7d6c226..6e87c3be11 100644
--- a/docs/system/devices/usb.rst
+++ b/docs/system/devices/usb.rst
@@ -199,6 +199,9 @@ option or the ``device_add`` monitor command. Available devices are:
 ``u2f-{emulated,passthru}``
    Universal Second Factor device
 
+``usb-printer``
+   USB printer device
+
 Physical port addressing
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig
index 53f8283ffd..1b5a953cae 100644
--- a/hw/usb/Kconfig
+++ b/hw/usb/Kconfig
@@ -133,3 +133,8 @@ config XLNX_USB_SUBSYS
     bool
     default y if XLNX_VERSAL
     select USB_DWC3
+
+config USB_PRINTER
+    bool
+    default y
+    depends on USB
diff --git a/hw/usb/dev-printer.c b/hw/usb/dev-printer.c
new file mode 100644
index 0000000000..5905615961
--- /dev/null
+++ b/hw/usb/dev-printer.c
@@ -0,0 +1,423 @@
+/*
+ * USB Printer Device emulation
+ *
+ * Copyright (c) 2022 ByteDance, Inc.
+ *
+ * Author:
+ *   Ruien Zhang <zhangruien@bytedance.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+/*
+ * References:
+ *   Universal Serial Bus Device Class Definition for Printing Devices,
+ *   version 1.1
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qemu/log.h"
+#include "qom/object.h"
+#include "qapi/error.h"
+#include "migration/vmstate.h"
+#include "hw/qdev-properties.h"
+#include "hw/usb.h"
+#include "hw/usb/printer.h"
+#include "printer/printer.h"
+#include "desc.h"
+#include "trace.h"
+
+#define USBPRINTER_VENDOR_NUM     0x46f4 /* CRC16() of "QEMU" */
+#define USBPRINTER_PRODUCT_NUM    0xa1f3
+
+enum {
+    STR_MANUFACTURER = 1,
+    STR_PRODUCT,
+    STR_SERIALNUMBER,
+    STR_CONFIG_FULL,
+    STR_CONFIG_HIGH,
+};
+
+static const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER] = "QEMU",
+    [STR_PRODUCT]      = "QEMU USB Printer",
+    [STR_SERIALNUMBER] = "1",
+    [STR_CONFIG_FULL]  = "Full speed config (usb 1.1)",
+    [STR_CONFIG_HIGH]  = "High speed config (usb 2.0)",
+};
+
+/*
+ * 5. Standard Descriptors
+ *
+ * "Printer Class devices support the following standard USB descriptors:
+ *  - Device. Each printer has one device descriptor.
+ *  - Configuration. Each device has one default configuration descriptor which
+ *    supports at least one interface.
+ *  - Interface. A printer device has a single data interface with possible
+ *    alternates.
+ *  - Endpoint. A printer device supports the following endpoints:
+ *  - Bulk OUT endpoint. Used for transfer of PDL/PCP data.
+ *  - Optional Bulk IN endpoint. Provides status and other return information."
+ */
+static const USBDescIface desc_iface_full = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = EP_NUMS_2,
+    .bInterfaceClass               = USB_CLASS_PRINTER,
+    .bInterfaceSubClass            = SC_PRINTERS,
+    .bInterfaceProtocol            = PC_PROTOCOL_BIDIR_1284_4,
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_OUT | EP_NUM_BULK_OUT,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_IN | EP_NUM_BULK_IN,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },
+    },
+};
+
+static const USBDescDevice desc_device_full = {
+    .bcdUSB                        = 0x0200,
+    .bMaxPacketSize0               = 8,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .iConfiguration        = STR_CONFIG_FULL,
+            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
+            .nif = 1,
+            .ifs = &desc_iface_full,
+        },
+    },
+};
+
+static const USBDescIface desc_iface_high = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = EP_NUMS_2,
+    .bInterfaceClass               = USB_CLASS_PRINTER,
+    .bInterfaceSubClass            = SC_PRINTERS,
+    .bInterfaceProtocol            = PC_PROTOCOL_BIDIR_1284_4,
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_OUT | EP_NUM_BULK_OUT,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 512,
+        },{
+            .bEndpointAddress      = USB_DIR_IN | EP_NUM_BULK_IN,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 512,
+        },
+    },
+};
+
+static const USBDescDevice desc_device_high = {
+    .bcdUSB                        = 0x0200,
+    .bMaxPacketSize0               = 64,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .iConfiguration        = STR_CONFIG_HIGH,
+            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
+            .nif = 1,
+            .ifs = &desc_iface_high,
+        },
+    },
+};
+
+static const USBDesc desc_printer = {
+    .id = {
+        .idVendor          = USB_CLASS_PRINTER,
+        .idProduct         = USBPRINTER_PRODUCT_NUM,
+        .bcdDevice         = 0,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full  = &desc_device_full,
+    .high  = &desc_device_high,
+    .str   = desc_strings,
+};
+
+struct USBPrinterState {
+    /* qemu interfaces */
+    USBDevice dev;
+
+    /* state */
+    QEMUPrinter *printer;
+
+    /* properties */
+    char *printerdev;
+    char *terminal;
+};
+
+#define TYPE_USB_PRINTER "usb-printer"
+OBJECT_DECLARE_SIMPLE_TYPE(USBPrinterState, USB_PRINTER)
+
+static void usb_printer_handle_reset(USBDevice *dev)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+    trace_usb_printer_handle_reset(bus->busnr, dev->addr);
+}
+
+/*
+ * 4.2.1 GET_DEVICE_ID (bRequest = 0)
+ * "This class-specific request returns a device ID string that is compatible
+ *  with IEEE 1284. See IEEE 1284 for syntax and formatting information."
+ */
+#define USB_PRINTER_DEVICE_ID_QEMU "QEMU Printer"
+#define USB_PRINTER_DEVICE_ID_QEMU_LEN \
+    strlen(USB_PRINTER_DEVICE_ID_QEMU)
+#define USB_PRINTER_DEVICE_ID_QEMU_LEN_IEEE_1284 \
+    (2 + USB_PRINTER_DEVICE_ID_QEMU_LEN)
+
+static const USBPrinterDeviceIDStrings usb_printer_device_ids = {
+    [USB_PRINTER_DEVICE_ID_DEFAULT] = USB_PRINTER_DEVICE_ID_QEMU,
+};
+
+static int usb_printer_get_device_id(USBDevice *dev, int request, int value,
+                                 int index, int length, uint8_t *data)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+
+    *((uint16_t *)data) = cpu_to_be16(USB_PRINTER_DEVICE_ID_QEMU_LEN_IEEE_1284);
+    memcpy(data + 2, usb_printer_device_ids[USB_PRINTER_DEVICE_ID_DEFAULT],
+        USB_PRINTER_DEVICE_ID_QEMU_LEN);
+
+    trace_usb_printer_get_device_id(bus->busnr, dev->addr);
+
+    return USB_PRINTER_DEVICE_ID_QEMU_LEN_IEEE_1284;
+}
+
+/*
+ * 4.2.2 GET_PORT_STATUS (bRequest = 1)
+ *
+ * "Note: Some USB printers may not always be able to determine this
+ *  information. In this case, they should return benign status of
+ *  “Paper Not Empty,” “Selected,” and “No Error.”"
+ */
+static int usb_printer_get_port_status(USBDevice *dev, int request, int value,
+                                 int index, int length, uint8_t *data)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+
+    *((uint8_t *)data) = PAPER_NOT_EMPTY | SELECTED | NO_ERROR;
+    trace_usb_printer_get_port_status(bus->busnr, dev->addr);
+    return 1;
+}
+
+/*
+ * TODO: 4.2.3 SOFT_RESET (bRequest = 2)
+ *
+ * "This class-specific request flushes all buffers and resets the Bulk OUT
+ *  and Bulk IN pipes to their default states. This request clears all stall
+ *  conditions. This reset does NOT change the USB addressing or USB
+ *  configuration."
+ */
+static int usb_printer_handle_soft_reset(USBDevice *dev, int request, int value,
+                                 int index, int length, uint8_t *data)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+
+    trace_usb_printer_handle_soft_reset(bus->busnr, dev->addr);
+    return 0;
+}
+
+static void usb_printer_handle_control(USBDevice *dev, USBPacket *p,
+                                    int request, int value, int index,
+                                    int length, uint8_t *data)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+    int ret = 0;
+
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return;
+    }
+
+    switch (request) {
+    case ClassInterfaceRequest | USBPRINTER_GET_DEVICE_ID:
+        ret = usb_printer_get_device_id(dev, request, value, index,
+                                        length, data);
+        if (ret < 0) {
+            goto error;
+        }
+        break;
+
+    case ClassInterfaceRequest | USBPRINTER_GET_PORT_STATUS:
+        ret = usb_printer_get_port_status(dev, request, value, index,
+                                          length, data);
+        if (ret < 0) {
+            goto error;
+        }
+        break;
+
+    case ClassInterfaceOutRequestCompat1_0 | USBPRINTER_SOFT_RESET:
+        /* fall through */
+    case ClassInterfaceOutRequest | USBPRINTER_SOFT_RESET:
+        ret = usb_printer_handle_soft_reset(dev, request, value, index,
+                                            length, data);
+        if (ret < 0) {
+            goto error;
+        }
+        break;
+
+    default:
+        qemu_log_mask(LOG_UNIMP, "%s: request %x not implemented\n",
+                      TYPE_USB_PRINTER, request);
+        goto error;
+    }
+
+    p->actual_length = ret;
+    p->status = USB_RET_SUCCESS;
+    return;
+
+error:
+    trace_usb_printer_handle_control_error(bus->busnr, dev->addr, request,
+        value, index, length);
+    p->status = USB_RET_STALL;
+}
+
+static void usb_printer_handle_data_out(USBDevice *dev, USBPacket *p)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+    QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;
+
+    p->status = USB_RET_SUCCESS;
+    trace_usb_printer_handle_data_out(bus->busnr, dev->addr, iov->size);
+}
+
+/*
+ * 5.4.2 Bulk IN Endpoint
+ *
+ * "The Bulk IN endpoint is used to return any data generated by the PDL
+ *  or PCP to the host. If the printer supports a PCP, such as IEEE-1284.1
+ *  or IEEE-1284.4, this endpoint will return status or other printer-related
+ *  information."
+ */
+static void usb_printer_handle_data_in(USBDevice *dev, USBPacket *p)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+    QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;
+
+    p->status = USB_RET_SUCCESS;
+    trace_usb_printer_handle_data_in(bus->busnr, dev->addr, iov->size);
+}
+
+static void usb_printer_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+
+    switch (p->pid) {
+    case USB_TOKEN_OUT:
+        switch (p->ep->nr) {
+        case EP_NUM_BULK_OUT:
+            usb_printer_handle_data_out(dev, p);
+            return;
+
+        default:
+            goto fail;
+        }
+        break;
+
+    case USB_TOKEN_IN:
+        switch (p->ep->nr) {
+        case EP_NUM_BULK_IN:
+            usb_printer_handle_data_in(dev, p);
+            return;
+
+        default:
+            goto fail;
+        }
+        break;
+
+    default:
+    fail:
+        p->status = USB_RET_STALL;
+        break;
+    }
+
+    if (p->status == USB_RET_STALL) {
+        fprintf(stderr, "usbprinter: failed data transaction: "
+                        "pid 0x%x ep 0x%x len 0x%zx\n",
+                        p->pid, p->ep->nr, p->iov.size);
+    }
+
+    trace_usb_printer_handle_data(bus->busnr, dev->addr, p->pid, p->ep->nr);
+}
+
+static void usb_printer_unrealize(USBDevice *dev)
+{
+}
+
+static void usb_printer_realize(USBDevice *dev, Error **errp)
+{
+    USBPrinterState *s = USB_PRINTER(dev);
+    if (!s->terminal || strcmp(s->terminal, "printer")) {
+        error_setg(errp, "%s: support terminal printer only", TYPE_USB_PRINTER);
+        return;
+    }
+
+    s->printer = qemu_printer_by_id(s->printerdev);
+    if (!s->printer) {
+        error_setg(errp, "%s: invalid printerdev %s",
+                   TYPE_USB_PRINTER, s->printerdev);
+        return;
+    }
+
+    dev->usb_desc = &desc_printer;
+
+    usb_desc_create_serial(dev);
+    usb_desc_init(dev);
+    s->dev.opaque = s;
+}
+
+/* TODO: set alternates on IPP-over-USB */
+static void usb_printer_set_interface(USBDevice *dev, int iface,
+                                    int old, int value)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+    trace_usb_printer_set_interface(bus->busnr, dev->addr, iface, old, value);
+}
+
+static Property usb_printer_properties[] = {
+    DEFINE_PROP_STRING("printerdev", USBPrinterState, printerdev),
+    DEFINE_PROP_STRING("terminal", USBPrinterState, terminal),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_printer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *k = USB_DEVICE_CLASS(klass);
+
+    device_class_set_props(dc, usb_printer_properties);
+    set_bit(DEVICE_CATEGORY_USB, dc->categories);
+    k->product_desc   = "QEMU USB Printer Interface";
+    k->realize        = usb_printer_realize;
+    k->handle_reset   = usb_printer_handle_reset;
+    k->handle_control = usb_printer_handle_control;
+    k->handle_data    = usb_printer_handle_data;
+    k->unrealize      = usb_printer_unrealize;
+    k->set_interface = usb_printer_set_interface;
+}
+
+static const TypeInfo usb_printer_info = {
+    .name          = TYPE_USB_PRINTER,
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBPrinterState),
+    .class_init    = usb_printer_class_init,
+};
+
+static void usb_printer_register_types(void)
+{
+    type_register_static(&usb_printer_info);
+}
+
+type_init(usb_printer_register_types)
diff --git a/hw/usb/meson.build b/hw/usb/meson.build
index de853d780d..f79d5e1f74 100644
--- a/hw/usb/meson.build
+++ b/hw/usb/meson.build
@@ -44,6 +44,7 @@ softmmu_ss.add(when: 'CONFIG_USB_STORAGE_UAS', if_true: files('dev-uas.c'))
 softmmu_ss.add(when: 'CONFIG_USB_AUDIO', if_true: files('dev-audio.c'))
 softmmu_ss.add(when: 'CONFIG_USB_SERIAL', if_true: files('dev-serial.c'))
 softmmu_ss.add(when: 'CONFIG_USB_NETWORK', if_true: files('dev-network.c'))
+softmmu_ss.add(when: 'CONFIG_USB_PRINTER', if_true: files('dev-printer.c'))
 softmmu_ss.add(when: ['CONFIG_POSIX', 'CONFIG_USB_STORAGE_MTP'], if_true: files('dev-mtp.c'))
 
 # smartcard
diff --git a/hw/usb/trace-events b/hw/usb/trace-events
index b8287b63f1..e3fed30c43 100644
--- a/hw/usb/trace-events
+++ b/hw/usb/trace-events
@@ -345,3 +345,14 @@ usb_serial_set_baud(int bus, int addr, int baud) "dev %d:%u baud rate %d"
 usb_serial_set_data(int bus, int addr, int parity, int data, int stop) "dev %d:%u parity %c, data bits %d, stop bits %d"
 usb_serial_set_flow_control(int bus, int addr, int index) "dev %d:%u flow control %d"
 usb_serial_set_xonxoff(int bus, int addr, uint8_t xon, uint8_t xoff) "dev %d:%u xon 0x%x xoff 0x%x"
+
+# dev-printer.c
+usb_printer_handle_reset(int bus, int addr) "dev %d:%u reset"
+usb_printer_get_device_id(int bus, int addr) "dev %d:%u get device id"
+usb_printer_get_port_status(int bus, int addr) "dev %d:%u get port status"
+usb_printer_handle_soft_reset(int bus, int addr) "dev %d:%u soft reset"
+usb_printer_handle_control_error(int bus, int addr, int request, int value, int index, int length) "dev %d:%u handle control error, request 0x%x, value 0x%x, index 0x%x, length 0x%x"
+usb_printer_handle_data(int bus, int addr, int pid, int ep) "dev %d:%u data, pid 0x%x, ep %d"
+usb_printer_handle_data_out(int bus, int addr, int size) "dev %d:%u data out, size %d"
+usb_printer_handle_data_in(int bus, int addr, int size) "dev %d:%u data in, size %d"
+usb_printer_set_interface(int bus, int addr, int iface, int old, int value) "dev %d:%u set interface %d, old %d, value %d"
diff --git a/include/hw/usb/printer.h b/include/hw/usb/printer.h
new file mode 100644
index 0000000000..0b14e11b8f
--- /dev/null
+++ b/include/hw/usb/printer.h
@@ -0,0 +1,93 @@
+/*
+ * USB Printer Device emulation
+ *
+ * Copyright (c) 2022 ByteDance, Inc.
+ *
+ * Author:
+ *   Ruien Zhang <zhangruien@bytedance.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+/*
+ * References:
+ *   Universal Serial Bus Device Class Definition for Printing Devices,
+ *   version 1.1
+ *   USB Print Interface Class IPP Protocol Specification, revision 1.0
+ */
+
+#ifndef HW_USB_PRINTER_H
+#define HW_USB_PRINTER_H
+
+/* 4.2 Class-Specific Requests */
+#define USBPRINTER_GET_DEVICE_ID   0
+#define USBPRINTER_GET_PORT_STATUS 1
+#define USBPRINTER_SOFT_RESET      2
+
+typedef enum {
+    USB_PRINTER_DEVICE_ID_DEFAULT,
+    USB_PRINTER_DEVICE_ID_MAX
+} USBPrinterDeviceIDType;
+
+typedef const char *USBPrinterDeviceIDStrings[USB_PRINTER_DEVICE_ID_MAX];
+
+/* 4.2.2 GET_PORT_STATUS (bRequest = 1) */
+#define PAPER_EMPTY     (1 << 5)
+#define PAPER_NOT_EMPTY (0 << 5)
+#define SELECTED        (1 << 4)
+#define NOT_SELECTED    (0 << 4)
+#define NO_ERROR        (1 << 3)
+#define ERROR           (0 << 3)
+
+/*
+ * 4.2.3 SOFT_RESET (bRequest = 2)
+ *
+ * "Note: Version 1.0 of the specification incorrectly stated that the
+ *  bmReqestType for SOFT_RESET was 00100011B. Version 1.1 Host software
+ *  implementers should be prepared for USB printers that expect this
+ *  request code, and version 1.1 device implementers should be prepared
+ *  for host software that issues this request code."
+ */
+#define ClassInterfaceOutRequestCompat1_0 \
+        ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER) << 8)
+
+/* 5.3 Interface Descriptors */
+#define EP_NUMS_1                0x01
+#define EP_NUMS_2                0x02
+#define EP_NUM_BULK_OUT          0x01
+#define EP_NUM_BULK_IN           0x02
+#define SC_PRINTERS              0x01
+#define PC_PROTOCOL_UNIDIR       0x01
+#define PC_PROTOCOL_BIDIR        0x02
+#define PC_PROTOCOL_BIDIR_1284_4 0x03
+#define PC_PROTOCOL_IPP_USB      0x04
+#define PC_VENDOR_SPECIFIC       0xff
+
+/* 4.3 Device Info Descriptor: A Class Specific Descriptor */
+#define DEV_INFO_DESC_CHECK_LEN(bLength) \
+        QEMU_BUILD_BUG_ON((bLength) < 10)
+
+#define DEV_INFO_DESC_CHECK_NUM_DESCS(bNumDescriptors) \
+        QEMU_BUILD_BUG_ON((bNumDescriptors) < 1)
+
+#define DEV_INFO_DESC_CHECK_OPT_CT(bCapabilitiesType) \
+        QEMU_BUILD_BUG_ON((bCapabilitiesType) < 0x20 || \
+                          (bCapabilitiesType) > 0xff)
+
+#define IPP_USB_CT_BASIC    0x00
+
+#define IPP_USB_CAP_BASIC_PRINT                 (1 << 0)
+#define IPP_USB_CAP_BASIC_SCAN                  (1 << 1)
+#define IPP_USB_CAP_BASIC_FAX                   (1 << 2)
+#define IPP_USB_CAP_BASIC_OTHER                 (1 << 3)
+#define IPP_USB_CAP_BASIC_ANY_HTTP_1_1_OVER_USB (1 << 4)
+
+#define IPP_USB_CAP_BASIC_AUTH_NONE              (0x00 << 5)
+#define IPP_USB_CAP_BASIC_AUTH_USERNAME_PASSWORD (0x01 << 5)
+#define IPP_USB_CAP_BASIC_AUTH_RESERVED          (0x02 << 5)
+#define IPP_USB_CAP_BASIC_AUTH_NEGOTIATE         (0x03 << 5)
+
+/* TODO: IPP string table in IPP server implementation */
+
+#endif /* HW_USB_PRINTER_H */
-- 
2.11.0



  parent reply	other threads:[~2022-01-13 14:57 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-13 11:56 [PATCH 0/2] Introduce printer subsystem and USB printer device Ruien Zhang
2022-01-13 11:56 ` [PATCH 1/2] printer: Introduce printer subsystem Ruien Zhang
2022-01-13 11:56 ` Ruien Zhang [this message]
2022-01-14  9:32 ` [PATCH 0/2] Introduce printer subsystem and USB printer device Gerd Hoffmann
2022-01-14 13:38   ` Ruien Zhang
2022-01-15 15:31   ` Ruien Zhang
2022-01-17  7:17     ` Gerd Hoffmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220113115659.72788-3-zhangruien@bytedance.com \
    --to=zhangruien@bytedance.com \
    --cc=berrange@redhat.com \
    --cc=eblake@redhat.com \
    --cc=kraxel@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=richard.henderson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.