brintos

brintos / linux-shallow public Read only

0
0
Text · 14.2 KiB · ca2c6f5 Raw
583 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Line 6 Linux USB driver4 *5 * Copyright (C) 2004-2010 Markus Grabner (line6@grabner-graz.at)6 *                         Emil Myhrman (emil.myhrman@gmail.com)7 */8 9#include <linux/wait.h>10#include <linux/usb.h>11#include <linux/slab.h>12#include <linux/module.h>13#include <linux/leds.h>14#include <sound/core.h>15#include <sound/control.h>16 17#include "capture.h"18#include "driver.h"19#include "playback.h"20 21enum line6_device_type {22	LINE6_GUITARPORT,23	LINE6_PODSTUDIO_GX,24	LINE6_PODSTUDIO_UX1,25	LINE6_PODSTUDIO_UX2,26	LINE6_TONEPORT_GX,27	LINE6_TONEPORT_UX1,28	LINE6_TONEPORT_UX2,29};30 31struct usb_line6_toneport;32 33struct toneport_led {34	struct led_classdev dev;35	char name[64];36	struct usb_line6_toneport *toneport;37	bool registered;38};39 40struct usb_line6_toneport {41	/* Generic Line 6 USB data */42	struct usb_line6 line6;43 44	/* Source selector */45	int source;46 47	/* Serial number of device */48	u32 serial_number;49 50	/* Firmware version (x 100) */51	u8 firmware_version;52 53	/* Device type */54	enum line6_device_type type;55 56	/* LED instances */57	struct toneport_led leds[2];58};59 60#define line6_to_toneport(x) container_of(x, struct usb_line6_toneport, line6)61 62static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);63 64#define TONEPORT_PCM_DELAY 165 66static const struct snd_ratden toneport_ratden = {67	.num_min = 44100,68	.num_max = 44100,69	.num_step = 1,70	.den = 171};72 73static struct line6_pcm_properties toneport_pcm_properties = {74	.playback_hw = {75				  .info = (SNDRV_PCM_INFO_MMAP |76					   SNDRV_PCM_INFO_INTERLEAVED |77					   SNDRV_PCM_INFO_BLOCK_TRANSFER |78					   SNDRV_PCM_INFO_MMAP_VALID |79					   SNDRV_PCM_INFO_PAUSE |80					   SNDRV_PCM_INFO_SYNC_START),81				  .formats = SNDRV_PCM_FMTBIT_S16_LE,82				  .rates = SNDRV_PCM_RATE_KNOT,83				  .rate_min = 44100,84				  .rate_max = 44100,85				  .channels_min = 2,86				  .channels_max = 2,87				  .buffer_bytes_max = 60000,88				  .period_bytes_min = 64,89				  .period_bytes_max = 8192,90				  .periods_min = 1,91				  .periods_max = 1024},92	.capture_hw = {93				 .info = (SNDRV_PCM_INFO_MMAP |94					  SNDRV_PCM_INFO_INTERLEAVED |95					  SNDRV_PCM_INFO_BLOCK_TRANSFER |96					  SNDRV_PCM_INFO_MMAP_VALID |97					  SNDRV_PCM_INFO_SYNC_START),98				 .formats = SNDRV_PCM_FMTBIT_S16_LE,99				 .rates = SNDRV_PCM_RATE_KNOT,100				 .rate_min = 44100,101				 .rate_max = 44100,102				 .channels_min = 2,103				 .channels_max = 2,104				 .buffer_bytes_max = 60000,105				 .period_bytes_min = 64,106				 .period_bytes_max = 8192,107				 .periods_min = 1,108				 .periods_max = 1024},109	.rates = {110			    .nrats = 1,111			    .rats = &toneport_ratden},112	.bytes_per_channel = 2113};114 115static const struct {116	const char *name;117	int code;118} toneport_source_info[] = {119	{"Microphone", 0x0a01},120	{"Line", 0x0801},121	{"Instrument", 0x0b01},122	{"Inst & Mic", 0x0901}123};124 125static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)126{127	int ret;128 129	ret = usb_control_msg_send(usbdev, 0, 0x67,130				   USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,131				   cmd1, cmd2, NULL, 0, LINE6_TIMEOUT,132				   GFP_KERNEL);133 134	if (ret) {135		dev_err(&usbdev->dev, "send failed (error %d)\n", ret);136		return ret;137	}138 139	return 0;140}141 142/* monitor info callback */143static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol,144				     struct snd_ctl_elem_info *uinfo)145{146	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;147	uinfo->count = 1;148	uinfo->value.integer.min = 0;149	uinfo->value.integer.max = 256;150	return 0;151}152 153/* monitor get callback */154static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,155				    struct snd_ctl_elem_value *ucontrol)156{157	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);158 159	ucontrol->value.integer.value[0] = line6pcm->volume_monitor;160	return 0;161}162 163/* monitor put callback */164static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,165				    struct snd_ctl_elem_value *ucontrol)166{167	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);168	int err;169 170	if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)171		return 0;172 173	line6pcm->volume_monitor = ucontrol->value.integer.value[0];174 175	if (line6pcm->volume_monitor > 0) {176		err = line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR, true);177		if (err < 0) {178			line6pcm->volume_monitor = 0;179			line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);180			return err;181		}182	} else {183		line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);184	}185 186	return 1;187}188 189/* source info callback */190static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,191				    struct snd_ctl_elem_info *uinfo)192{193	const int size = ARRAY_SIZE(toneport_source_info);194 195	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;196	uinfo->count = 1;197	uinfo->value.enumerated.items = size;198 199	if (uinfo->value.enumerated.item >= size)200		uinfo->value.enumerated.item = size - 1;201 202	strcpy(uinfo->value.enumerated.name,203	       toneport_source_info[uinfo->value.enumerated.item].name);204 205	return 0;206}207 208/* source get callback */209static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,210				   struct snd_ctl_elem_value *ucontrol)211{212	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);213	struct usb_line6_toneport *toneport = line6_to_toneport(line6pcm->line6);214 215	ucontrol->value.enumerated.item[0] = toneport->source;216	return 0;217}218 219/* source put callback */220static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,221				   struct snd_ctl_elem_value *ucontrol)222{223	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);224	struct usb_line6_toneport *toneport = line6_to_toneport(line6pcm->line6);225	unsigned int source;226 227	source = ucontrol->value.enumerated.item[0];228	if (source >= ARRAY_SIZE(toneport_source_info))229		return -EINVAL;230	if (source == toneport->source)231		return 0;232 233	toneport->source = source;234	toneport_send_cmd(toneport->line6.usbdev,235			  toneport_source_info[source].code, 0x0000);236	return 1;237}238 239static void toneport_startup(struct usb_line6 *line6)240{241	line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR, true);242}243 244/* control definition */245static const struct snd_kcontrol_new toneport_control_monitor = {246	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,247	.name = "Monitor Playback Volume",248	.index = 0,249	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,250	.info = snd_toneport_monitor_info,251	.get = snd_toneport_monitor_get,252	.put = snd_toneport_monitor_put253};254 255/* source selector definition */256static const struct snd_kcontrol_new toneport_control_source = {257	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,258	.name = "PCM Capture Source",259	.index = 0,260	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,261	.info = snd_toneport_source_info,262	.get = snd_toneport_source_get,263	.put = snd_toneport_source_put264};265 266/*267	For the led on Guitarport.268	Brightness goes from 0x00 to 0x26. Set a value above this to have led269	blink.270	(void cmd_0x02(byte red, byte green)271*/272 273static bool toneport_has_led(struct usb_line6_toneport *toneport)274{275	switch (toneport->type) {276	case LINE6_GUITARPORT:277	case LINE6_TONEPORT_GX:278	/* add your device here if you are missing support for the LEDs */279		return true;280 281	default:282		return false;283	}284}285 286static const char * const toneport_led_colors[2] = { "red", "green" };287static const int toneport_led_init_vals[2] = { 0x00, 0x26 };288 289static void toneport_update_led(struct usb_line6_toneport *toneport)290{291	toneport_send_cmd(toneport->line6.usbdev,292			  (toneport->leds[0].dev.brightness << 8) | 0x0002,293			  toneport->leds[1].dev.brightness);294}295 296static void toneport_led_brightness_set(struct led_classdev *led_cdev,297					enum led_brightness brightness)298{299	struct toneport_led *leds =300		container_of(led_cdev, struct toneport_led, dev);301	toneport_update_led(leds->toneport);302}303 304static int toneport_init_leds(struct usb_line6_toneport *toneport)305{306	struct device *dev = &toneport->line6.usbdev->dev;307	int i, err;308 309	for (i = 0; i < 2; i++) {310		struct toneport_led *led = &toneport->leds[i];311		struct led_classdev *leddev = &led->dev;312 313		led->toneport = toneport;314		snprintf(led->name, sizeof(led->name), "%s::%s",315			 dev_name(dev), toneport_led_colors[i]);316		leddev->name = led->name;317		leddev->brightness = toneport_led_init_vals[i];318		leddev->max_brightness = 0x26;319		leddev->brightness_set = toneport_led_brightness_set;320		err = led_classdev_register(dev, leddev);321		if (err)322			return err;323		led->registered = true;324	}325 326	return 0;327}328 329static void toneport_remove_leds(struct usb_line6_toneport *toneport)330{331	struct toneport_led *led;332	int i;333 334	for (i = 0; i < 2; i++) {335		led = &toneport->leds[i];336		if (!led->registered)337			break;338		led_classdev_unregister(&led->dev);339		led->registered = false;340	}341}342 343static bool toneport_has_source_select(struct usb_line6_toneport *toneport)344{345	switch (toneport->type) {346	case LINE6_TONEPORT_UX1:347	case LINE6_TONEPORT_UX2:348	case LINE6_PODSTUDIO_UX1:349	case LINE6_PODSTUDIO_UX2:350		return true;351 352	default:353		return false;354	}355}356 357/*358	Setup Toneport device.359*/360static int toneport_setup(struct usb_line6_toneport *toneport)361{362	u32 *ticks;363	struct usb_line6 *line6 = &toneport->line6;364	struct usb_device *usbdev = line6->usbdev;365 366	ticks = kmalloc(sizeof(*ticks), GFP_KERNEL);367	if (!ticks)368		return -ENOMEM;369 370	/* sync time on device with host: */371	/* note: 32-bit timestamps overflow in year 2106 */372	*ticks = (u32)ktime_get_real_seconds();373	line6_write_data(line6, 0x80c6, ticks, 4);374	kfree(ticks);375 376	/* enable device: */377	toneport_send_cmd(usbdev, 0x0301, 0x0000);378 379	/* initialize source select: */380	if (toneport_has_source_select(toneport))381		toneport_send_cmd(usbdev,382				  toneport_source_info[toneport->source].code,383				  0x0000);384 385	if (toneport_has_led(toneport))386		toneport_update_led(toneport);387 388	schedule_delayed_work(&toneport->line6.startup_work,389			      msecs_to_jiffies(TONEPORT_PCM_DELAY * 1000));390	return 0;391}392 393/*394	Toneport device disconnected.395*/396static void line6_toneport_disconnect(struct usb_line6 *line6)397{398	struct usb_line6_toneport *toneport = line6_to_toneport(line6);399 400	if (toneport_has_led(toneport))401		toneport_remove_leds(toneport);402}403 404 405/*406	 Try to init Toneport device.407*/408static int toneport_init(struct usb_line6 *line6,409			 const struct usb_device_id *id)410{411	int err;412	struct usb_line6_toneport *toneport = line6_to_toneport(line6);413 414	toneport->type = id->driver_info;415 416	line6->disconnect = line6_toneport_disconnect;417	line6->startup = toneport_startup;418 419	/* initialize PCM subsystem: */420	err = line6_init_pcm(line6, &toneport_pcm_properties);421	if (err < 0)422		return err;423 424	/* register monitor control: */425	err = snd_ctl_add(line6->card,426			  snd_ctl_new1(&toneport_control_monitor,427				       line6->line6pcm));428	if (err < 0)429		return err;430 431	/* register source select control: */432	if (toneport_has_source_select(toneport)) {433		err =434		    snd_ctl_add(line6->card,435				snd_ctl_new1(&toneport_control_source,436					     line6->line6pcm));437		if (err < 0)438			return err;439	}440 441	line6_read_serial_number(line6, &toneport->serial_number);442	line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);443 444	if (toneport_has_led(toneport)) {445		err = toneport_init_leds(toneport);446		if (err < 0)447			return err;448	}449 450	err = toneport_setup(toneport);451	if (err)452		return err;453 454	/* register audio system: */455	return snd_card_register(line6->card);456}457 458#ifdef CONFIG_PM459/*460	Resume Toneport device after reset.461*/462static int toneport_reset_resume(struct usb_interface *interface)463{464	int err;465 466	err = toneport_setup(usb_get_intfdata(interface));467	if (err)468		return err;469	return line6_resume(interface);470}471#endif472 473#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)474#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)475 476/* table of devices that work with this driver */477static const struct usb_device_id toneport_id_table[] = {478	{ LINE6_DEVICE(0x4750),    .driver_info = LINE6_GUITARPORT },479	{ LINE6_DEVICE(0x4153),    .driver_info = LINE6_PODSTUDIO_GX },480	{ LINE6_DEVICE(0x4150),    .driver_info = LINE6_PODSTUDIO_UX1 },481	{ LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 },482	{ LINE6_DEVICE(0x4147),    .driver_info = LINE6_TONEPORT_GX },483	{ LINE6_DEVICE(0x4141),    .driver_info = LINE6_TONEPORT_UX1 },484	{ LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 },485	{}486};487 488MODULE_DEVICE_TABLE(usb, toneport_id_table);489 490static const struct line6_properties toneport_properties_table[] = {491	[LINE6_GUITARPORT] = {492		.id = "GuitarPort",493		.name = "GuitarPort",494		.capabilities	= LINE6_CAP_PCM,495		.altsetting = 2,  /* 1..4 seem to be ok */496		/* no control channel */497		.ep_audio_r = 0x82,498		.ep_audio_w = 0x01,499	},500	[LINE6_PODSTUDIO_GX] = {501		.id = "PODStudioGX",502		.name = "POD Studio GX",503		.capabilities	= LINE6_CAP_PCM,504		.altsetting = 2,  /* 1..4 seem to be ok */505		/* no control channel */506		.ep_audio_r = 0x82,507		.ep_audio_w = 0x01,508	},509	[LINE6_PODSTUDIO_UX1] = {510		.id = "PODStudioUX1",511		.name = "POD Studio UX1",512		.capabilities	= LINE6_CAP_PCM,513		.altsetting = 2,  /* 1..4 seem to be ok */514		/* no control channel */515		.ep_audio_r = 0x82,516		.ep_audio_w = 0x01,517	},518	[LINE6_PODSTUDIO_UX2] = {519		.id = "PODStudioUX2",520		.name = "POD Studio UX2",521		.capabilities	= LINE6_CAP_PCM,522		.altsetting = 2,  /* defaults to 44.1kHz, 16-bit */523		/* no control channel */524		.ep_audio_r = 0x82,525		.ep_audio_w = 0x01,526	},527	[LINE6_TONEPORT_GX] = {528		.id = "TonePortGX",529		.name = "TonePort GX",530		.capabilities	= LINE6_CAP_PCM,531		.altsetting = 2,  /* 1..4 seem to be ok */532		/* no control channel */533		.ep_audio_r = 0x82,534		.ep_audio_w = 0x01,535	},536	[LINE6_TONEPORT_UX1] = {537		.id = "TonePortUX1",538		.name = "TonePort UX1",539		.capabilities	= LINE6_CAP_PCM,540		.altsetting = 2,  /* 1..4 seem to be ok */541		/* no control channel */542		.ep_audio_r = 0x82,543		.ep_audio_w = 0x01,544	},545	[LINE6_TONEPORT_UX2] = {546		.id = "TonePortUX2",547		.name = "TonePort UX2",548		.capabilities	= LINE6_CAP_PCM,549		.altsetting = 2,  /* defaults to 44.1kHz, 16-bit */550		/* no control channel */551		.ep_audio_r = 0x82,552		.ep_audio_w = 0x01,553	},554};555 556/*557	Probe USB device.558*/559static int toneport_probe(struct usb_interface *interface,560			  const struct usb_device_id *id)561{562	return line6_probe(interface, id, "Line6-TonePort",563			   &toneport_properties_table[id->driver_info],564			   toneport_init, sizeof(struct usb_line6_toneport));565}566 567static struct usb_driver toneport_driver = {568	.name = KBUILD_MODNAME,569	.probe = toneport_probe,570	.disconnect = line6_disconnect,571#ifdef CONFIG_PM572	.suspend = line6_suspend,573	.resume = line6_resume,574	.reset_resume = toneport_reset_resume,575#endif576	.id_table = toneport_id_table,577};578 579module_usb_driver(toneport_driver);580 581MODULE_DESCRIPTION("TonePort USB driver");582MODULE_LICENSE("GPL");583