diff options
Diffstat (limited to 'drivers/usb/serial/wishbone-serial.c')
| -rw-r--r-- | drivers/usb/serial/wishbone-serial.c | 95 | 
1 files changed, 95 insertions, 0 deletions
diff --git a/drivers/usb/serial/wishbone-serial.c b/drivers/usb/serial/wishbone-serial.c new file mode 100644 index 00000000000..100573c6f19 --- /dev/null +++ b/drivers/usb/serial/wishbone-serial.c @@ -0,0 +1,95 @@ +/* + * USB Wishbone-Serial adapter driver + * + * Copyright (C) 2013 Wesley W. Terpstra <w.terpstra@gsi.de> + * Copyright (C) 2013 GSI Helmholtz Centre for Heavy Ion Research GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <linux/uaccess.h> + +#define GSI_VENDOR_OPENCLOSE 0xB0 + +static const struct usb_device_id id_table[] = { +	{ USB_DEVICE_AND_INTERFACE_INFO(0x1D50, 0x6062, 0xFF, 0xFF, 0xFF) }, +	{ }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +/* + * Etherbone must be told that a new stream has begun before data arrives. + * This is necessary to restart the negotiation of Wishbone bus parameters. + * Similarly, when the stream ends, Etherbone must be told so that the cycle + * line can be driven low in the case that userspace failed to do so. + */ +static int usb_gsi_openclose(struct usb_serial_port *port, int value) +{ +	struct usb_device *dev = port->serial->dev; + +	return usb_control_msg( +		dev, +		usb_sndctrlpipe(dev, 0), /* Send to EP0OUT */ +		GSI_VENDOR_OPENCLOSE, +		USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, +		value, /* wValue = device is open(1) or closed(0) */ +		port->serial->interface->cur_altsetting->desc.bInterfaceNumber, +		NULL, 0,  /* There is no data stage */ +		5000); /* Timeout till operation fails */ +} + +static int wishbone_serial_open(struct tty_struct *tty, +				struct usb_serial_port *port) +{ +	int retval; + +	retval = usb_gsi_openclose(port, 1); +	if (retval) { +		dev_err(&port->serial->dev->dev, +		       "Could not mark device as open (%d)\n", +		       retval); +		return retval; +	} + +	retval = usb_serial_generic_open(tty, port); +	if (retval) +		usb_gsi_openclose(port, 0); + +	return retval; +} + +static void wishbone_serial_close(struct usb_serial_port *port) +{ +	usb_serial_generic_close(port); +	usb_gsi_openclose(port, 0); +} + +static struct usb_serial_driver wishbone_serial_device = { +	.driver = { +		.owner =	THIS_MODULE, +		.name =		"wishbone_serial", +	}, +	.id_table =		id_table, +	.num_ports =		1, +	.open =			&wishbone_serial_open, +	.close =		&wishbone_serial_close, +}; + +static struct usb_serial_driver * const serial_drivers[] = { +	&wishbone_serial_device, NULL +}; + +module_usb_serial_driver(serial_drivers, id_table); + +MODULE_AUTHOR("Wesley W. Terpstra <w.terpstra@gsi.de>"); +MODULE_DESCRIPTION("USB Wishbone-Serial adapter"); +MODULE_LICENSE("GPL");  |