2017-11-03 11:28:30 +01:00
// SPDX-License-Identifier: GPL-2.0
2006-08-01 11:28:16 +10:00
/*
* gmidi . c - - USB MIDI Gadget Driver
*
* Copyright ( C ) 2006 Thumtronics Pty Ltd .
* Developed for Thumtronics by Grey Innovation
* Ben Williamson < ben . williamson @ greyinnovation . com >
*
* This code is based in part on :
*
* Gadget Zero driver , Copyright ( C ) 2003 - 2004 David Brownell .
* USB Audio driver , Copyright ( C ) 2002 by Takashi Iwai .
* USB MIDI driver , Copyright ( C ) 2002 - 2005 Clemens Ladisch .
*
* Refer to the USB Device Class Definition for MIDI Devices :
* http : //www.usb.org/developers/devclass_docs/midi10.pdf
*/
2007-08-02 00:01:27 -07:00
/* #define VERBOSE_DEBUG */
2006-08-01 11:28:16 +10:00
# include <linux/kernel.h>
2011-07-03 16:09:31 -04:00
# include <linux/module.h>
2006-08-01 11:28:16 +10:00
# include <sound/initval.h>
2012-09-06 20:11:27 +02:00
# include <linux/usb/composite.h>
2007-10-04 18:05:17 -07:00
# include <linux/usb/gadget.h>
2006-08-01 11:28:16 +10:00
2014-10-16 13:33:28 +02:00
# include "u_midi.h"
2008-08-18 17:42:04 -07:00
/*-------------------------------------------------------------------------*/
2006-08-01 11:28:16 +10:00
MODULE_AUTHOR ( " Ben Williamson " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
static const char longname [ ] = " MIDI Gadget " ;
2012-09-10 15:01:53 +02:00
USB_GADGET_COMPOSITE_OPTIONS ( ) ;
2006-08-01 11:28:16 +10:00
static int index = SNDRV_DEFAULT_IDX1 ;
2011-09-28 16:41:33 +02:00
module_param ( index , int , S_IRUGO ) ;
2006-08-01 11:28:16 +10:00
MODULE_PARM_DESC ( index , " Index value for the USB MIDI Gadget adapter. " ) ;
2011-09-28 16:41:33 +02:00
static char * id = SNDRV_DEFAULT_STR1 ;
module_param ( id , charp , S_IRUGO ) ;
MODULE_PARM_DESC ( id , " ID string for the USB MIDI Gadget adapter. " ) ;
2006-08-01 11:28:16 +10:00
2016-08-08 21:30:08 +01:00
static unsigned int buflen = 512 ;
2006-08-01 11:28:16 +10:00
module_param ( buflen , uint , S_IRUGO ) ;
2011-09-28 16:41:33 +02:00
MODULE_PARM_DESC ( buflen , " MIDI buffer length " ) ;
2006-08-01 11:28:16 +10:00
2011-09-28 16:41:33 +02:00
static unsigned int qlen = 32 ;
module_param ( qlen , uint , S_IRUGO ) ;
2015-12-01 18:31:02 +00:00
MODULE_PARM_DESC ( qlen , " USB read and write request queue length " ) ;
2006-08-01 11:28:16 +10:00
2011-09-28 16:41:34 +02:00
static unsigned int in_ports = 1 ;
module_param ( in_ports , uint , S_IRUGO ) ;
MODULE_PARM_DESC ( in_ports , " Number of MIDI input ports " ) ;
static unsigned int out_ports = 1 ;
module_param ( out_ports , uint , S_IRUGO ) ;
MODULE_PARM_DESC ( out_ports , " Number of MIDI output ports " ) ;
2006-08-01 11:28:16 +10:00
/* Thanks to Grey Innovation for donating this product ID.
*
* DO NOT REUSE THESE IDs with a protocol - incompatible driver ! ! Ever ! !
* Instead : allocate your own , using normal USB - IF procedures .
*/
# define DRIVER_VENDOR_NUM 0x17b3 /* Grey Innovation */
# define DRIVER_PRODUCT_NUM 0x0004 /* Linux-USB "MIDI Gadget" */
2011-09-28 16:41:33 +02:00
/* string IDs are assigned dynamically */
2006-08-01 11:28:16 +10:00
2012-09-06 20:11:21 +02:00
# define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX
2006-08-01 11:28:16 +10:00
static struct usb_device_descriptor device_desc = {
. bLength = USB_DT_DEVICE_SIZE ,
. bDescriptorType = USB_DT_DEVICE ,
2015-10-20 18:33:13 +02:00
/* .bcdUSB = DYNAMIC */
2006-08-01 11:28:16 +10:00
. bDeviceClass = USB_CLASS_PER_INTERFACE ,
2015-06-06 07:02:53 +05:30
. idVendor = cpu_to_le16 ( DRIVER_VENDOR_NUM ) ,
. idProduct = cpu_to_le16 ( DRIVER_PRODUCT_NUM ) ,
2011-09-28 16:41:33 +02:00
/* .iManufacturer = DYNAMIC */
/* .iProduct = DYNAMIC */
2006-08-01 11:28:16 +10:00
. bNumConfigurations = 1 ,
} ;
2011-09-28 16:41:33 +02:00
static struct usb_string strings_dev [ ] = {
2012-09-06 20:11:21 +02:00
[ USB_GADGET_MANUFACTURER_IDX ] . s = " Grey Innovation " ,
[ USB_GADGET_PRODUCT_IDX ] . s = " MIDI Gadget " ,
[ USB_GADGET_SERIAL_IDX ] . s = " " ,
2011-09-28 16:41:33 +02:00
[ STRING_DESCRIPTION_IDX ] . s = " MIDI " ,
{ } /* end of list */
2006-08-01 11:28:16 +10:00
} ;
2011-09-28 16:41:33 +02:00
static struct usb_gadget_strings stringtab_dev = {
2006-08-01 11:28:16 +10:00
. language = 0x0409 , /* en-us */
2011-09-28 16:41:33 +02:00
. strings = strings_dev ,
2006-08-01 11:28:16 +10:00
} ;
2011-09-28 16:41:33 +02:00
static struct usb_gadget_strings * dev_strings [ ] = {
& stringtab_dev ,
NULL ,
2006-08-01 11:28:16 +10:00
} ;
2014-11-12 21:28:24 +08:00
static struct usb_function_instance * fi_midi ;
static struct usb_function * f_midi ;
2014-10-16 13:33:28 +02:00
2015-04-11 00:14:21 +02:00
static int midi_unbind ( struct usb_composite_dev * dev )
2006-08-01 11:28:16 +10:00
{
2014-10-16 13:33:28 +02:00
usb_put_function ( f_midi ) ;
usb_put_function_instance ( fi_midi ) ;
2006-08-01 11:28:16 +10:00
return 0 ;
}
2011-09-28 16:41:33 +02:00
static struct usb_configuration midi_config = {
. label = " MIDI Gadget " ,
. bConfigurationValue = 1 ,
/* .iConfiguration = DYNAMIC */
. bmAttributes = USB_CONFIG_ATT_ONE ,
2012-12-03 20:07:05 +01:00
. MaxPower = CONFIG_USB_GADGET_VBUS_DRAW ,
2006-08-01 11:28:16 +10:00
} ;
2015-04-11 00:14:21 +02:00
static int midi_bind_config ( struct usb_configuration * c )
2006-08-01 11:28:16 +10:00
{
2014-10-16 13:33:28 +02:00
int status ;
f_midi = usb_get_function ( fi_midi ) ;
if ( IS_ERR ( f_midi ) )
return PTR_ERR ( f_midi ) ;
status = usb_add_function ( c , f_midi ) ;
if ( status < 0 ) {
usb_put_function ( f_midi ) ;
return status ;
}
return 0 ;
2006-08-01 11:28:16 +10:00
}
2015-04-11 00:14:21 +02:00
static int midi_bind ( struct usb_composite_dev * cdev )
2006-08-01 11:28:16 +10:00
{
2014-10-16 13:33:28 +02:00
struct f_midi_opts * midi_opts ;
2012-09-10 09:16:07 +02:00
int status ;
2006-08-01 11:28:16 +10:00
2014-10-16 13:33:28 +02:00
fi_midi = usb_get_function_instance ( " midi " ) ;
if ( IS_ERR ( fi_midi ) )
return PTR_ERR ( fi_midi ) ;
midi_opts = container_of ( fi_midi , struct f_midi_opts , func_inst ) ;
midi_opts - > index = index ;
midi_opts - > id = id ;
midi_opts - > in_ports = in_ports ;
midi_opts - > out_ports = out_ports ;
midi_opts - > buflen = buflen ;
midi_opts - > qlen = qlen ;
2012-09-06 20:11:16 +02:00
status = usb_string_ids_tab ( cdev , strings_dev ) ;
2011-09-28 16:41:33 +02:00
if ( status < 0 )
2014-10-16 13:33:28 +02:00
goto put ;
2012-09-06 20:11:21 +02:00
device_desc . iManufacturer = strings_dev [ USB_GADGET_MANUFACTURER_IDX ] . id ;
device_desc . iProduct = strings_dev [ USB_GADGET_PRODUCT_IDX ] . id ;
2012-09-06 20:11:16 +02:00
midi_config . iConfiguration = strings_dev [ STRING_DESCRIPTION_IDX ] . id ;
2006-08-01 11:28:16 +10:00
2011-09-28 16:41:33 +02:00
status = usb_add_config ( cdev , & midi_config , midi_bind_config ) ;
if ( status < 0 )
2014-10-16 13:33:28 +02:00
goto put ;
2012-09-10 15:01:53 +02:00
usb_composite_overwrite_options ( cdev , & coverwrite ) ;
2011-09-28 16:41:33 +02:00
pr_info ( " %s \n " , longname ) ;
2006-08-01 11:28:16 +10:00
return 0 ;
2014-10-16 13:33:28 +02:00
put :
usb_put_function_instance ( fi_midi ) ;
return status ;
2006-08-01 11:28:16 +10:00
}
2015-04-11 00:14:21 +02:00
static struct usb_composite_driver midi_driver = {
2011-09-28 16:41:33 +02:00
. name = ( char * ) longname ,
. dev = & device_desc ,
. strings = dev_strings ,
. max_speed = USB_SPEED_HIGH ,
2012-09-06 20:11:04 +02:00
. bind = midi_bind ,
2015-04-11 00:14:21 +02:00
. unbind = midi_unbind ,
2006-08-01 11:28:16 +10:00
} ;
2014-07-09 18:09:56 +02:00
module_usb_composite_driver ( midi_driver ) ;