1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * USB Wishbone-Serial adapter driver 4 * 5 * Copyright (C) 2013 Wesley W. Terpstra <w.terpstra@gsi.de> 6 * Copyright (C) 2013 GSI Helmholtz Centre for Heavy Ion Research GmbH 7 */ 8 9 #include <linux/kernel.h> 10 #include <linux/tty.h> 11 #include <linux/module.h> 12 #include <linux/usb.h> 13 #include <linux/usb/serial.h> 14 #include <linux/uaccess.h> 15 16 #define GSI_VENDOR_OPENCLOSE 0xB0 17 18 static const struct usb_device_id id_table[] = { 19 { USB_DEVICE_AND_INTERFACE_INFO(0x1D50, 0x6062, 0xFF, 0xFF, 0xFF) }, 20 { }, 21 }; 22 MODULE_DEVICE_TABLE(usb, id_table); 23 24 /* 25 * Etherbone must be told that a new stream has begun before data arrives. 26 * This is necessary to restart the negotiation of Wishbone bus parameters. 27 * Similarly, when the stream ends, Etherbone must be told so that the cycle 28 * line can be driven low in the case that userspace failed to do so. 29 */ 30 static int usb_gsi_openclose(struct usb_serial_port *port, int value) 31 { 32 struct usb_device *dev = port->serial->dev; 33 34 return usb_control_msg( 35 dev, 36 usb_sndctrlpipe(dev, 0), /* Send to EP0OUT */ 37 GSI_VENDOR_OPENCLOSE, 38 USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, 39 value, /* wValue = device is open(1) or closed(0) */ 40 port->serial->interface->cur_altsetting->desc.bInterfaceNumber, 41 NULL, 0, /* There is no data stage */ 42 5000); /* Timeout till operation fails */ 43 } 44 45 static int wishbone_serial_open(struct tty_struct *tty, 46 struct usb_serial_port *port) 47 { 48 int retval; 49 50 retval = usb_gsi_openclose(port, 1); 51 if (retval) { 52 dev_err(&port->serial->dev->dev, 53 "Could not mark device as open (%d)\n", 54 retval); 55 return retval; 56 } 57 58 retval = usb_serial_generic_open(tty, port); 59 if (retval) 60 usb_gsi_openclose(port, 0); 61 62 return retval; 63 } 64 65 static void wishbone_serial_close(struct usb_serial_port *port) 66 { 67 usb_serial_generic_close(port); 68 usb_gsi_openclose(port, 0); 69 } 70 71 static struct usb_serial_driver wishbone_serial_device = { 72 .driver = { 73 .owner = THIS_MODULE, 74 .name = "wishbone_serial", 75 }, 76 .id_table = id_table, 77 .num_ports = 1, 78 .open = &wishbone_serial_open, 79 .close = &wishbone_serial_close, 80 }; 81 82 static struct usb_serial_driver * const serial_drivers[] = { 83 &wishbone_serial_device, NULL 84 }; 85 86 module_usb_serial_driver(serial_drivers, id_table); 87 88 MODULE_AUTHOR("Wesley W. Terpstra <w.terpstra@gsi.de>"); 89 MODULE_DESCRIPTION("USB Wishbone-Serial adapter"); 90 MODULE_LICENSE("GPL"); 91