18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * USB Debug cable driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2006 Greg Kroah-Hartman <greg@kroah.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/gfp.h>
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/tty.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/usb.h>
138c2ecf20Sopenharmony_ci#include <linux/usb/serial.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define USB_DEBUG_MAX_PACKET_SIZE	8
168c2ecf20Sopenharmony_ci#define USB_DEBUG_BRK_SIZE		8
178c2ecf20Sopenharmony_cistatic const char USB_DEBUG_BRK[USB_DEBUG_BRK_SIZE] = {
188c2ecf20Sopenharmony_ci	0x00,
198c2ecf20Sopenharmony_ci	0xff,
208c2ecf20Sopenharmony_ci	0x01,
218c2ecf20Sopenharmony_ci	0xfe,
228c2ecf20Sopenharmony_ci	0x00,
238c2ecf20Sopenharmony_ci	0xfe,
248c2ecf20Sopenharmony_ci	0x01,
258c2ecf20Sopenharmony_ci	0xff,
268c2ecf20Sopenharmony_ci};
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table[] = {
298c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x0525, 0x127a) },
308c2ecf20Sopenharmony_ci	{ },
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic const struct usb_device_id dbc_id_table[] = {
348c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x1d6b, 0x0010) },
358c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x1d6b, 0x0011) },
368c2ecf20Sopenharmony_ci	{ },
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table_combined[] = {
408c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x0525, 0x127a) },
418c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x1d6b, 0x0010) },
428c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x1d6b, 0x0011) },
438c2ecf20Sopenharmony_ci	{ },
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table_combined);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/* This HW really does not support a serial break, so one will be
488c2ecf20Sopenharmony_ci * emulated when ever the break state is set to true.
498c2ecf20Sopenharmony_ci */
508c2ecf20Sopenharmony_cistatic void usb_debug_break_ctl(struct tty_struct *tty, int break_state)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct usb_serial_port *port = tty->driver_data;
538c2ecf20Sopenharmony_ci	if (!break_state)
548c2ecf20Sopenharmony_ci		return;
558c2ecf20Sopenharmony_ci	usb_serial_generic_write(tty, port, USB_DEBUG_BRK, USB_DEBUG_BRK_SIZE);
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic void usb_debug_process_read_urb(struct urb *urb)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	struct usb_serial_port *port = urb->context;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if (urb->actual_length == USB_DEBUG_BRK_SIZE &&
638c2ecf20Sopenharmony_ci		memcmp(urb->transfer_buffer, USB_DEBUG_BRK,
648c2ecf20Sopenharmony_ci						USB_DEBUG_BRK_SIZE) == 0) {
658c2ecf20Sopenharmony_ci		usb_serial_handle_break(port);
668c2ecf20Sopenharmony_ci		return;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	usb_serial_generic_process_read_urb(urb);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic struct usb_serial_driver debug_device = {
738c2ecf20Sopenharmony_ci	.driver = {
748c2ecf20Sopenharmony_ci		.owner =	THIS_MODULE,
758c2ecf20Sopenharmony_ci		.name =		"debug",
768c2ecf20Sopenharmony_ci	},
778c2ecf20Sopenharmony_ci	.id_table =		id_table,
788c2ecf20Sopenharmony_ci	.num_ports =		1,
798c2ecf20Sopenharmony_ci	.bulk_out_size =	USB_DEBUG_MAX_PACKET_SIZE,
808c2ecf20Sopenharmony_ci	.break_ctl =		usb_debug_break_ctl,
818c2ecf20Sopenharmony_ci	.process_read_urb =	usb_debug_process_read_urb,
828c2ecf20Sopenharmony_ci};
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic struct usb_serial_driver dbc_device = {
858c2ecf20Sopenharmony_ci	.driver = {
868c2ecf20Sopenharmony_ci		.owner =	THIS_MODULE,
878c2ecf20Sopenharmony_ci		.name =		"xhci_dbc",
888c2ecf20Sopenharmony_ci	},
898c2ecf20Sopenharmony_ci	.id_table =		dbc_id_table,
908c2ecf20Sopenharmony_ci	.num_ports =		1,
918c2ecf20Sopenharmony_ci	.break_ctl =		usb_debug_break_ctl,
928c2ecf20Sopenharmony_ci	.process_read_urb =	usb_debug_process_read_urb,
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = {
968c2ecf20Sopenharmony_ci	&debug_device, &dbc_device, NULL
978c2ecf20Sopenharmony_ci};
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table_combined);
1008c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
101