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