162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * USB Debug cable driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2006 Greg Kroah-Hartman <greg@kroah.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/gfp.h> 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/tty.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/usb.h> 1362306a36Sopenharmony_ci#include <linux/usb/serial.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define USB_DEBUG_MAX_PACKET_SIZE 8 1662306a36Sopenharmony_ci#define USB_DEBUG_BRK_SIZE 8 1762306a36Sopenharmony_cistatic const char USB_DEBUG_BRK[USB_DEBUG_BRK_SIZE] = { 1862306a36Sopenharmony_ci 0x00, 1962306a36Sopenharmony_ci 0xff, 2062306a36Sopenharmony_ci 0x01, 2162306a36Sopenharmony_ci 0xfe, 2262306a36Sopenharmony_ci 0x00, 2362306a36Sopenharmony_ci 0xfe, 2462306a36Sopenharmony_ci 0x01, 2562306a36Sopenharmony_ci 0xff, 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic const struct usb_device_id id_table[] = { 2962306a36Sopenharmony_ci { USB_DEVICE(0x0525, 0x127a) }, 3062306a36Sopenharmony_ci { }, 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic const struct usb_device_id dbc_id_table[] = { 3462306a36Sopenharmony_ci { USB_DEVICE(0x1d6b, 0x0010) }, 3562306a36Sopenharmony_ci { USB_DEVICE(0x1d6b, 0x0011) }, 3662306a36Sopenharmony_ci { }, 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic const struct usb_device_id id_table_combined[] = { 4062306a36Sopenharmony_ci { USB_DEVICE(0x0525, 0x127a) }, 4162306a36Sopenharmony_ci { USB_DEVICE(0x1d6b, 0x0010) }, 4262306a36Sopenharmony_ci { USB_DEVICE(0x1d6b, 0x0011) }, 4362306a36Sopenharmony_ci { }, 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table_combined); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* This HW really does not support a serial break, so one will be 4862306a36Sopenharmony_ci * emulated when ever the break state is set to true. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_cistatic int usb_debug_break_ctl(struct tty_struct *tty, int break_state) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 5362306a36Sopenharmony_ci int ret; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (!break_state) 5662306a36Sopenharmony_ci return 0; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci ret = usb_serial_generic_write(tty, port, USB_DEBUG_BRK, USB_DEBUG_BRK_SIZE); 5962306a36Sopenharmony_ci if (ret < 0) 6062306a36Sopenharmony_ci return ret; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return 0; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic void usb_debug_process_read_urb(struct urb *urb) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (urb->actual_length == USB_DEBUG_BRK_SIZE && 7062306a36Sopenharmony_ci memcmp(urb->transfer_buffer, USB_DEBUG_BRK, 7162306a36Sopenharmony_ci USB_DEBUG_BRK_SIZE) == 0) { 7262306a36Sopenharmony_ci usb_serial_handle_break(port); 7362306a36Sopenharmony_ci return; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci usb_serial_generic_process_read_urb(urb); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic struct usb_serial_driver debug_device = { 8062306a36Sopenharmony_ci .driver = { 8162306a36Sopenharmony_ci .owner = THIS_MODULE, 8262306a36Sopenharmony_ci .name = "debug", 8362306a36Sopenharmony_ci }, 8462306a36Sopenharmony_ci .id_table = id_table, 8562306a36Sopenharmony_ci .num_ports = 1, 8662306a36Sopenharmony_ci .bulk_out_size = USB_DEBUG_MAX_PACKET_SIZE, 8762306a36Sopenharmony_ci .break_ctl = usb_debug_break_ctl, 8862306a36Sopenharmony_ci .process_read_urb = usb_debug_process_read_urb, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic struct usb_serial_driver dbc_device = { 9262306a36Sopenharmony_ci .driver = { 9362306a36Sopenharmony_ci .owner = THIS_MODULE, 9462306a36Sopenharmony_ci .name = "xhci_dbc", 9562306a36Sopenharmony_ci }, 9662306a36Sopenharmony_ci .id_table = dbc_id_table, 9762306a36Sopenharmony_ci .num_ports = 1, 9862306a36Sopenharmony_ci .break_ctl = usb_debug_break_ctl, 9962306a36Sopenharmony_ci .process_read_urb = usb_debug_process_read_urb, 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 10362306a36Sopenharmony_ci &debug_device, &dbc_device, NULL 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table_combined); 10762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 108