Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: usb/6fire - Driver for TerraTec DMX 6Fire USB

What is working: Everything except SPDIF
- Hardware Master volume
- PCM 44-192kHz@24 bits, 6 channels out, 4 channels in (analog)
- MIDI in/out
- firmware loading after cold start
- phono/line switching

Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Torsten Schenk and committed by
Takashi Iwai
c6d43ba8 49c6ad43

+2313 -1
+3
sound/usb/6fire/Makefile
··· 1 + snd-usb-6fire-objs += chip.o comm.o midi.o control.o firmware.o pcm.o 2 + obj-$(CONFIG_SND_USB_6FIRE) += snd-usb-6fire.o 3 +
+232
sound/usb/6fire/chip.c
··· 1 + /* 2 + * Linux driver for TerraTec DMX 6Fire USB 3 + * 4 + * Main routines and module definitions. 5 + * 6 + * Author: Torsten Schenk <torsten.schenk@zoho.com> 7 + * Created: Jan 01, 2011 8 + * Version: 0.3.0 9 + * Copyright: (C) Torsten Schenk 10 + * 11 + * This program is free software; you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License as published by 13 + * the Free Software Foundation; either version 2 of the License, or 14 + * (at your option) any later version. 15 + */ 16 + 17 + #include "chip.h" 18 + #include "firmware.h" 19 + #include "pcm.h" 20 + #include "control.h" 21 + #include "comm.h" 22 + #include "midi.h" 23 + 24 + #include <linux/moduleparam.h> 25 + #include <linux/interrupt.h> 26 + #include <linux/module.h> 27 + #include <linux/init.h> 28 + #include <linux/gfp.h> 29 + #include <sound/initval.h> 30 + 31 + MODULE_AUTHOR("Torsten Schenk <torsten.schenk@zoho.com>"); 32 + MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver, version 0.3.0"); 33 + MODULE_LICENSE("GPL v2"); 34 + MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}"); 35 + 36 + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ 37 + static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */ 38 + static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable card */ 39 + static struct sfire_chip *chips[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; 40 + static struct usb_device *devices[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; 41 + 42 + module_param_array(index, int, NULL, 0444); 43 + MODULE_PARM_DESC(index, "Index value for the 6fire sound device"); 44 + module_param_array(id, charp, NULL, 0444); 45 + MODULE_PARM_DESC(id, "ID string for the 6fire sound device."); 46 + module_param_array(enable, bool, NULL, 0444); 47 + MODULE_PARM_DESC(enable, "Enable the 6fire sound device."); 48 + 49 + static DEFINE_MUTEX(register_mutex); 50 + 51 + static void usb6fire_chip_abort(struct sfire_chip *chip) 52 + { 53 + if (chip) { 54 + if (chip->pcm) 55 + usb6fire_pcm_abort(chip); 56 + if (chip->midi) 57 + usb6fire_midi_abort(chip); 58 + if (chip->comm) 59 + usb6fire_comm_abort(chip); 60 + if (chip->control) 61 + usb6fire_control_abort(chip); 62 + if (chip->card) { 63 + snd_card_disconnect(chip->card); 64 + snd_card_free_when_closed(chip->card); 65 + chip->card = NULL; 66 + } 67 + } 68 + } 69 + 70 + static void usb6fire_chip_destroy(struct sfire_chip *chip) 71 + { 72 + if (chip) { 73 + if (chip->pcm) 74 + usb6fire_pcm_destroy(chip); 75 + if (chip->midi) 76 + usb6fire_midi_destroy(chip); 77 + if (chip->comm) 78 + usb6fire_comm_destroy(chip); 79 + if (chip->control) 80 + usb6fire_control_destroy(chip); 81 + if (chip->card) 82 + snd_card_free(chip->card); 83 + } 84 + } 85 + 86 + static int __devinit usb6fire_chip_probe(struct usb_interface *intf, 87 + const struct usb_device_id *usb_id) 88 + { 89 + int ret; 90 + int i; 91 + struct sfire_chip *chip = NULL; 92 + struct usb_device *device = interface_to_usbdev(intf); 93 + int regidx = -1; /* index in module parameter array */ 94 + struct snd_card *card = NULL; 95 + 96 + /* look if we already serve this card and return if so */ 97 + mutex_lock(&register_mutex); 98 + for (i = 0; i < SNDRV_CARDS; i++) { 99 + if (devices[i] == device) { 100 + if (chips[i]) 101 + chips[i]->intf_count++; 102 + usb_set_intfdata(intf, chips[i]); 103 + mutex_unlock(&register_mutex); 104 + return 0; 105 + } else if (regidx < 0) 106 + regidx = i; 107 + } 108 + if (regidx < 0) { 109 + mutex_unlock(&register_mutex); 110 + snd_printk(KERN_ERR PREFIX "too many cards registered.\n"); 111 + return -ENODEV; 112 + } 113 + devices[regidx] = device; 114 + mutex_unlock(&register_mutex); 115 + 116 + /* check, if firmware is present on device, upload it if not */ 117 + ret = usb6fire_fw_init(intf); 118 + if (ret < 0) 119 + return ret; 120 + else if (ret == FW_NOT_READY) /* firmware update performed */ 121 + return 0; 122 + 123 + /* if we are here, card can be registered in alsa. */ 124 + if (usb_set_interface(device, 0, 0) != 0) { 125 + snd_printk(KERN_ERR PREFIX "can't set first interface.\n"); 126 + return -EIO; 127 + } 128 + ret = snd_card_create(index[regidx], id[regidx], THIS_MODULE, 129 + sizeof(struct sfire_chip), &card); 130 + if (ret < 0) { 131 + snd_printk(KERN_ERR PREFIX "cannot create alsa card.\n"); 132 + return ret; 133 + } 134 + strcpy(card->driver, "6FireUSB"); 135 + strcpy(card->shortname, "TerraTec DMX6FireUSB"); 136 + sprintf(card->longname, "%s at %d:%d", card->shortname, 137 + device->bus->busnum, device->devnum); 138 + snd_card_set_dev(card, &intf->dev); 139 + 140 + chip = card->private_data; 141 + chips[regidx] = chip; 142 + chip->dev = device; 143 + chip->regidx = regidx; 144 + chip->intf_count = 1; 145 + chip->card = card; 146 + 147 + ret = usb6fire_comm_init(chip); 148 + if (ret < 0) { 149 + usb6fire_chip_destroy(chip); 150 + return ret; 151 + } 152 + 153 + ret = usb6fire_midi_init(chip); 154 + if (ret < 0) { 155 + usb6fire_chip_destroy(chip); 156 + return ret; 157 + } 158 + 159 + ret = usb6fire_pcm_init(chip); 160 + if (ret < 0) { 161 + usb6fire_chip_destroy(chip); 162 + return ret; 163 + } 164 + 165 + ret = usb6fire_control_init(chip); 166 + if (ret < 0) { 167 + usb6fire_chip_destroy(chip); 168 + return ret; 169 + } 170 + 171 + ret = snd_card_register(card); 172 + if (ret < 0) { 173 + snd_printk(KERN_ERR PREFIX "cannot register card."); 174 + usb6fire_chip_destroy(chip); 175 + return ret; 176 + } 177 + usb_set_intfdata(intf, chip); 178 + return 0; 179 + } 180 + 181 + static void usb6fire_chip_disconnect(struct usb_interface *intf) 182 + { 183 + struct sfire_chip *chip; 184 + struct snd_card *card; 185 + 186 + chip = usb_get_intfdata(intf); 187 + if (chip) { /* if !chip, fw upload has been performed */ 188 + card = chip->card; 189 + chip->intf_count--; 190 + if (!chip->intf_count) { 191 + mutex_lock(&register_mutex); 192 + devices[chip->regidx] = NULL; 193 + chips[chip->regidx] = NULL; 194 + mutex_unlock(&register_mutex); 195 + 196 + chip->shutdown = true; 197 + usb6fire_chip_abort(chip); 198 + usb6fire_chip_destroy(chip); 199 + } 200 + } 201 + } 202 + 203 + static struct usb_device_id device_table[] = { 204 + { 205 + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 206 + .idVendor = 0x0ccd, 207 + .idProduct = 0x0080 208 + }, 209 + {} 210 + }; 211 + 212 + MODULE_DEVICE_TABLE(usb, device_table); 213 + 214 + static struct usb_driver driver = { 215 + .name = "snd-usb-6fire", 216 + .probe = usb6fire_chip_probe, 217 + .disconnect = usb6fire_chip_disconnect, 218 + .id_table = device_table, 219 + }; 220 + 221 + static int __init usb6fire_chip_init(void) 222 + { 223 + return usb_register(&driver); 224 + } 225 + 226 + static void __exit usb6fire_chip_cleanup(void) 227 + { 228 + usb_deregister(&driver); 229 + } 230 + 231 + module_init(usb6fire_chip_init); 232 + module_exit(usb6fire_chip_cleanup);
+32
sound/usb/6fire/chip.h
··· 1 + /* 2 + * Linux driver for TerraTec DMX 6Fire USB 3 + * 4 + * Author: Torsten Schenk <torsten.schenk@zoho.com> 5 + * Created: Jan 01, 2011 6 + * Version: 0.3.0 7 + * Copyright: (C) Torsten Schenk 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2 of the License, or 12 + * (at your option) any later version. 13 + */ 14 + #ifndef USB6FIRE_CHIP_H 15 + #define USB6FIRE_CHIP_H 16 + 17 + #include "common.h" 18 + 19 + struct sfire_chip { 20 + struct usb_device *dev; 21 + struct snd_card *card; 22 + int intf_count; /* number of registered interfaces */ 23 + int regidx; /* index in module parameter arrays */ 24 + bool shutdown; 25 + 26 + struct midi_runtime *midi; 27 + struct pcm_runtime *pcm; 28 + struct control_runtime *control; 29 + struct comm_runtime *comm; 30 + }; 31 + #endif /* USB6FIRE_CHIP_H */ 32 +
+176
sound/usb/6fire/comm.c
··· 1 + /* 2 + * Linux driver for TerraTec DMX 6Fire USB 3 + * 4 + * Device communications 5 + * 6 + * Author: Torsten Schenk <torsten.schenk@zoho.com> 7 + * Created: Jan 01, 2011 8 + * Version: 0.3.0 9 + * Copyright: (C) Torsten Schenk 10 + * 11 + * This program is free software; you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License as published by 13 + * the Free Software Foundation; either version 2 of the License, or 14 + * (at your option) any later version. 15 + */ 16 + 17 + #include "comm.h" 18 + #include "chip.h" 19 + #include "midi.h" 20 + 21 + enum { 22 + COMM_EP = 1, 23 + COMM_FPGA_EP = 2 24 + }; 25 + 26 + static void usb6fire_comm_init_urb(struct comm_runtime *rt, struct urb *urb, 27 + u8 *buffer, void *context, void(*handler)(struct urb *urb)) 28 + { 29 + usb_init_urb(urb); 30 + urb->transfer_buffer = buffer; 31 + urb->pipe = usb_sndintpipe(rt->chip->dev, COMM_EP); 32 + urb->complete = handler; 33 + urb->context = context; 34 + urb->interval = 1; 35 + urb->dev = rt->chip->dev; 36 + } 37 + 38 + static void usb6fire_comm_receiver_handler(struct urb *urb) 39 + { 40 + struct comm_runtime *rt = urb->context; 41 + struct midi_runtime *midi_rt = rt->chip->midi; 42 + 43 + if (!urb->status) { 44 + if (rt->receiver_buffer[0] == 0x10) /* midi in event */ 45 + if (midi_rt) 46 + midi_rt->in_received(midi_rt, 47 + rt->receiver_buffer + 2, 48 + rt->receiver_buffer[1]); 49 + } 50 + 51 + if (!rt->chip->shutdown) { 52 + urb->status = 0; 53 + urb->actual_length = 0; 54 + if (usb_submit_urb(urb, GFP_ATOMIC) < 0) 55 + snd_printk(KERN_WARNING PREFIX 56 + "comm data receiver aborted.\n"); 57 + } 58 + } 59 + 60 + static void usb6fire_comm_init_buffer(u8 *buffer, u8 id, u8 request, 61 + u8 reg, u8 vl, u8 vh) 62 + { 63 + buffer[0] = 0x01; 64 + buffer[2] = request; 65 + buffer[3] = id; 66 + switch (request) { 67 + case 0x02: 68 + buffer[1] = 0x05; /* length (starting at buffer[2]) */ 69 + buffer[4] = reg; 70 + buffer[5] = vl; 71 + buffer[6] = vh; 72 + break; 73 + 74 + case 0x12: 75 + buffer[1] = 0x0b; /* length (starting at buffer[2]) */ 76 + buffer[4] = 0x00; 77 + buffer[5] = 0x18; 78 + buffer[6] = 0x05; 79 + buffer[7] = 0x00; 80 + buffer[8] = 0x01; 81 + buffer[9] = 0x00; 82 + buffer[10] = 0x9e; 83 + buffer[11] = reg; 84 + buffer[12] = vl; 85 + break; 86 + 87 + case 0x20: 88 + case 0x21: 89 + case 0x22: 90 + buffer[1] = 0x04; 91 + buffer[4] = reg; 92 + buffer[5] = vl; 93 + break; 94 + } 95 + } 96 + 97 + static int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev) 98 + { 99 + int ret; 100 + int actual_len; 101 + 102 + ret = usb_interrupt_msg(dev, usb_sndintpipe(dev, COMM_EP), 103 + buffer, buffer[1] + 2, &actual_len, HZ); 104 + if (ret < 0) 105 + return ret; 106 + else if (actual_len != buffer[1] + 2) 107 + return -EIO; 108 + return 0; 109 + } 110 + 111 + static int usb6fire_comm_write8(struct comm_runtime *rt, u8 request, 112 + u8 reg, u8 value) 113 + { 114 + u8 buffer[13]; /* 13: maximum length of message */ 115 + 116 + usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00); 117 + return usb6fire_comm_send_buffer(buffer, rt->chip->dev); 118 + } 119 + 120 + static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request, 121 + u8 reg, u8 vl, u8 vh) 122 + { 123 + u8 buffer[13]; /* 13: maximum length of message */ 124 + 125 + usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh); 126 + return usb6fire_comm_send_buffer(buffer, rt->chip->dev); 127 + } 128 + 129 + int __devinit usb6fire_comm_init(struct sfire_chip *chip) 130 + { 131 + struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime), 132 + GFP_KERNEL); 133 + struct urb *urb = &rt->receiver; 134 + int ret; 135 + 136 + if (!rt) 137 + return -ENOMEM; 138 + 139 + rt->serial = 1; 140 + rt->chip = chip; 141 + usb_init_urb(urb); 142 + rt->init_urb = usb6fire_comm_init_urb; 143 + rt->write8 = usb6fire_comm_write8; 144 + rt->write16 = usb6fire_comm_write16; 145 + 146 + /* submit an urb that receives communication data from device */ 147 + urb->transfer_buffer = rt->receiver_buffer; 148 + urb->transfer_buffer_length = COMM_RECEIVER_BUFSIZE; 149 + urb->pipe = usb_rcvintpipe(chip->dev, COMM_EP); 150 + urb->dev = chip->dev; 151 + urb->complete = usb6fire_comm_receiver_handler; 152 + urb->context = rt; 153 + urb->interval = 1; 154 + ret = usb_submit_urb(urb, GFP_KERNEL); 155 + if (ret < 0) { 156 + kfree(rt); 157 + snd_printk(KERN_ERR PREFIX "cannot create comm data receiver."); 158 + return ret; 159 + } 160 + chip->comm = rt; 161 + return 0; 162 + } 163 + 164 + void usb6fire_comm_abort(struct sfire_chip *chip) 165 + { 166 + struct comm_runtime *rt = chip->comm; 167 + 168 + if (rt) 169 + usb_poison_urb(&rt->receiver); 170 + } 171 + 172 + void usb6fire_comm_destroy(struct sfire_chip *chip) 173 + { 174 + kfree(chip->comm); 175 + chip->comm = NULL; 176 + }
+44
sound/usb/6fire/comm.h
··· 1 + /* 2 + * Linux driver for TerraTec DMX 6Fire USB 3 + * 4 + * Author: Torsten Schenk <torsten.schenk@zoho.com> 5 + * Created: Jan 01, 2011 6 + * Version: 0.3.0 7 + * Copyright: (C) Torsten Schenk 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2 of the License, or 12 + * (at your option) any later version. 13 + */ 14 + #ifndef USB6FIRE_COMM_H 15 + #define USB6FIRE_COMM_H 16 + 17 + #include "common.h" 18 + 19 + enum /* settings for comm */ 20 + { 21 + COMM_RECEIVER_BUFSIZE = 64, 22 + }; 23 + 24 + struct comm_runtime { 25 + struct sfire_chip *chip; 26 + 27 + struct urb receiver; 28 + u8 receiver_buffer[COMM_RECEIVER_BUFSIZE]; 29 + 30 + u8 serial; /* urb serial */ 31 + 32 + void (*init_urb)(struct comm_runtime *rt, struct urb *urb, u8 *buffer, 33 + void *context, void(*handler)(struct urb *urb)); 34 + /* writes control data to the device */ 35 + int (*write8)(struct comm_runtime *rt, u8 request, u8 reg, u8 value); 36 + int (*write16)(struct comm_runtime *rt, u8 request, u8 reg, 37 + u8 vh, u8 vl); 38 + }; 39 + 40 + int __devinit usb6fire_comm_init(struct sfire_chip *chip); 41 + void usb6fire_comm_abort(struct sfire_chip *chip); 42 + void usb6fire_comm_destroy(struct sfire_chip *chip); 43 + #endif /* USB6FIRE_COMM_H */ 44 +
+30
sound/usb/6fire/common.h
··· 1 + /* 2 + * Linux driver for TerraTec DMX 6Fire USB 3 + * 4 + * Author: Torsten Schenk <torsten.schenk@zoho.com> 5 + * Created: Jan 01, 2011 6 + * Version: 0.3.0 7 + * Copyright: (C) Torsten Schenk 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2 of the License, or 12 + * (at your option) any later version. 13 + */ 14 + 15 + #ifndef USB6FIRE_COMMON_H 16 + #define USB6FIRE_COMMON_H 17 + 18 + #include <linux/slab.h> 19 + #include <linux/usb.h> 20 + #include <sound/core.h> 21 + 22 + #define PREFIX "6fire: " 23 + 24 + struct sfire_chip; 25 + struct midi_runtime; 26 + struct pcm_runtime; 27 + struct control_runtime; 28 + struct comm_runtime; 29 + #endif /* USB6FIRE_COMMON_H */ 30 +
+275
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 + * Version: 0.3.0 9 + * Copyright: (C) Torsten Schenk 10 + * 11 + * This program is free software; you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License as published by 13 + * the Free Software Foundation; either version 2 of the License, or 14 + * (at your option) any later version. 15 + */ 16 + 17 + #include <linux/interrupt.h> 18 + #include <sound/control.h> 19 + 20 + #include "control.h" 21 + #include "comm.h" 22 + #include "chip.h" 23 + 24 + static char *opt_coax_texts[2] = { "Optical", "Coax" }; 25 + static char *line_phono_texts[2] = { "Line", "Phono" }; 26 + 27 + /* 28 + * calculated with $value\[i\] = 128 \cdot sqrt[3]{\frac{i}{128}}$ 29 + * this is done because the linear values cause rapid degredation 30 + * of volume in the uppermost region. 31 + */ 32 + static const u8 log_volume_table[128] = { 33 + 0x00, 0x19, 0x20, 0x24, 0x28, 0x2b, 0x2e, 0x30, 0x32, 0x34, 34 + 0x36, 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x41, 0x42, 0x43, 35 + 0x44, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 36 + 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x53, 0x54, 0x55, 0x56, 37 + 0x56, 0x57, 0x58, 0x58, 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 38 + 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, 39 + 0x63, 0x63, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68, 40 + 0x68, 0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 41 + 0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, 42 + 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, 43 + 0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 44 + 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 45 + 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f }; 46 + 47 + /* 48 + * data that needs to be sent to device. sets up card internal stuff. 49 + * values dumped from windows driver and filtered by trial'n'error. 50 + */ 51 + static const struct { 52 + u8 type; 53 + u8 reg; 54 + u8 value; 55 + } 56 + init_data[] = { 57 + { 0x22, 0x00, 0x00 }, { 0x20, 0x00, 0x08 }, { 0x22, 0x01, 0x01 }, 58 + { 0x20, 0x01, 0x08 }, { 0x22, 0x02, 0x00 }, { 0x20, 0x02, 0x08 }, 59 + { 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 }, 60 + { 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 }, 61 + { 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 }, 62 + { 0x12, 0x0d, 0x78 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, 63 + { 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 }, 64 + { 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 }, 65 + { 0 } /* TERMINATING ENTRY */ 66 + }; 67 + 68 + static void usb6fire_control_master_vol_update(struct control_runtime *rt) 69 + { 70 + struct comm_runtime *comm_rt = rt->chip->comm; 71 + if (comm_rt) { 72 + /* set volume */ 73 + comm_rt->write8(comm_rt, 0x12, 0x0f, 0x7f - 74 + log_volume_table[rt->master_vol]); 75 + /* unmute */ 76 + comm_rt->write8(comm_rt, 0x12, 0x0e, 0x00); 77 + } 78 + } 79 + 80 + static void usb6fire_control_line_phono_update(struct control_runtime *rt) 81 + { 82 + struct comm_runtime *comm_rt = rt->chip->comm; 83 + if (comm_rt) { 84 + comm_rt->write8(comm_rt, 0x22, 0x02, rt->line_phono_switch); 85 + comm_rt->write8(comm_rt, 0x21, 0x02, rt->line_phono_switch); 86 + } 87 + } 88 + 89 + static void usb6fire_control_opt_coax_update(struct control_runtime *rt) 90 + { 91 + struct comm_runtime *comm_rt = rt->chip->comm; 92 + if (comm_rt) { 93 + comm_rt->write8(comm_rt, 0x22, 0x00, rt->opt_coax_switch); 94 + comm_rt->write8(comm_rt, 0x21, 0x00, rt->opt_coax_switch); 95 + } 96 + } 97 + 98 + static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, 99 + struct snd_ctl_elem_info *uinfo) 100 + { 101 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 102 + uinfo->count = 1; 103 + uinfo->value.integer.min = 0; 104 + uinfo->value.integer.max = 127; 105 + return 0; 106 + } 107 + 108 + static int usb6fire_control_master_vol_put(struct snd_kcontrol *kcontrol, 109 + struct snd_ctl_elem_value *ucontrol) 110 + { 111 + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); 112 + int changed = 0; 113 + if (rt->master_vol != ucontrol->value.integer.value[0]) { 114 + rt->master_vol = ucontrol->value.integer.value[0]; 115 + usb6fire_control_master_vol_update(rt); 116 + changed = 1; 117 + } 118 + return changed; 119 + } 120 + 121 + static int usb6fire_control_master_vol_get(struct snd_kcontrol *kcontrol, 122 + struct snd_ctl_elem_value *ucontrol) 123 + { 124 + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); 125 + ucontrol->value.integer.value[0] = rt->master_vol; 126 + return 0; 127 + } 128 + 129 + static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol, 130 + struct snd_ctl_elem_info *uinfo) 131 + { 132 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 133 + uinfo->count = 1; 134 + uinfo->value.enumerated.items = 2; 135 + if (uinfo->value.enumerated.item > 1) 136 + uinfo->value.enumerated.item = 1; 137 + strcpy(uinfo->value.enumerated.name, 138 + line_phono_texts[uinfo->value.enumerated.item]); 139 + return 0; 140 + } 141 + 142 + static int usb6fire_control_line_phono_put(struct snd_kcontrol *kcontrol, 143 + struct snd_ctl_elem_value *ucontrol) 144 + { 145 + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); 146 + int changed = 0; 147 + if (rt->line_phono_switch != ucontrol->value.integer.value[0]) { 148 + rt->line_phono_switch = ucontrol->value.integer.value[0]; 149 + usb6fire_control_line_phono_update(rt); 150 + changed = 1; 151 + } 152 + return changed; 153 + } 154 + 155 + static int usb6fire_control_line_phono_get(struct snd_kcontrol *kcontrol, 156 + struct snd_ctl_elem_value *ucontrol) 157 + { 158 + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); 159 + ucontrol->value.integer.value[0] = rt->line_phono_switch; 160 + return 0; 161 + } 162 + 163 + static int usb6fire_control_opt_coax_info(struct snd_kcontrol *kcontrol, 164 + struct snd_ctl_elem_info *uinfo) 165 + { 166 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 167 + uinfo->count = 1; 168 + uinfo->value.enumerated.items = 2; 169 + if (uinfo->value.enumerated.item > 1) 170 + uinfo->value.enumerated.item = 1; 171 + strcpy(uinfo->value.enumerated.name, 172 + opt_coax_texts[uinfo->value.enumerated.item]); 173 + return 0; 174 + } 175 + 176 + static int usb6fire_control_opt_coax_put(struct snd_kcontrol *kcontrol, 177 + struct snd_ctl_elem_value *ucontrol) 178 + { 179 + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); 180 + int changed = 0; 181 + 182 + if (rt->opt_coax_switch != ucontrol->value.enumerated.item[0]) { 183 + rt->opt_coax_switch = ucontrol->value.enumerated.item[0]; 184 + usb6fire_control_opt_coax_update(rt); 185 + changed = 1; 186 + } 187 + return changed; 188 + } 189 + 190 + static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol, 191 + struct snd_ctl_elem_value *ucontrol) 192 + { 193 + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); 194 + ucontrol->value.enumerated.item[0] = rt->opt_coax_switch; 195 + return 0; 196 + } 197 + 198 + static struct __devinitdata snd_kcontrol_new elements[] = { 199 + { 200 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 201 + .name = "Master Playback Volume", 202 + .index = 0, 203 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 204 + .info = usb6fire_control_master_vol_info, 205 + .get = usb6fire_control_master_vol_get, 206 + .put = usb6fire_control_master_vol_put 207 + }, 208 + { 209 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 210 + .name = "Line/Phono Capture Route", 211 + .index = 0, 212 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 213 + .info = usb6fire_control_line_phono_info, 214 + .get = usb6fire_control_line_phono_get, 215 + .put = usb6fire_control_line_phono_put 216 + }, 217 + { 218 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 219 + .name = "Opt/Coax Capture Route", 220 + .index = 0, 221 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 222 + .info = usb6fire_control_opt_coax_info, 223 + .get = usb6fire_control_opt_coax_get, 224 + .put = usb6fire_control_opt_coax_put 225 + }, 226 + {} 227 + }; 228 + 229 + int __devinit usb6fire_control_init(struct sfire_chip *chip) 230 + { 231 + int i; 232 + int ret; 233 + struct control_runtime *rt = kzalloc(sizeof(struct control_runtime), 234 + GFP_KERNEL); 235 + struct comm_runtime *comm_rt = chip->comm; 236 + 237 + if (!rt) 238 + return -ENOMEM; 239 + 240 + rt->chip = chip; 241 + 242 + i = 0; 243 + while (init_data[i].type) { 244 + comm_rt->write8(comm_rt, init_data[i].type, init_data[i].reg, 245 + init_data[i].value); 246 + i++; 247 + } 248 + 249 + usb6fire_control_opt_coax_update(rt); 250 + usb6fire_control_line_phono_update(rt); 251 + usb6fire_control_master_vol_update(rt); 252 + 253 + i = 0; 254 + while (elements[i].name) { 255 + ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt)); 256 + if (ret < 0) { 257 + kfree(rt); 258 + snd_printk(KERN_ERR PREFIX "cannot add control.\n"); 259 + return ret; 260 + } 261 + i++; 262 + } 263 + 264 + chip->control = rt; 265 + return 0; 266 + } 267 + 268 + void usb6fire_control_abort(struct sfire_chip *chip) 269 + {} 270 + 271 + void usb6fire_control_destroy(struct sfire_chip *chip) 272 + { 273 + kfree(chip->control); 274 + chip->control = NULL; 275 + }
+37
sound/usb/6fire/control.h
··· 1 + /* 2 + * Linux driver for TerraTec DMX 6Fire USB 3 + * 4 + * Author: Torsten Schenk <torsten.schenk@zoho.com> 5 + * Created: Jan 01, 2011 6 + * Version: 0.3.0 7 + * Copyright: (C) Torsten Schenk 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2 of the License, or 12 + * (at your option) any later version. 13 + */ 14 + 15 + #ifndef USB6FIRE_CONTROL_H 16 + #define USB6FIRE_CONTROL_H 17 + 18 + #include "common.h" 19 + 20 + enum { 21 + CONTROL_MAX_ELEMENTS = 32 22 + }; 23 + 24 + struct control_runtime { 25 + struct sfire_chip *chip; 26 + 27 + struct snd_kcontrol *element[CONTROL_MAX_ELEMENTS]; 28 + bool opt_coax_switch; 29 + bool line_phono_switch; 30 + u8 master_vol; 31 + }; 32 + 33 + int __devinit usb6fire_control_init(struct sfire_chip *chip); 34 + void usb6fire_control_abort(struct sfire_chip *chip); 35 + void usb6fire_control_destroy(struct sfire_chip *chip); 36 + #endif /* USB6FIRE_CONTROL_H */ 37 +
+426
sound/usb/6fire/firmware.c
··· 1 + /* 2 + * Linux driver for TerraTec DMX 6Fire USB 3 + * 4 + * Firmware loader 5 + * 6 + * Currently not working for all devices. To be able to use the device 7 + * in linux, it is also possible to let the windows driver upload the firmware. 8 + * For that, start the computer in windows and reboot. 9 + * As long as the device is connected to the power supply, no firmware reload 10 + * needs to be performed. 11 + * 12 + * Author: Torsten Schenk <torsten.schenk@zoho.com> 13 + * Created: Jan 01, 2011 14 + * Version: 0.3.0 15 + * Copyright: (C) Torsten Schenk 16 + * 17 + * This program is free software; you can redistribute it and/or modify 18 + * it under the terms of the GNU General Public License as published by 19 + * the Free Software Foundation; either version 2 of the License, or 20 + * (at your option) any later version. 21 + */ 22 + 23 + #include <linux/firmware.h> 24 + 25 + #include "firmware.h" 26 + #include "chip.h" 27 + 28 + MODULE_FIRMWARE("6fire/dmx6firel2.ihx"); 29 + MODULE_FIRMWARE("6fire/dmx6fireap.ihx"); 30 + MODULE_FIRMWARE("6fire/dmx6firecf.bin"); 31 + 32 + enum { 33 + FPGA_BUFSIZE = 512, FPGA_EP = 2 34 + }; 35 + 36 + static const u8 BIT_REVERSE_TABLE[256] = { 37 + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 38 + 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 39 + 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 40 + 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 41 + 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 42 + 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 43 + 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 44 + 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 45 + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 46 + 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 47 + 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 48 + 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 49 + 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 50 + 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 51 + 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 52 + 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 53 + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 54 + 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 55 + 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 56 + 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 57 + 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 58 + 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 59 + 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 60 + 0xbf, 0x7f, 0xff }; 61 + 62 + /* 63 + * wMaxPacketSize of pcm endpoints. 64 + * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c 65 + * fpp: frames per isopacket 66 + * 67 + * CAUTION: keep sizeof <= buffer[] in usb6fire_fw_init 68 + */ 69 + static const u8 ep_w_max_packet_size[] = { 70 + 0xe4, 0x00, 0xe4, 0x00, /* alt 1: 228 EP2 and EP6 (7 fpp) */ 71 + 0xa4, 0x01, 0xa4, 0x01, /* alt 2: 420 EP2 and EP6 (13 fpp)*/ 72 + 0x94, 0x01, 0x5c, 0x02 /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */ 73 + }; 74 + 75 + struct ihex_record { 76 + u16 address; 77 + u8 len; 78 + u8 data[256]; 79 + char error; /* true if an error occured parsing this record */ 80 + 81 + u8 max_len; /* maximum record length in whole ihex */ 82 + 83 + /* private */ 84 + const char *txt_data; 85 + unsigned int txt_length; 86 + unsigned int txt_offset; /* current position in txt_data */ 87 + }; 88 + 89 + static u8 usb6fire_fw_ihex_nibble(const u8 n) 90 + { 91 + if (n >= '0' && n <= '9') 92 + return n - '0'; 93 + else if (n >= 'A' && n <= 'F') 94 + return n - ('A' - 10); 95 + else if (n >= 'a' && n <= 'f') 96 + return n - ('a' - 10); 97 + return 0; 98 + } 99 + 100 + static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc) 101 + { 102 + u8 val = (usb6fire_fw_ihex_nibble(data[0]) << 4) | 103 + usb6fire_fw_ihex_nibble(data[1]); 104 + *crc += val; 105 + return val; 106 + } 107 + 108 + /* 109 + * returns true if record is available, false otherwise. 110 + * iff an error occured, false will be returned and record->error will be true. 111 + */ 112 + static bool usb6fire_fw_ihex_next_record(struct ihex_record *record) 113 + { 114 + u8 crc = 0; 115 + u8 type; 116 + int i; 117 + 118 + record->error = false; 119 + 120 + /* find begin of record (marked by a colon) */ 121 + while (record->txt_offset < record->txt_length 122 + && record->txt_data[record->txt_offset] != ':') 123 + record->txt_offset++; 124 + if (record->txt_offset == record->txt_length) 125 + return false; 126 + 127 + /* number of characters needed for len, addr and type entries */ 128 + record->txt_offset++; 129 + if (record->txt_offset + 8 > record->txt_length) { 130 + record->error = true; 131 + return false; 132 + } 133 + 134 + record->len = usb6fire_fw_ihex_hex(record->txt_data + 135 + record->txt_offset, &crc); 136 + record->txt_offset += 2; 137 + record->address = usb6fire_fw_ihex_hex(record->txt_data + 138 + record->txt_offset, &crc) << 8; 139 + record->txt_offset += 2; 140 + record->address |= usb6fire_fw_ihex_hex(record->txt_data + 141 + record->txt_offset, &crc); 142 + record->txt_offset += 2; 143 + type = usb6fire_fw_ihex_hex(record->txt_data + 144 + record->txt_offset, &crc); 145 + record->txt_offset += 2; 146 + 147 + /* number of characters needed for data and crc entries */ 148 + if (record->txt_offset + 2 * (record->len + 1) > record->txt_length) { 149 + record->error = true; 150 + return false; 151 + } 152 + for (i = 0; i < record->len; i++) { 153 + record->data[i] = usb6fire_fw_ihex_hex(record->txt_data 154 + + record->txt_offset, &crc); 155 + record->txt_offset += 2; 156 + } 157 + usb6fire_fw_ihex_hex(record->txt_data + record->txt_offset, &crc); 158 + if (crc) { 159 + record->error = true; 160 + return false; 161 + } 162 + 163 + if (type == 1 || !record->len) /* eof */ 164 + return false; 165 + else if (type == 0) 166 + return true; 167 + else { 168 + record->error = true; 169 + return false; 170 + } 171 + } 172 + 173 + static int usb6fire_fw_ihex_init(const struct firmware *fw, 174 + struct ihex_record *record) 175 + { 176 + record->txt_data = fw->data; 177 + record->txt_length = fw->size; 178 + record->txt_offset = 0; 179 + record->max_len = 0; 180 + /* read all records, if loop ends, record->error indicates, 181 + * whether ihex is valid. */ 182 + while (usb6fire_fw_ihex_next_record(record)) 183 + record->max_len = max(record->len, record->max_len); 184 + if (record->error) 185 + return -EINVAL; 186 + record->txt_offset = 0; 187 + return 0; 188 + } 189 + 190 + static int usb6fire_fw_ezusb_write(struct usb_device *device, 191 + int type, int value, char *data, int len) 192 + { 193 + int ret; 194 + 195 + ret = usb_control_msg(device, usb_sndctrlpipe(device, 0), type, 196 + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 197 + value, 0, data, len, HZ); 198 + if (ret < 0) 199 + return ret; 200 + else if (ret != len) 201 + return -EIO; 202 + return 0; 203 + } 204 + 205 + static int usb6fire_fw_ezusb_read(struct usb_device *device, 206 + int type, int value, char *data, int len) 207 + { 208 + int ret = usb_control_msg(device, usb_rcvctrlpipe(device, 0), type, 209 + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 210 + 0, data, len, HZ); 211 + if (ret < 0) 212 + return ret; 213 + else if (ret != len) 214 + return -EIO; 215 + return 0; 216 + } 217 + 218 + static int usb6fire_fw_fpga_write(struct usb_device *device, 219 + char *data, int len) 220 + { 221 + int actual_len; 222 + int ret; 223 + 224 + ret = usb_bulk_msg(device, usb_sndbulkpipe(device, FPGA_EP), data, len, 225 + &actual_len, HZ); 226 + if (ret < 0) 227 + return ret; 228 + else if (actual_len != len) 229 + return -EIO; 230 + return 0; 231 + } 232 + 233 + static int usb6fire_fw_ezusb_upload( 234 + struct usb_interface *intf, const char *fwname, 235 + unsigned int postaddr, u8 *postdata, unsigned int postlen) 236 + { 237 + int ret; 238 + u8 data; 239 + struct usb_device *device = interface_to_usbdev(intf); 240 + const struct firmware *fw = 0; 241 + struct ihex_record *rec = kmalloc(sizeof(struct ihex_record), 242 + GFP_KERNEL); 243 + 244 + if (!rec) 245 + return -ENOMEM; 246 + 247 + ret = request_firmware(&fw, fwname, &device->dev); 248 + if (ret < 0) { 249 + kfree(rec); 250 + snd_printk(KERN_ERR PREFIX "error requesting ezusb " 251 + "firmware %s.\n", fwname); 252 + return ret; 253 + } 254 + ret = usb6fire_fw_ihex_init(fw, rec); 255 + if (ret < 0) { 256 + kfree(rec); 257 + snd_printk(KERN_ERR PREFIX "error validating ezusb " 258 + "firmware %s.\n", fwname); 259 + return ret; 260 + } 261 + /* upload firmware image */ 262 + data = 0x01; /* stop ezusb cpu */ 263 + ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1); 264 + if (ret < 0) { 265 + kfree(rec); 266 + release_firmware(fw); 267 + snd_printk(KERN_ERR PREFIX "unable to upload ezusb " 268 + "firmware %s: begin message.\n", fwname); 269 + return ret; 270 + } 271 + 272 + while (usb6fire_fw_ihex_next_record(rec)) { /* write firmware */ 273 + ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address, 274 + rec->data, rec->len); 275 + if (ret < 0) { 276 + kfree(rec); 277 + release_firmware(fw); 278 + snd_printk(KERN_ERR PREFIX "unable to upload ezusb " 279 + "firmware %s: data urb.\n", fwname); 280 + return ret; 281 + } 282 + } 283 + 284 + release_firmware(fw); 285 + kfree(rec); 286 + if (postdata) { /* write data after firmware has been uploaded */ 287 + ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr, 288 + postdata, postlen); 289 + if (ret < 0) { 290 + snd_printk(KERN_ERR PREFIX "unable to upload ezusb " 291 + "firmware %s: post urb.\n", fwname); 292 + return ret; 293 + } 294 + } 295 + 296 + data = 0x00; /* resume ezusb cpu */ 297 + ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1); 298 + if (ret < 0) { 299 + release_firmware(fw); 300 + snd_printk(KERN_ERR PREFIX "unable to upload ezusb " 301 + "firmware %s: end message.\n", fwname); 302 + return ret; 303 + } 304 + return 0; 305 + } 306 + 307 + static int usb6fire_fw_fpga_upload( 308 + struct usb_interface *intf, const char *fwname) 309 + { 310 + int ret; 311 + int i; 312 + struct usb_device *device = interface_to_usbdev(intf); 313 + u8 *buffer = kmalloc(FPGA_BUFSIZE, GFP_KERNEL); 314 + const char *c; 315 + const char *end; 316 + const struct firmware *fw; 317 + 318 + if (!buffer) 319 + return -ENOMEM; 320 + 321 + ret = request_firmware(&fw, fwname, &device->dev); 322 + if (ret < 0) { 323 + snd_printk(KERN_ERR PREFIX "unable to get fpga firmware %s.\n", 324 + fwname); 325 + kfree(buffer); 326 + return -EIO; 327 + } 328 + 329 + c = fw->data; 330 + end = fw->data + fw->size; 331 + 332 + ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0); 333 + if (ret < 0) { 334 + kfree(buffer); 335 + release_firmware(fw); 336 + snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: " 337 + "begin urb.\n"); 338 + return ret; 339 + } 340 + 341 + while (c != end) { 342 + for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++) 343 + buffer[i] = BIT_REVERSE_TABLE[(u8) *c]; 344 + 345 + ret = usb6fire_fw_fpga_write(device, buffer, i); 346 + if (ret < 0) { 347 + release_firmware(fw); 348 + kfree(buffer); 349 + snd_printk(KERN_ERR PREFIX "unable to upload fpga " 350 + "firmware: fw urb.\n"); 351 + return ret; 352 + } 353 + } 354 + release_firmware(fw); 355 + kfree(buffer); 356 + 357 + ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0); 358 + if (ret < 0) { 359 + snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: " 360 + "end urb.\n"); 361 + return ret; 362 + } 363 + return 0; 364 + } 365 + 366 + int usb6fire_fw_init(struct usb_interface *intf) 367 + { 368 + int i; 369 + int ret; 370 + struct usb_device *device = interface_to_usbdev(intf); 371 + /* buffer: 8 receiving bytes from device and 372 + * sizeof(EP_W_MAX_PACKET_SIZE) bytes for non-const copy */ 373 + u8 buffer[12]; 374 + 375 + ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8); 376 + if (ret < 0) { 377 + snd_printk(KERN_ERR PREFIX "unable to receive device " 378 + "firmware state.\n"); 379 + return ret; 380 + } 381 + if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55 382 + || buffer[4] != 0x03 || buffer[5] != 0x01 || buffer[7] 383 + != 0x00) { 384 + snd_printk(KERN_ERR PREFIX "unknown device firmware state " 385 + "received from device: "); 386 + for (i = 0; i < 8; i++) 387 + snd_printk("%02x ", buffer[i]); 388 + snd_printk("\n"); 389 + return -EIO; 390 + } 391 + /* do we need fpga loader ezusb firmware? */ 392 + if (buffer[3] == 0x01 && buffer[6] == 0x19) { 393 + ret = usb6fire_fw_ezusb_upload(intf, 394 + "6fire/dmx6firel2.ihx", 0, NULL, 0); 395 + if (ret < 0) 396 + return ret; 397 + return FW_NOT_READY; 398 + } 399 + /* do we need fpga firmware and application ezusb firmware? */ 400 + else if (buffer[3] == 0x02 && buffer[6] == 0x0b) { 401 + ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin"); 402 + if (ret < 0) 403 + return ret; 404 + memcpy(buffer, ep_w_max_packet_size, 405 + sizeof(ep_w_max_packet_size)); 406 + ret = usb6fire_fw_ezusb_upload(intf, "6fire/dmx6fireap.ihx", 407 + 0x0003, buffer, sizeof(ep_w_max_packet_size)); 408 + if (ret < 0) 409 + return ret; 410 + return FW_NOT_READY; 411 + } 412 + /* all fw loaded? */ 413 + else if (buffer[3] == 0x03 && buffer[6] == 0x0b) 414 + return 0; 415 + /* unknown data? */ 416 + else { 417 + snd_printk(KERN_ERR PREFIX "unknown device firmware state " 418 + "received from device: "); 419 + for (i = 0; i < 8; i++) 420 + snd_printk("%02x ", buffer[i]); 421 + snd_printk("\n"); 422 + return -EIO; 423 + } 424 + return 0; 425 + } 426 +
+27
sound/usb/6fire/firmware.h
··· 1 + /* 2 + * Linux driver for TerraTec DMX 6Fire USB 3 + * 4 + * Author: Torsten Schenk 5 + * Created: Jan 01, 2011 6 + * Copyright: (C) Torsten Schenk 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; either version 2 of the License, or 11 + * (at your option) any later version. 12 + */ 13 + 14 + #ifndef USB6FIRE_FIRMWARE_H 15 + #define USB6FIRE_FIRMWARE_H 16 + 17 + #include "common.h" 18 + 19 + enum /* firmware state of device */ 20 + { 21 + FW_READY = 0, 22 + FW_NOT_READY = 1 23 + }; 24 + 25 + int __devinit usb6fire_fw_init(struct usb_interface *intf); 26 + #endif /* USB6FIRE_FIRMWARE_H */ 27 +
+203
sound/usb/6fire/midi.c
··· 1 + /* 2 + * Linux driver for TerraTec DMX 6Fire USB 3 + * 4 + * Rawmidi driver 5 + * 6 + * Author: Torsten Schenk <torsten.schenk@zoho.com> 7 + * Created: Jan 01, 2011 8 + * Version: 0.3.0 9 + * Copyright: (C) Torsten Schenk 10 + * 11 + * This program is free software; you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License as published by 13 + * the Free Software Foundation; either version 2 of the License, or 14 + * (at your option) any later version. 15 + */ 16 + 17 + #include <sound/rawmidi.h> 18 + 19 + #include "midi.h" 20 + #include "chip.h" 21 + #include "comm.h" 22 + 23 + static void usb6fire_midi_out_handler(struct urb *urb) 24 + { 25 + struct midi_runtime *rt = urb->context; 26 + int ret; 27 + unsigned long flags; 28 + 29 + spin_lock_irqsave(&rt->out_lock, flags); 30 + 31 + if (rt->out) { 32 + ret = snd_rawmidi_transmit(rt->out, rt->out_buffer + 4, 33 + MIDI_BUFSIZE - 4); 34 + if (ret > 0) { /* more data available, send next packet */ 35 + rt->out_buffer[1] = ret + 2; 36 + rt->out_buffer[3] = rt->out_serial++; 37 + urb->transfer_buffer_length = ret + 4; 38 + 39 + ret = usb_submit_urb(urb, GFP_ATOMIC); 40 + if (ret < 0) 41 + snd_printk(KERN_ERR PREFIX "midi out urb " 42 + "submit failed: %d\n", ret); 43 + } else /* no more data to transmit */ 44 + rt->out = NULL; 45 + } 46 + spin_unlock_irqrestore(&rt->out_lock, flags); 47 + } 48 + 49 + static void usb6fire_midi_in_received( 50 + struct midi_runtime *rt, u8 *data, int length) 51 + { 52 + unsigned long flags; 53 + 54 + spin_lock_irqsave(&rt->in_lock, flags); 55 + if (rt->in) 56 + snd_rawmidi_receive(rt->in, data, length); 57 + spin_unlock_irqrestore(&rt->in_lock, flags); 58 + } 59 + 60 + static int usb6fire_midi_out_open(struct snd_rawmidi_substream *alsa_sub) 61 + { 62 + return 0; 63 + } 64 + 65 + static int usb6fire_midi_out_close(struct snd_rawmidi_substream *alsa_sub) 66 + { 67 + return 0; 68 + } 69 + 70 + static void usb6fire_midi_out_trigger( 71 + struct snd_rawmidi_substream *alsa_sub, int up) 72 + { 73 + struct midi_runtime *rt = alsa_sub->rmidi->private_data; 74 + struct urb *urb = &rt->out_urb; 75 + __s8 ret; 76 + unsigned long flags; 77 + 78 + spin_lock_irqsave(&rt->out_lock, flags); 79 + if (up) { /* start transfer */ 80 + if (rt->out) { /* we are already transmitting so just return */ 81 + spin_unlock_irqrestore(&rt->out_lock, flags); 82 + return; 83 + } 84 + 85 + ret = snd_rawmidi_transmit(alsa_sub, rt->out_buffer + 4, 86 + MIDI_BUFSIZE - 4); 87 + if (ret > 0) { 88 + rt->out_buffer[1] = ret + 2; 89 + rt->out_buffer[3] = rt->out_serial++; 90 + urb->transfer_buffer_length = ret + 4; 91 + 92 + ret = usb_submit_urb(urb, GFP_ATOMIC); 93 + if (ret < 0) 94 + snd_printk(KERN_ERR PREFIX "midi out urb " 95 + "submit failed: %d\n", ret); 96 + else 97 + rt->out = alsa_sub; 98 + } 99 + } else if (rt->out == alsa_sub) 100 + rt->out = NULL; 101 + spin_unlock_irqrestore(&rt->out_lock, flags); 102 + } 103 + 104 + static void usb6fire_midi_out_drain(struct snd_rawmidi_substream *alsa_sub) 105 + { 106 + struct midi_runtime *rt = alsa_sub->rmidi->private_data; 107 + int retry = 0; 108 + 109 + while (rt->out && retry++ < 100) 110 + msleep(10); 111 + } 112 + 113 + static int usb6fire_midi_in_open(struct snd_rawmidi_substream *alsa_sub) 114 + { 115 + return 0; 116 + } 117 + 118 + static int usb6fire_midi_in_close(struct snd_rawmidi_substream *alsa_sub) 119 + { 120 + return 0; 121 + } 122 + 123 + static void usb6fire_midi_in_trigger( 124 + struct snd_rawmidi_substream *alsa_sub, int up) 125 + { 126 + struct midi_runtime *rt = alsa_sub->rmidi->private_data; 127 + unsigned long flags; 128 + 129 + spin_lock_irqsave(&rt->in_lock, flags); 130 + if (up) 131 + rt->in = alsa_sub; 132 + else 133 + rt->in = NULL; 134 + spin_unlock_irqrestore(&rt->in_lock, flags); 135 + } 136 + 137 + static struct snd_rawmidi_ops out_ops = { 138 + .open = usb6fire_midi_out_open, 139 + .close = usb6fire_midi_out_close, 140 + .trigger = usb6fire_midi_out_trigger, 141 + .drain = usb6fire_midi_out_drain 142 + }; 143 + 144 + static struct snd_rawmidi_ops in_ops = { 145 + .open = usb6fire_midi_in_open, 146 + .close = usb6fire_midi_in_close, 147 + .trigger = usb6fire_midi_in_trigger 148 + }; 149 + 150 + int __devinit usb6fire_midi_init(struct sfire_chip *chip) 151 + { 152 + int ret; 153 + struct midi_runtime *rt = kzalloc(sizeof(struct midi_runtime), 154 + GFP_KERNEL); 155 + struct comm_runtime *comm_rt = chip->comm; 156 + 157 + if (!rt) 158 + return -ENOMEM; 159 + 160 + rt->chip = chip; 161 + rt->in_received = usb6fire_midi_in_received; 162 + rt->out_buffer[0] = 0x80; /* 'send midi' command */ 163 + rt->out_buffer[1] = 0x00; /* size of data */ 164 + rt->out_buffer[2] = 0x00; /* always 0 */ 165 + spin_lock_init(&rt->in_lock); 166 + spin_lock_init(&rt->out_lock); 167 + 168 + comm_rt->init_urb(comm_rt, &rt->out_urb, rt->out_buffer, rt, 169 + usb6fire_midi_out_handler); 170 + 171 + ret = snd_rawmidi_new(chip->card, "6FireUSB", 0, 1, 1, &rt->instance); 172 + if (ret < 0) { 173 + kfree(rt); 174 + snd_printk(KERN_ERR PREFIX "unable to create midi.\n"); 175 + return ret; 176 + } 177 + rt->instance->private_data = rt; 178 + strcpy(rt->instance->name, "DMX6FireUSB MIDI"); 179 + rt->instance->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | 180 + SNDRV_RAWMIDI_INFO_INPUT | 181 + SNDRV_RAWMIDI_INFO_DUPLEX; 182 + snd_rawmidi_set_ops(rt->instance, SNDRV_RAWMIDI_STREAM_OUTPUT, 183 + &out_ops); 184 + snd_rawmidi_set_ops(rt->instance, SNDRV_RAWMIDI_STREAM_INPUT, 185 + &in_ops); 186 + 187 + chip->midi = rt; 188 + return 0; 189 + } 190 + 191 + void usb6fire_midi_abort(struct sfire_chip *chip) 192 + { 193 + struct midi_runtime *rt = chip->midi; 194 + 195 + if (rt) 196 + usb_poison_urb(&rt->out_urb); 197 + } 198 + 199 + void usb6fire_midi_destroy(struct sfire_chip *chip) 200 + { 201 + kfree(chip->midi); 202 + chip->midi = NULL; 203 + }
+46
sound/usb/6fire/midi.h
··· 1 + /* 2 + * Linux driver for TerraTec DMX 6Fire USB 3 + * 4 + * Author: Torsten Schenk <torsten.schenk@zoho.com> 5 + * Created: Jan 01, 2011 6 + * Version: 0.3.0 7 + * Copyright: (C) Torsten Schenk 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2 of the License, or 12 + * (at your option) any later version. 13 + */ 14 + 15 + #ifndef USB6FIRE_MIDI_H 16 + #define USB6FIRE_MIDI_H 17 + 18 + #include "common.h" 19 + 20 + enum { 21 + MIDI_BUFSIZE = 64 22 + }; 23 + 24 + struct midi_runtime { 25 + struct sfire_chip *chip; 26 + struct snd_rawmidi *instance; 27 + 28 + struct snd_rawmidi_substream *in; 29 + char in_active; 30 + 31 + spinlock_t in_lock; 32 + spinlock_t out_lock; 33 + struct snd_rawmidi_substream *out; 34 + struct urb out_urb; 35 + u8 out_serial; /* serial number of out packet */ 36 + u8 out_buffer[MIDI_BUFSIZE]; 37 + int buffer_offset; 38 + 39 + void (*in_received)(struct midi_runtime *rt, u8 *data, int length); 40 + }; 41 + 42 + int __devinit usb6fire_midi_init(struct sfire_chip *chip); 43 + void usb6fire_midi_abort(struct sfire_chip *chip); 44 + void usb6fire_midi_destroy(struct sfire_chip *chip); 45 + #endif /* USB6FIRE_MIDI_H */ 46 +
+689
sound/usb/6fire/pcm.c
··· 1 + /* 2 + * Linux driver for TerraTec DMX 6Fire USB 3 + * 4 + * PCM driver 5 + * 6 + * Author: Torsten Schenk <torsten.schenk@zoho.com> 7 + * Created: Jan 01, 2011 8 + * Version: 0.3.0 9 + * Copyright: (C) Torsten Schenk 10 + * 11 + * This program is free software; you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License as published by 13 + * the Free Software Foundation; either version 2 of the License, or 14 + * (at your option) any later version. 15 + */ 16 + 17 + #include "pcm.h" 18 + #include "chip.h" 19 + #include "comm.h" 20 + 21 + enum { 22 + OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4 23 + }; 24 + 25 + /* keep next two synced with 26 + * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */ 27 + static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 }; 28 + static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 }; 29 + static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; 30 + static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; 31 + static const int rates_alsaid[] = { 32 + SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000, 33 + SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000, 34 + SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 }; 35 + 36 + /* values to write to soundcard register for all samplerates */ 37 + static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; 38 + static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; 39 + 40 + enum { /* settings for pcm */ 41 + OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024 42 + }; 43 + 44 + enum { /* pcm streaming states */ 45 + STREAM_DISABLED, /* no pcm streaming */ 46 + STREAM_STARTING, /* pcm streaming requested, waiting to become ready */ 47 + STREAM_RUNNING, /* pcm streaming running */ 48 + STREAM_STOPPING 49 + }; 50 + 51 + enum { /* pcm sample rates (also index into RATES_XXX[]) */ 52 + RATE_44KHZ, 53 + RATE_48KHZ, 54 + RATE_88KHZ, 55 + RATE_96KHZ, 56 + RATE_176KHZ, 57 + RATE_192KHZ 58 + }; 59 + 60 + static const struct snd_pcm_hardware pcm_hw = { 61 + .info = SNDRV_PCM_INFO_MMAP | 62 + SNDRV_PCM_INFO_INTERLEAVED | 63 + SNDRV_PCM_INFO_BLOCK_TRANSFER | 64 + SNDRV_PCM_INFO_MMAP_VALID | 65 + SNDRV_PCM_INFO_BATCH, 66 + 67 + .formats = SNDRV_PCM_FMTBIT_S24_LE, 68 + 69 + .rates = SNDRV_PCM_RATE_44100 | 70 + SNDRV_PCM_RATE_48000 | 71 + SNDRV_PCM_RATE_88200 | 72 + SNDRV_PCM_RATE_96000 | 73 + SNDRV_PCM_RATE_176400 | 74 + SNDRV_PCM_RATE_192000, 75 + 76 + .rate_min = 44100, 77 + .rate_max = 192000, 78 + .channels_min = 1, 79 + .channels_max = 0, /* set in pcm_open, depending on capture/playback */ 80 + .buffer_bytes_max = MAX_BUFSIZE, 81 + .period_bytes_min = PCM_N_PACKETS_PER_URB * (PCM_MAX_PACKET_SIZE - 4), 82 + .period_bytes_max = MAX_BUFSIZE, 83 + .periods_min = 2, 84 + .periods_max = 1024 85 + }; 86 + 87 + static int usb6fire_pcm_set_rate(struct pcm_runtime *rt) 88 + { 89 + int ret; 90 + struct usb_device *device = rt->chip->dev; 91 + struct comm_runtime *comm_rt = rt->chip->comm; 92 + 93 + if (rt->rate >= ARRAY_SIZE(rates)) 94 + return -EINVAL; 95 + /* disable streaming */ 96 + ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00); 97 + if (ret < 0) { 98 + snd_printk(KERN_ERR PREFIX "error stopping streaming while " 99 + "setting samplerate %d.\n", rates[rt->rate]); 100 + return ret; 101 + } 102 + 103 + ret = usb_set_interface(device, 1, rates_altsetting[rt->rate]); 104 + if (ret < 0) { 105 + snd_printk(KERN_ERR PREFIX "error setting interface " 106 + "altsetting %d for samplerate %d.\n", 107 + rates_altsetting[rt->rate], rates[rt->rate]); 108 + return ret; 109 + } 110 + 111 + /* set soundcard clock */ 112 + ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rt->rate], 113 + rates_6fire_vh[rt->rate]); 114 + if (ret < 0) { 115 + snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n", 116 + rates[rt->rate]); 117 + return ret; 118 + } 119 + 120 + /* enable analog inputs and outputs 121 + * (one bit per stereo-channel) */ 122 + ret = comm_rt->write16(comm_rt, 0x02, 0x02, 123 + (1 << (OUT_N_CHANNELS / 2)) - 1, 124 + (1 << (IN_N_CHANNELS / 2)) - 1); 125 + if (ret < 0) { 126 + snd_printk(KERN_ERR PREFIX "error initializing analog channels " 127 + "while setting samplerate %d.\n", 128 + rates[rt->rate]); 129 + return ret; 130 + } 131 + /* disable digital inputs and outputs */ 132 + ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00); 133 + if (ret < 0) { 134 + snd_printk(KERN_ERR PREFIX "error initializing digital " 135 + "channels while setting samplerate %d.\n", 136 + rates[rt->rate]); 137 + return ret; 138 + } 139 + 140 + ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x01); 141 + if (ret < 0) { 142 + snd_printk(KERN_ERR PREFIX "error starting streaming while " 143 + "setting samplerate %d.\n", rates[rt->rate]); 144 + return ret; 145 + } 146 + 147 + rt->in_n_analog = IN_N_CHANNELS; 148 + rt->out_n_analog = OUT_N_CHANNELS; 149 + rt->in_packet_size = rates_in_packet_size[rt->rate]; 150 + rt->out_packet_size = rates_out_packet_size[rt->rate]; 151 + return 0; 152 + } 153 + 154 + static struct pcm_substream *usb6fire_pcm_get_substream( 155 + struct snd_pcm_substream *alsa_sub) 156 + { 157 + struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); 158 + 159 + if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) 160 + return &rt->playback; 161 + else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE) 162 + return &rt->capture; 163 + snd_printk(KERN_ERR PREFIX "error getting pcm substream slot.\n"); 164 + return NULL; 165 + } 166 + 167 + /* call with stream_mutex locked */ 168 + static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt) 169 + { 170 + int i; 171 + 172 + if (rt->stream_state != STREAM_DISABLED) { 173 + for (i = 0; i < PCM_N_URBS; i++) { 174 + usb_kill_urb(&rt->in_urbs[i].instance); 175 + usb_kill_urb(&rt->out_urbs[i].instance); 176 + } 177 + rt->stream_state = STREAM_DISABLED; 178 + } 179 + } 180 + 181 + /* call with stream_mutex locked */ 182 + static int usb6fire_pcm_stream_start(struct pcm_runtime *rt) 183 + { 184 + int ret; 185 + int i; 186 + int k; 187 + struct usb_iso_packet_descriptor *packet; 188 + 189 + if (rt->stream_state == STREAM_DISABLED) { 190 + /* submit our in urbs */ 191 + rt->stream_wait_cond = false; 192 + rt->stream_state = STREAM_STARTING; 193 + for (i = 0; i < PCM_N_URBS; i++) { 194 + for (k = 0; k < PCM_N_PACKETS_PER_URB; k++) { 195 + packet = &rt->in_urbs[i].packets[k]; 196 + packet->offset = k * rt->in_packet_size; 197 + packet->length = rt->in_packet_size; 198 + packet->actual_length = 0; 199 + packet->status = 0; 200 + } 201 + ret = usb_submit_urb(&rt->in_urbs[i].instance, 202 + GFP_ATOMIC); 203 + if (ret) { 204 + usb6fire_pcm_stream_stop(rt); 205 + return ret; 206 + } 207 + } 208 + 209 + /* wait for first out urb to return (sent in in urb handler) */ 210 + wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond, 211 + HZ); 212 + if (rt->stream_wait_cond) 213 + rt->stream_state = STREAM_RUNNING; 214 + else { 215 + usb6fire_pcm_stream_stop(rt); 216 + return -EIO; 217 + } 218 + } 219 + return 0; 220 + } 221 + 222 + /* call with substream locked */ 223 + static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) 224 + { 225 + int i; 226 + int frame; 227 + int frame_count; 228 + unsigned int total_length = 0; 229 + struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); 230 + struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; 231 + u32 *src = (u32 *) urb->buffer; 232 + u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off 233 + * (alsa_rt->frame_bits >> 3)); 234 + u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size 235 + * (alsa_rt->frame_bits >> 3)); 236 + int bytes_per_frame = alsa_rt->channels << 2; 237 + 238 + for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { 239 + /* at least 4 header bytes for valid packet. 240 + * after that: 32 bits per sample for analog channels */ 241 + if (urb->packets[i].actual_length > 4) 242 + frame_count = (urb->packets[i].actual_length - 4) 243 + / (rt->in_n_analog << 2); 244 + else 245 + frame_count = 0; 246 + 247 + src = (u32 *) (urb->buffer + total_length); 248 + src++; /* skip leading 4 bytes of every packet */ 249 + total_length += urb->packets[i].length; 250 + for (frame = 0; frame < frame_count; frame++) { 251 + memcpy(dest, src, bytes_per_frame); 252 + dest += alsa_rt->channels; 253 + src += rt->in_n_analog; 254 + sub->dma_off++; 255 + sub->period_off++; 256 + if (dest == dest_end) { 257 + sub->dma_off = 0; 258 + dest = (u32 *) alsa_rt->dma_area; 259 + } 260 + } 261 + } 262 + } 263 + 264 + /* call with substream locked */ 265 + static void usb6fire_pcm_playback(struct pcm_substream *sub, 266 + struct pcm_urb *urb) 267 + { 268 + int i; 269 + int frame; 270 + int frame_count; 271 + struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); 272 + struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; 273 + u32 *src = (u32 *) (alsa_rt->dma_area + sub->dma_off 274 + * (alsa_rt->frame_bits >> 3)); 275 + u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size 276 + * (alsa_rt->frame_bits >> 3)); 277 + u32 *dest = (u32 *) urb->buffer; 278 + int bytes_per_frame = alsa_rt->channels << 2; 279 + 280 + for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { 281 + /* at least 4 header bytes for valid packet. 282 + * after that: 32 bits per sample for analog channels */ 283 + if (urb->packets[i].length > 4) 284 + frame_count = (urb->packets[i].length - 4) 285 + / (rt->out_n_analog << 2); 286 + else 287 + frame_count = 0; 288 + dest++; /* skip leading 4 bytes of every frame */ 289 + for (frame = 0; frame < frame_count; frame++) { 290 + memcpy(dest, src, bytes_per_frame); 291 + src += alsa_rt->channels; 292 + dest += rt->out_n_analog; 293 + sub->dma_off++; 294 + sub->period_off++; 295 + if (src == src_end) { 296 + src = (u32 *) alsa_rt->dma_area; 297 + sub->dma_off = 0; 298 + } 299 + } 300 + } 301 + } 302 + 303 + static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb) 304 + { 305 + struct pcm_urb *in_urb = usb_urb->context; 306 + struct pcm_urb *out_urb = in_urb->peer; 307 + struct pcm_runtime *rt = in_urb->chip->pcm; 308 + struct pcm_substream *sub; 309 + unsigned long flags; 310 + int total_length = 0; 311 + int frame_count; 312 + int frame; 313 + int channel; 314 + int i; 315 + u8 *dest; 316 + 317 + if (usb_urb->status || rt->panic || rt->stream_state == STREAM_STOPPING) 318 + return; 319 + for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) 320 + if (in_urb->packets[i].status) { 321 + rt->panic = true; 322 + return; 323 + } 324 + 325 + if (rt->stream_state == STREAM_DISABLED) { 326 + snd_printk(KERN_ERR PREFIX "internal error: " 327 + "stream disabled in in-urb handler.\n"); 328 + return; 329 + } 330 + 331 + /* receive our capture data */ 332 + sub = &rt->capture; 333 + spin_lock_irqsave(&sub->lock, flags); 334 + if (sub->active) { 335 + usb6fire_pcm_capture(sub, in_urb); 336 + if (sub->period_off >= sub->instance->runtime->period_size) { 337 + sub->period_off %= sub->instance->runtime->period_size; 338 + spin_unlock_irqrestore(&sub->lock, flags); 339 + snd_pcm_period_elapsed(sub->instance); 340 + } else 341 + spin_unlock_irqrestore(&sub->lock, flags); 342 + } else 343 + spin_unlock_irqrestore(&sub->lock, flags); 344 + 345 + /* setup out urb structure */ 346 + for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { 347 + out_urb->packets[i].offset = total_length; 348 + out_urb->packets[i].length = (in_urb->packets[i].actual_length 349 + - 4) / (rt->in_n_analog << 2) 350 + * (rt->out_n_analog << 2) + 4; 351 + out_urb->packets[i].status = 0; 352 + total_length += out_urb->packets[i].length; 353 + } 354 + memset(out_urb->buffer, 0, total_length); 355 + 356 + /* now send our playback data (if a free out urb was found) */ 357 + sub = &rt->playback; 358 + spin_lock_irqsave(&sub->lock, flags); 359 + if (sub->active) { 360 + usb6fire_pcm_playback(sub, out_urb); 361 + if (sub->period_off >= sub->instance->runtime->period_size) { 362 + sub->period_off %= sub->instance->runtime->period_size; 363 + spin_unlock_irqrestore(&sub->lock, flags); 364 + snd_pcm_period_elapsed(sub->instance); 365 + } else 366 + spin_unlock_irqrestore(&sub->lock, flags); 367 + } else 368 + spin_unlock_irqrestore(&sub->lock, flags); 369 + 370 + /* setup the 4th byte of each sample (0x40 for analog channels) */ 371 + dest = out_urb->buffer; 372 + for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) 373 + if (out_urb->packets[i].length >= 4) { 374 + frame_count = (out_urb->packets[i].length - 4) 375 + / (rt->out_n_analog << 2); 376 + *(dest++) = 0xaa; 377 + *(dest++) = 0xaa; 378 + *(dest++) = frame_count; 379 + *(dest++) = 0x00; 380 + for (frame = 0; frame < frame_count; frame++) 381 + for (channel = 0; 382 + channel < rt->out_n_analog; 383 + channel++) { 384 + dest += 3; /* skip sample data */ 385 + *(dest++) = 0x40; 386 + } 387 + } 388 + usb_submit_urb(&out_urb->instance, GFP_ATOMIC); 389 + usb_submit_urb(&in_urb->instance, GFP_ATOMIC); 390 + } 391 + 392 + static void usb6fire_pcm_out_urb_handler(struct urb *usb_urb) 393 + { 394 + struct pcm_urb *urb = usb_urb->context; 395 + struct pcm_runtime *rt = urb->chip->pcm; 396 + 397 + if (rt->stream_state == STREAM_STARTING) { 398 + rt->stream_wait_cond = true; 399 + wake_up(&rt->stream_wait_queue); 400 + } 401 + } 402 + 403 + static int usb6fire_pcm_open(struct snd_pcm_substream *alsa_sub) 404 + { 405 + struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); 406 + struct pcm_substream *sub = NULL; 407 + struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; 408 + 409 + if (rt->panic) 410 + return -EPIPE; 411 + 412 + mutex_lock(&rt->stream_mutex); 413 + alsa_rt->hw = pcm_hw; 414 + 415 + if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) { 416 + if (rt->rate >= 0) 417 + alsa_rt->hw.rates = rates_alsaid[rt->rate]; 418 + alsa_rt->hw.channels_max = OUT_N_CHANNELS; 419 + sub = &rt->playback; 420 + } else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE) { 421 + if (rt->rate >= 0) 422 + alsa_rt->hw.rates = rates_alsaid[rt->rate]; 423 + alsa_rt->hw.channels_max = IN_N_CHANNELS; 424 + sub = &rt->capture; 425 + } 426 + 427 + if (!sub) { 428 + mutex_unlock(&rt->stream_mutex); 429 + snd_printk(KERN_ERR PREFIX "invalid stream type.\n"); 430 + return -EINVAL; 431 + } 432 + 433 + sub->instance = alsa_sub; 434 + sub->active = false; 435 + mutex_unlock(&rt->stream_mutex); 436 + return 0; 437 + } 438 + 439 + static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub) 440 + { 441 + struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); 442 + struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); 443 + unsigned long flags; 444 + 445 + if (rt->panic) 446 + return 0; 447 + 448 + mutex_lock(&rt->stream_mutex); 449 + if (sub) { 450 + /* deactivate substream */ 451 + spin_lock_irqsave(&sub->lock, flags); 452 + sub->instance = NULL; 453 + sub->active = false; 454 + spin_unlock_irqrestore(&sub->lock, flags); 455 + 456 + /* all substreams closed? if so, stop streaming */ 457 + if (!rt->playback.instance && !rt->capture.instance) { 458 + usb6fire_pcm_stream_stop(rt); 459 + rt->rate = -1; 460 + } 461 + } 462 + mutex_unlock(&rt->stream_mutex); 463 + return 0; 464 + } 465 + 466 + static int usb6fire_pcm_hw_params(struct snd_pcm_substream *alsa_sub, 467 + struct snd_pcm_hw_params *hw_params) 468 + { 469 + return snd_pcm_lib_malloc_pages(alsa_sub, 470 + params_buffer_bytes(hw_params)); 471 + } 472 + 473 + static int usb6fire_pcm_hw_free(struct snd_pcm_substream *alsa_sub) 474 + { 475 + return snd_pcm_lib_free_pages(alsa_sub); 476 + } 477 + 478 + static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) 479 + { 480 + struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); 481 + struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); 482 + struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; 483 + int i; 484 + int ret; 485 + 486 + if (rt->panic) 487 + return -EPIPE; 488 + if (!sub) 489 + return -ENODEV; 490 + 491 + mutex_lock(&rt->stream_mutex); 492 + sub->dma_off = 0; 493 + sub->period_off = 0; 494 + 495 + if (rt->stream_state == STREAM_DISABLED) { 496 + rt->rate = -1; 497 + for (i = 0; i < ARRAY_SIZE(rates); i++) 498 + if (alsa_rt->rate == rates[i]) { 499 + rt->rate = i; 500 + break; 501 + } 502 + if (rt->rate == -1) { 503 + mutex_unlock(&rt->stream_mutex); 504 + snd_printk("invalid rate %d in prepare.\n", 505 + alsa_rt->rate); 506 + return -EINVAL; 507 + } 508 + 509 + ret = usb6fire_pcm_set_rate(rt); 510 + if (ret) { 511 + mutex_unlock(&rt->stream_mutex); 512 + return ret; 513 + } 514 + ret = usb6fire_pcm_stream_start(rt); 515 + if (ret) { 516 + mutex_unlock(&rt->stream_mutex); 517 + snd_printk(KERN_ERR PREFIX 518 + "could not start pcm stream.\n"); 519 + return ret; 520 + } 521 + } 522 + mutex_unlock(&rt->stream_mutex); 523 + return 0; 524 + } 525 + 526 + static int usb6fire_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd) 527 + { 528 + struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); 529 + struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); 530 + unsigned long flags; 531 + 532 + if (rt->panic) 533 + return -EPIPE; 534 + if (!sub) 535 + return -ENODEV; 536 + 537 + switch (cmd) { 538 + case SNDRV_PCM_TRIGGER_START: 539 + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 540 + spin_lock_irqsave(&sub->lock, flags); 541 + sub->active = true; 542 + spin_unlock_irqrestore(&sub->lock, flags); 543 + return 0; 544 + 545 + case SNDRV_PCM_TRIGGER_STOP: 546 + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 547 + spin_lock_irqsave(&sub->lock, flags); 548 + sub->active = false; 549 + spin_unlock_irqrestore(&sub->lock, flags); 550 + return 0; 551 + 552 + default: 553 + return -EINVAL; 554 + } 555 + } 556 + 557 + static snd_pcm_uframes_t usb6fire_pcm_pointer( 558 + struct snd_pcm_substream *alsa_sub) 559 + { 560 + struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); 561 + struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); 562 + unsigned long flags; 563 + snd_pcm_uframes_t ret; 564 + 565 + if (rt->panic || !sub) 566 + return SNDRV_PCM_STATE_XRUN; 567 + 568 + spin_lock_irqsave(&sub->lock, flags); 569 + ret = sub->dma_off; 570 + spin_unlock_irqrestore(&sub->lock, flags); 571 + return ret; 572 + } 573 + 574 + static struct snd_pcm_ops pcm_ops = { 575 + .open = usb6fire_pcm_open, 576 + .close = usb6fire_pcm_close, 577 + .ioctl = snd_pcm_lib_ioctl, 578 + .hw_params = usb6fire_pcm_hw_params, 579 + .hw_free = usb6fire_pcm_hw_free, 580 + .prepare = usb6fire_pcm_prepare, 581 + .trigger = usb6fire_pcm_trigger, 582 + .pointer = usb6fire_pcm_pointer, 583 + }; 584 + 585 + static void __devinit usb6fire_pcm_init_urb(struct pcm_urb *urb, 586 + struct sfire_chip *chip, bool in, int ep, 587 + void (*handler)(struct urb *)) 588 + { 589 + urb->chip = chip; 590 + usb_init_urb(&urb->instance); 591 + urb->instance.transfer_buffer = urb->buffer; 592 + urb->instance.transfer_buffer_length = 593 + PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE; 594 + urb->instance.dev = chip->dev; 595 + urb->instance.pipe = in ? usb_rcvisocpipe(chip->dev, ep) 596 + : usb_sndisocpipe(chip->dev, ep); 597 + urb->instance.interval = 1; 598 + urb->instance.transfer_flags = URB_ISO_ASAP; 599 + urb->instance.complete = handler; 600 + urb->instance.context = urb; 601 + urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB; 602 + } 603 + 604 + int __devinit usb6fire_pcm_init(struct sfire_chip *chip) 605 + { 606 + int i; 607 + int ret; 608 + struct snd_pcm *pcm; 609 + struct pcm_runtime *rt = 610 + kzalloc(sizeof(struct pcm_runtime), GFP_KERNEL); 611 + 612 + if (!rt) 613 + return -ENOMEM; 614 + 615 + rt->chip = chip; 616 + rt->stream_state = STREAM_DISABLED; 617 + rt->rate = -1; 618 + init_waitqueue_head(&rt->stream_wait_queue); 619 + mutex_init(&rt->stream_mutex); 620 + 621 + spin_lock_init(&rt->playback.lock); 622 + spin_lock_init(&rt->capture.lock); 623 + 624 + for (i = 0; i < PCM_N_URBS; i++) { 625 + usb6fire_pcm_init_urb(&rt->in_urbs[i], chip, true, IN_EP, 626 + usb6fire_pcm_in_urb_handler); 627 + usb6fire_pcm_init_urb(&rt->out_urbs[i], chip, false, OUT_EP, 628 + usb6fire_pcm_out_urb_handler); 629 + 630 + rt->in_urbs[i].peer = &rt->out_urbs[i]; 631 + rt->out_urbs[i].peer = &rt->in_urbs[i]; 632 + } 633 + 634 + ret = snd_pcm_new(chip->card, "DMX6FireUSB", 0, 1, 1, &pcm); 635 + if (ret < 0) { 636 + kfree(rt); 637 + snd_printk(KERN_ERR PREFIX "cannot create pcm instance.\n"); 638 + return ret; 639 + } 640 + 641 + pcm->private_data = rt; 642 + strcpy(pcm->name, "DMX 6Fire USB"); 643 + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops); 644 + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops); 645 + 646 + ret = snd_pcm_lib_preallocate_pages_for_all(pcm, 647 + SNDRV_DMA_TYPE_CONTINUOUS, 648 + snd_dma_continuous_data(GFP_KERNEL), 649 + MAX_BUFSIZE, MAX_BUFSIZE); 650 + if (ret) { 651 + kfree(rt); 652 + snd_printk(KERN_ERR PREFIX 653 + "error preallocating pcm buffers.\n"); 654 + return ret; 655 + } 656 + rt->instance = pcm; 657 + 658 + chip->pcm = rt; 659 + return 0; 660 + } 661 + 662 + void usb6fire_pcm_abort(struct sfire_chip *chip) 663 + { 664 + struct pcm_runtime *rt = chip->pcm; 665 + int i; 666 + 667 + if (rt) { 668 + rt->panic = true; 669 + 670 + if (rt->playback.instance) 671 + snd_pcm_stop(rt->playback.instance, 672 + SNDRV_PCM_STATE_XRUN); 673 + if (rt->capture.instance) 674 + snd_pcm_stop(rt->capture.instance, 675 + SNDRV_PCM_STATE_XRUN); 676 + 677 + for (i = 0; i < PCM_N_URBS; i++) { 678 + usb_poison_urb(&rt->in_urbs[i].instance); 679 + usb_poison_urb(&rt->out_urbs[i].instance); 680 + } 681 + 682 + } 683 + } 684 + 685 + void usb6fire_pcm_destroy(struct sfire_chip *chip) 686 + { 687 + kfree(chip->pcm); 688 + chip->pcm = NULL; 689 + }
+76
sound/usb/6fire/pcm.h
··· 1 + /* 2 + * Linux driver for TerraTec DMX 6Fire USB 3 + * 4 + * Author: Torsten Schenk <torsten.schenk@zoho.com> 5 + * Created: Jan 01, 2011 6 + * Version: 0.3.0 7 + * Copyright: (C) Torsten Schenk 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2 of the License, or 12 + * (at your option) any later version. 13 + */ 14 + 15 + #ifndef USB6FIRE_PCM_H 16 + #define USB6FIRE_PCM_H 17 + 18 + #include <sound/pcm.h> 19 + #include <linux/mutex.h> 20 + 21 + #include "common.h" 22 + 23 + enum /* settings for pcm */ 24 + { 25 + /* maximum of EP_W_MAX_PACKET_SIZE[] (see firmware.c) */ 26 + PCM_N_URBS = 16, PCM_N_PACKETS_PER_URB = 8, PCM_MAX_PACKET_SIZE = 604 27 + }; 28 + 29 + struct pcm_urb { 30 + struct sfire_chip *chip; 31 + 32 + /* BEGIN DO NOT SEPARATE */ 33 + struct urb instance; 34 + struct usb_iso_packet_descriptor packets[PCM_N_PACKETS_PER_URB]; 35 + /* END DO NOT SEPARATE */ 36 + u8 buffer[PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE]; 37 + 38 + struct pcm_urb *peer; 39 + }; 40 + 41 + struct pcm_substream { 42 + spinlock_t lock; 43 + struct snd_pcm_substream *instance; 44 + 45 + bool active; 46 + 47 + snd_pcm_uframes_t dma_off; /* current position in alsa dma_area */ 48 + snd_pcm_uframes_t period_off; /* current position in current period */ 49 + }; 50 + 51 + struct pcm_runtime { 52 + struct sfire_chip *chip; 53 + struct snd_pcm *instance; 54 + 55 + struct pcm_substream playback; 56 + struct pcm_substream capture; 57 + bool panic; /* if set driver won't do anymore pcm on device */ 58 + 59 + struct pcm_urb in_urbs[PCM_N_URBS]; 60 + struct pcm_urb out_urbs[PCM_N_URBS]; 61 + int in_packet_size; 62 + int out_packet_size; 63 + int in_n_analog; /* number of analog channels soundcard sends */ 64 + int out_n_analog; /* number of analog channels soundcard receives */ 65 + 66 + struct mutex stream_mutex; 67 + u8 stream_state; /* one of STREAM_XXX (pcm.c) */ 68 + u8 rate; /* one of PCM_RATE_XXX */ 69 + wait_queue_head_t stream_wait_queue; 70 + bool stream_wait_cond; 71 + }; 72 + 73 + int __devinit usb6fire_pcm_init(struct sfire_chip *chip); 74 + void usb6fire_pcm_abort(struct sfire_chip *chip); 75 + void usb6fire_pcm_destroy(struct sfire_chip *chip); 76 + #endif /* USB6FIRE_PCM_H */
+16
sound/usb/Kconfig
··· 97 97 To compile this driver as a module, choose M here: the module 98 98 will be called snd-usb-us122l. 99 99 100 + config SND_USB_6FIRE 101 + tristate "TerraTec DMX 6Fire USB" 102 + depends on EXPERIMENTAL 103 + select FW_LOADER 104 + select SND_RAWMIDI 105 + select SND_PCM 106 + help 107 + Say Y here to include support for TerraTec 6fire DMX USB interface. 108 + 109 + You will need firmware files in order to be able to use the device 110 + after it has been coldstarted. This driver currently does not support 111 + firmware loading for all devices. If you own such a device, 112 + you could start windows and let the windows driver upload 113 + the firmware. As long as you do not unplug your device from power, 114 + it should be usable. 115 + 100 116 endif # SND_USB 101 117
+1 -1
sound/usb/Makefile
··· 23 23 obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o 24 24 obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o 25 25 26 - obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 26 + obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/