cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

control.c (16323B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Linux driver for TerraTec DMX 6Fire USB
      4 *
      5 * Mixer control
      6 *
      7 * Author:	Torsten Schenk <torsten.schenk@zoho.com>
      8 * Created:	Jan 01, 2011
      9 * Copyright:	(C) Torsten Schenk
     10 *
     11 * Thanks to:
     12 * - Holger Ruckdeschel: he found out how to control individual channel
     13 *   volumes and introduced mute switch
     14 */
     15
     16#include <linux/interrupt.h>
     17#include <sound/control.h>
     18#include <sound/tlv.h>
     19
     20#include "control.h"
     21#include "comm.h"
     22#include "chip.h"
     23
     24static const char * const opt_coax_texts[2] = { "Optical", "Coax" };
     25static const char * const line_phono_texts[2] = { "Line", "Phono" };
     26
     27/*
     28 * data that needs to be sent to device. sets up card internal stuff.
     29 * values dumped from windows driver and filtered by trial'n'error.
     30 */
     31static const struct {
     32	u8 type;
     33	u8 reg;
     34	u8 value;
     35}
     36init_data[] = {
     37	{ 0x22, 0x00, 0x00 }, { 0x20, 0x00, 0x08 }, { 0x22, 0x01, 0x01 },
     38	{ 0x20, 0x01, 0x08 }, { 0x22, 0x02, 0x00 }, { 0x20, 0x02, 0x08 },
     39	{ 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 },
     40	{ 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 },
     41	{ 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 },
     42	{ 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 },
     43	{ 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 },
     44	{ 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 },
     45	{ 0 } /* TERMINATING ENTRY */
     46};
     47
     48static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
     49/* values to write to soundcard register for all samplerates */
     50static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
     51static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
     52
     53static DECLARE_TLV_DB_MINMAX(tlv_output, -9000, 0);
     54static DECLARE_TLV_DB_MINMAX(tlv_input, -1500, 1500);
     55
     56enum {
     57	DIGITAL_THRU_ONLY_SAMPLERATE = 3
     58};
     59
     60static void usb6fire_control_output_vol_update(struct control_runtime *rt)
     61{
     62	struct comm_runtime *comm_rt = rt->chip->comm;
     63	int i;
     64
     65	if (comm_rt)
     66		for (i = 0; i < 6; i++)
     67			if (!(rt->ovol_updated & (1 << i))) {
     68				comm_rt->write8(comm_rt, 0x12, 0x0f + i,
     69					180 - rt->output_vol[i]);
     70				rt->ovol_updated |= 1 << i;
     71			}
     72}
     73
     74static void usb6fire_control_output_mute_update(struct control_runtime *rt)
     75{
     76	struct comm_runtime *comm_rt = rt->chip->comm;
     77
     78	if (comm_rt)
     79		comm_rt->write8(comm_rt, 0x12, 0x0e, ~rt->output_mute);
     80}
     81
     82static void usb6fire_control_input_vol_update(struct control_runtime *rt)
     83{
     84	struct comm_runtime *comm_rt = rt->chip->comm;
     85	int i;
     86
     87	if (comm_rt)
     88		for (i = 0; i < 2; i++)
     89			if (!(rt->ivol_updated & (1 << i))) {
     90				comm_rt->write8(comm_rt, 0x12, 0x1c + i,
     91					rt->input_vol[i] & 0x3f);
     92				rt->ivol_updated |= 1 << i;
     93			}
     94}
     95
     96static void usb6fire_control_line_phono_update(struct control_runtime *rt)
     97{
     98	struct comm_runtime *comm_rt = rt->chip->comm;
     99	if (comm_rt) {
    100		comm_rt->write8(comm_rt, 0x22, 0x02, rt->line_phono_switch);
    101		comm_rt->write8(comm_rt, 0x21, 0x02, rt->line_phono_switch);
    102	}
    103}
    104
    105static void usb6fire_control_opt_coax_update(struct control_runtime *rt)
    106{
    107	struct comm_runtime *comm_rt = rt->chip->comm;
    108	if (comm_rt) {
    109		comm_rt->write8(comm_rt, 0x22, 0x00, rt->opt_coax_switch);
    110		comm_rt->write8(comm_rt, 0x21, 0x00, rt->opt_coax_switch);
    111	}
    112}
    113
    114static int usb6fire_control_set_rate(struct control_runtime *rt, int rate)
    115{
    116	int ret;
    117	struct usb_device *device = rt->chip->dev;
    118	struct comm_runtime *comm_rt = rt->chip->comm;
    119
    120	if (rate < 0 || rate >= CONTROL_N_RATES)
    121		return -EINVAL;
    122
    123	ret = usb_set_interface(device, 1, rates_altsetting[rate]);
    124	if (ret < 0)
    125		return ret;
    126
    127	/* set soundcard clock */
    128	ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate],
    129			rates_6fire_vh[rate]);
    130	if (ret < 0)
    131		return ret;
    132
    133	return 0;
    134}
    135
    136static int usb6fire_control_set_channels(
    137	struct control_runtime *rt, int n_analog_out,
    138	int n_analog_in, bool spdif_out, bool spdif_in)
    139{
    140	int ret;
    141	struct comm_runtime *comm_rt = rt->chip->comm;
    142
    143	/* enable analog inputs and outputs
    144	 * (one bit per stereo-channel) */
    145	ret = comm_rt->write16(comm_rt, 0x02, 0x02,
    146			(1 << (n_analog_out / 2)) - 1,
    147			(1 << (n_analog_in / 2)) - 1);
    148	if (ret < 0)
    149		return ret;
    150
    151	/* disable digital inputs and outputs */
    152	/* TODO: use spdif_x to enable/disable digital channels */
    153	ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
    154	if (ret < 0)
    155		return ret;
    156
    157	return 0;
    158}
    159
    160static int usb6fire_control_streaming_update(struct control_runtime *rt)
    161{
    162	struct comm_runtime *comm_rt = rt->chip->comm;
    163
    164	if (comm_rt) {
    165		if (!rt->usb_streaming && rt->digital_thru_switch)
    166			usb6fire_control_set_rate(rt,
    167				DIGITAL_THRU_ONLY_SAMPLERATE);
    168		return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00,
    169			(rt->usb_streaming ? 0x01 : 0x00) |
    170			(rt->digital_thru_switch ? 0x08 : 0x00));
    171	}
    172	return -EINVAL;
    173}
    174
    175static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol,
    176		struct snd_ctl_elem_info *uinfo)
    177{
    178	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    179	uinfo->count = 2;
    180	uinfo->value.integer.min = 0;
    181	uinfo->value.integer.max = 180;
    182	return 0;
    183}
    184
    185static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol,
    186		struct snd_ctl_elem_value *ucontrol)
    187{
    188	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
    189	unsigned int ch = kcontrol->private_value;
    190	int changed = 0;
    191
    192	if (ch > 4) {
    193		dev_err(&rt->chip->dev->dev,
    194			"Invalid channel in volume control.");
    195		return -EINVAL;
    196	}
    197
    198	if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) {
    199		rt->output_vol[ch] = ucontrol->value.integer.value[0];
    200		rt->ovol_updated &= ~(1 << ch);
    201		changed = 1;
    202	}
    203	if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) {
    204		rt->output_vol[ch + 1] = ucontrol->value.integer.value[1];
    205		rt->ovol_updated &= ~(2 << ch);
    206		changed = 1;
    207	}
    208
    209	if (changed)
    210		usb6fire_control_output_vol_update(rt);
    211
    212	return changed;
    213}
    214
    215static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol,
    216		struct snd_ctl_elem_value *ucontrol)
    217{
    218	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
    219	unsigned int ch = kcontrol->private_value;
    220
    221	if (ch > 4) {
    222		dev_err(&rt->chip->dev->dev,
    223			"Invalid channel in volume control.");
    224		return -EINVAL;
    225	}
    226
    227	ucontrol->value.integer.value[0] = rt->output_vol[ch];
    228	ucontrol->value.integer.value[1] = rt->output_vol[ch + 1];
    229	return 0;
    230}
    231
    232static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol,
    233	struct snd_ctl_elem_value *ucontrol)
    234{
    235	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
    236	unsigned int ch = kcontrol->private_value;
    237	u8 old = rt->output_mute;
    238	u8 value = 0;
    239
    240	if (ch > 4) {
    241		dev_err(&rt->chip->dev->dev,
    242			"Invalid channel in volume control.");
    243		return -EINVAL;
    244	}
    245
    246	rt->output_mute &= ~(3 << ch);
    247	if (ucontrol->value.integer.value[0])
    248		value |= 1;
    249	if (ucontrol->value.integer.value[1])
    250		value |= 2;
    251	rt->output_mute |= value << ch;
    252
    253	if (rt->output_mute != old)
    254		usb6fire_control_output_mute_update(rt);
    255
    256	return rt->output_mute != old;
    257}
    258
    259static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol,
    260	struct snd_ctl_elem_value *ucontrol)
    261{
    262	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
    263	unsigned int ch = kcontrol->private_value;
    264	u8 value = rt->output_mute >> ch;
    265
    266	if (ch > 4) {
    267		dev_err(&rt->chip->dev->dev,
    268			"Invalid channel in volume control.");
    269		return -EINVAL;
    270	}
    271
    272	ucontrol->value.integer.value[0] = 1 & value;
    273	value >>= 1;
    274	ucontrol->value.integer.value[1] = 1 & value;
    275
    276	return 0;
    277}
    278
    279static int usb6fire_control_input_vol_info(struct snd_kcontrol *kcontrol,
    280		struct snd_ctl_elem_info *uinfo)
    281{
    282	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    283	uinfo->count = 2;
    284	uinfo->value.integer.min = 0;
    285	uinfo->value.integer.max = 30;
    286	return 0;
    287}
    288
    289static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol,
    290		struct snd_ctl_elem_value *ucontrol)
    291{
    292	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
    293	int changed = 0;
    294
    295	if (rt->input_vol[0] != ucontrol->value.integer.value[0]) {
    296		rt->input_vol[0] = ucontrol->value.integer.value[0] - 15;
    297		rt->ivol_updated &= ~(1 << 0);
    298		changed = 1;
    299	}
    300	if (rt->input_vol[1] != ucontrol->value.integer.value[1]) {
    301		rt->input_vol[1] = ucontrol->value.integer.value[1] - 15;
    302		rt->ivol_updated &= ~(1 << 1);
    303		changed = 1;
    304	}
    305
    306	if (changed)
    307		usb6fire_control_input_vol_update(rt);
    308
    309	return changed;
    310}
    311
    312static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol,
    313		struct snd_ctl_elem_value *ucontrol)
    314{
    315	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
    316
    317	ucontrol->value.integer.value[0] = rt->input_vol[0] + 15;
    318	ucontrol->value.integer.value[1] = rt->input_vol[1] + 15;
    319
    320	return 0;
    321}
    322
    323static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol,
    324		struct snd_ctl_elem_info *uinfo)
    325{
    326	return snd_ctl_enum_info(uinfo, 1, 2, line_phono_texts);
    327}
    328
    329static int usb6fire_control_line_phono_put(struct snd_kcontrol *kcontrol,
    330		struct snd_ctl_elem_value *ucontrol)
    331{
    332	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
    333	int changed = 0;
    334	if (rt->line_phono_switch != ucontrol->value.integer.value[0]) {
    335		rt->line_phono_switch = ucontrol->value.integer.value[0];
    336		usb6fire_control_line_phono_update(rt);
    337		changed = 1;
    338	}
    339	return changed;
    340}
    341
    342static int usb6fire_control_line_phono_get(struct snd_kcontrol *kcontrol,
    343		struct snd_ctl_elem_value *ucontrol)
    344{
    345	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
    346	ucontrol->value.integer.value[0] = rt->line_phono_switch;
    347	return 0;
    348}
    349
    350static int usb6fire_control_opt_coax_info(struct snd_kcontrol *kcontrol,
    351		struct snd_ctl_elem_info *uinfo)
    352{
    353	return snd_ctl_enum_info(uinfo, 1, 2, opt_coax_texts);
    354}
    355
    356static int usb6fire_control_opt_coax_put(struct snd_kcontrol *kcontrol,
    357		struct snd_ctl_elem_value *ucontrol)
    358{
    359	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
    360	int changed = 0;
    361
    362	if (rt->opt_coax_switch != ucontrol->value.enumerated.item[0]) {
    363		rt->opt_coax_switch = ucontrol->value.enumerated.item[0];
    364		usb6fire_control_opt_coax_update(rt);
    365		changed = 1;
    366	}
    367	return changed;
    368}
    369
    370static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol,
    371		struct snd_ctl_elem_value *ucontrol)
    372{
    373	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
    374	ucontrol->value.enumerated.item[0] = rt->opt_coax_switch;
    375	return 0;
    376}
    377
    378static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol,
    379		struct snd_ctl_elem_value *ucontrol)
    380{
    381	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
    382	int changed = 0;
    383
    384	if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) {
    385		rt->digital_thru_switch = ucontrol->value.integer.value[0];
    386		usb6fire_control_streaming_update(rt);
    387		changed = 1;
    388	}
    389	return changed;
    390}
    391
    392static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol,
    393		struct snd_ctl_elem_value *ucontrol)
    394{
    395	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
    396	ucontrol->value.integer.value[0] = rt->digital_thru_switch;
    397	return 0;
    398}
    399
    400static const struct snd_kcontrol_new vol_elements[] = {
    401	{
    402		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    403		.name = "Analog Playback Volume",
    404		.index = 0,
    405		.private_value = 0,
    406		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
    407			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
    408		.info = usb6fire_control_output_vol_info,
    409		.get = usb6fire_control_output_vol_get,
    410		.put = usb6fire_control_output_vol_put,
    411		.tlv = { .p = tlv_output }
    412	},
    413	{
    414		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    415		.name = "Analog Playback Volume",
    416		.index = 1,
    417		.private_value = 2,
    418		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
    419			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
    420		.info = usb6fire_control_output_vol_info,
    421		.get = usb6fire_control_output_vol_get,
    422		.put = usb6fire_control_output_vol_put,
    423		.tlv = { .p = tlv_output }
    424	},
    425	{
    426		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    427		.name = "Analog Playback Volume",
    428		.index = 2,
    429		.private_value = 4,
    430		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
    431			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
    432		.info = usb6fire_control_output_vol_info,
    433		.get = usb6fire_control_output_vol_get,
    434		.put = usb6fire_control_output_vol_put,
    435		.tlv = { .p = tlv_output }
    436	},
    437	{}
    438};
    439
    440static const struct snd_kcontrol_new mute_elements[] = {
    441	{
    442		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    443		.name = "Analog Playback Switch",
    444		.index = 0,
    445		.private_value = 0,
    446		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
    447		.info = snd_ctl_boolean_stereo_info,
    448		.get = usb6fire_control_output_mute_get,
    449		.put = usb6fire_control_output_mute_put,
    450	},
    451	{
    452		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    453		.name = "Analog Playback Switch",
    454		.index = 1,
    455		.private_value = 2,
    456		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
    457		.info = snd_ctl_boolean_stereo_info,
    458		.get = usb6fire_control_output_mute_get,
    459		.put = usb6fire_control_output_mute_put,
    460	},
    461	{
    462		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    463		.name = "Analog Playback Switch",
    464		.index = 2,
    465		.private_value = 4,
    466		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
    467		.info = snd_ctl_boolean_stereo_info,
    468		.get = usb6fire_control_output_mute_get,
    469		.put = usb6fire_control_output_mute_put,
    470	},
    471	{}
    472};
    473
    474static const struct snd_kcontrol_new elements[] = {
    475	{
    476		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    477		.name = "Line/Phono Capture Route",
    478		.index = 0,
    479		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
    480		.info = usb6fire_control_line_phono_info,
    481		.get = usb6fire_control_line_phono_get,
    482		.put = usb6fire_control_line_phono_put
    483	},
    484	{
    485		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    486		.name = "Opt/Coax Capture Route",
    487		.index = 0,
    488		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
    489		.info = usb6fire_control_opt_coax_info,
    490		.get = usb6fire_control_opt_coax_get,
    491		.put = usb6fire_control_opt_coax_put
    492	},
    493	{
    494		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    495		.name = "Digital Thru Playback Route",
    496		.index = 0,
    497		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
    498		.info = snd_ctl_boolean_mono_info,
    499		.get = usb6fire_control_digital_thru_get,
    500		.put = usb6fire_control_digital_thru_put
    501	},
    502	{
    503		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    504		.name = "Analog Capture Volume",
    505		.index = 0,
    506		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
    507			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
    508		.info = usb6fire_control_input_vol_info,
    509		.get = usb6fire_control_input_vol_get,
    510		.put = usb6fire_control_input_vol_put,
    511		.tlv = { .p = tlv_input }
    512	},
    513	{}
    514};
    515
    516static int usb6fire_control_add_virtual(
    517	struct control_runtime *rt,
    518	struct snd_card *card,
    519	char *name,
    520	const struct snd_kcontrol_new *elems)
    521{
    522	int ret;
    523	int i;
    524	struct snd_kcontrol *vmaster =
    525		snd_ctl_make_virtual_master(name, tlv_output);
    526	struct snd_kcontrol *control;
    527
    528	if (!vmaster)
    529		return -ENOMEM;
    530	ret = snd_ctl_add(card, vmaster);
    531	if (ret < 0)
    532		return ret;
    533
    534	i = 0;
    535	while (elems[i].name) {
    536		control = snd_ctl_new1(&elems[i], rt);
    537		if (!control)
    538			return -ENOMEM;
    539		ret = snd_ctl_add(card, control);
    540		if (ret < 0)
    541			return ret;
    542		ret = snd_ctl_add_follower(vmaster, control);
    543		if (ret < 0)
    544			return ret;
    545		i++;
    546	}
    547	return 0;
    548}
    549
    550int usb6fire_control_init(struct sfire_chip *chip)
    551{
    552	int i;
    553	int ret;
    554	struct control_runtime *rt = kzalloc(sizeof(struct control_runtime),
    555			GFP_KERNEL);
    556	struct comm_runtime *comm_rt = chip->comm;
    557
    558	if (!rt)
    559		return -ENOMEM;
    560
    561	rt->chip = chip;
    562	rt->update_streaming = usb6fire_control_streaming_update;
    563	rt->set_rate = usb6fire_control_set_rate;
    564	rt->set_channels = usb6fire_control_set_channels;
    565
    566	i = 0;
    567	while (init_data[i].type) {
    568		comm_rt->write8(comm_rt, init_data[i].type, init_data[i].reg,
    569				init_data[i].value);
    570		i++;
    571	}
    572
    573	usb6fire_control_opt_coax_update(rt);
    574	usb6fire_control_line_phono_update(rt);
    575	usb6fire_control_output_vol_update(rt);
    576	usb6fire_control_output_mute_update(rt);
    577	usb6fire_control_input_vol_update(rt);
    578	usb6fire_control_streaming_update(rt);
    579
    580	ret = usb6fire_control_add_virtual(rt, chip->card,
    581		"Master Playback Volume", vol_elements);
    582	if (ret) {
    583		dev_err(&chip->dev->dev, "cannot add control.\n");
    584		kfree(rt);
    585		return ret;
    586	}
    587	ret = usb6fire_control_add_virtual(rt, chip->card,
    588		"Master Playback Switch", mute_elements);
    589	if (ret) {
    590		dev_err(&chip->dev->dev, "cannot add control.\n");
    591		kfree(rt);
    592		return ret;
    593	}
    594
    595	i = 0;
    596	while (elements[i].name) {
    597		ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt));
    598		if (ret < 0) {
    599			kfree(rt);
    600			dev_err(&chip->dev->dev, "cannot add control.\n");
    601			return ret;
    602		}
    603		i++;
    604	}
    605
    606	chip->control = rt;
    607	return 0;
    608}
    609
    610void usb6fire_control_abort(struct sfire_chip *chip)
    611{}
    612
    613void usb6fire_control_destroy(struct sfire_chip *chip)
    614{
    615	kfree(chip->control);
    616	chip->control = NULL;
    617}