1 /* 2 * Driver for Tascam US-X2Y USB soundcards 3 * 4 * FPGA Loader + ALSA Startup 5 * 6 * Copyright (c) 2003 by Karsten Wiese <annabellesgarden@yahoo.de> 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 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22 23 #include <sound/driver.h> 24 #include <linux/interrupt.h> 25 #include <linux/usb.h> 26 #include <sound/core.h> 27 #include <sound/memalloc.h> 28 #include <sound/pcm.h> 29 #include <sound/hwdep.h> 30 #include "usx2y.h" 31 #include "usbusx2y.h" 32 #include "usX2Yhwdep.h" 33 34 int usX2Y_hwdep_pcm_new(struct snd_card *card); 35 36 37 static struct page * snd_us428ctls_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type) 38 { 39 unsigned long offset; 40 struct page * page; 41 void *vaddr; 42 43 snd_printdd("ENTER, start %lXh, ofs %lXh, pgoff %ld, addr %lXh\n", 44 area->vm_start, 45 address - area->vm_start, 46 (address - area->vm_start) >> PAGE_SHIFT, 47 address); 48 49 offset = area->vm_pgoff << PAGE_SHIFT; 50 offset += address - area->vm_start; 51 snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_SIGBUS); 52 vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->us428ctls_sharedmem + offset; 53 page = virt_to_page(vaddr); 54 get_page(page); 55 snd_printdd( "vaddr=%p made us428ctls_vm_nopage() return %p; offset=%lX\n", vaddr, page, offset); 56 57 if (type) 58 *type = VM_FAULT_MINOR; 59 60 return page; 61 } 62 63 static struct vm_operations_struct us428ctls_vm_ops = { 64 .nopage = snd_us428ctls_vm_nopage, 65 }; 66 67 static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area) 68 { 69 unsigned long size = (unsigned long)(area->vm_end - area->vm_start); 70 struct usX2Ydev *us428 = hw->private_data; 71 72 // FIXME this hwdep interface is used twice: fpga download and mmap for controlling Lights etc. Maybe better using 2 hwdep devs? 73 // so as long as the device isn't fully initialised yet we return -EBUSY here. 74 if (!(us428->chip_status & USX2Y_STAT_CHIP_INIT)) 75 return -EBUSY; 76 77 /* if userspace tries to mmap beyond end of our buffer, fail */ 78 if (size > PAGE_ALIGN(sizeof(struct us428ctls_sharedmem))) { 79 snd_printd( "%lu > %lu\n", size, (unsigned long)sizeof(struct us428ctls_sharedmem)); 80 return -EINVAL; 81 } 82 83 if (!us428->us428ctls_sharedmem) { 84 init_waitqueue_head(&us428->us428ctls_wait_queue_head); 85 if(!(us428->us428ctls_sharedmem = snd_malloc_pages(sizeof(struct us428ctls_sharedmem), GFP_KERNEL))) 86 return -ENOMEM; 87 memset(us428->us428ctls_sharedmem, -1, sizeof(struct us428ctls_sharedmem)); 88 us428->us428ctls_sharedmem->CtlSnapShotLast = -2; 89 } 90 area->vm_ops = &us428ctls_vm_ops; 91 area->vm_flags |= VM_RESERVED; 92 area->vm_private_data = hw->private_data; 93 return 0; 94 } 95 96 static unsigned int snd_us428ctls_poll(struct snd_hwdep *hw, struct file *file, poll_table *wait) 97 { 98 unsigned int mask = 0; 99 struct usX2Ydev *us428 = hw->private_data; 100 struct us428ctls_sharedmem *shm = us428->us428ctls_sharedmem; 101 if (us428->chip_status & USX2Y_STAT_CHIP_HUP) 102 return POLLHUP; 103 104 poll_wait(file, &us428->us428ctls_wait_queue_head, wait); 105 106 if (shm != NULL && shm->CtlSnapShotLast != shm->CtlSnapShotRed) 107 mask |= POLLIN; 108 109 return mask; 110 } 111 112 113 static int snd_usX2Y_hwdep_open(struct snd_hwdep *hw, struct file *file) 114 { 115 return 0; 116 } 117 118 static int snd_usX2Y_hwdep_release(struct snd_hwdep *hw, struct file *file) 119 { 120 return 0; 121 } 122 123 static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw, 124 struct snd_hwdep_dsp_status *info) 125 { 126 static char *type_ids[USX2Y_TYPE_NUMS] = { 127 [USX2Y_TYPE_122] = "us122", 128 [USX2Y_TYPE_224] = "us224", 129 [USX2Y_TYPE_428] = "us428", 130 }; 131 struct usX2Ydev *us428 = hw->private_data; 132 int id = -1; 133 134 switch (le16_to_cpu(us428->chip.dev->descriptor.idProduct)) { 135 case USB_ID_US122: 136 id = USX2Y_TYPE_122; 137 break; 138 case USB_ID_US224: 139 id = USX2Y_TYPE_224; 140 break; 141 case USB_ID_US428: 142 id = USX2Y_TYPE_428; 143 break; 144 } 145 if (0 > id) 146 return -ENODEV; 147 strcpy(info->id, type_ids[id]); 148 info->num_dsps = 2; // 0: Prepad Data, 1: FPGA Code 149 if (us428->chip_status & USX2Y_STAT_CHIP_INIT) 150 info->chip_ready = 1; 151 info->version = USX2Y_DRIVER_VERSION; 152 return 0; 153 } 154 155 156 static int usX2Y_create_usbmidi(struct snd_card *card) 157 { 158 static struct snd_usb_midi_endpoint_info quirk_data_1 = { 159 .out_ep = 0x06, 160 .in_ep = 0x06, 161 .out_cables = 0x001, 162 .in_cables = 0x001 163 }; 164 static struct snd_usb_audio_quirk quirk_1 = { 165 .vendor_name = "TASCAM", 166 .product_name = NAME_ALLCAPS, 167 .ifnum = 0, 168 .type = QUIRK_MIDI_FIXED_ENDPOINT, 169 .data = &quirk_data_1 170 }; 171 static struct snd_usb_midi_endpoint_info quirk_data_2 = { 172 .out_ep = 0x06, 173 .in_ep = 0x06, 174 .out_cables = 0x003, 175 .in_cables = 0x003 176 }; 177 static struct snd_usb_audio_quirk quirk_2 = { 178 .vendor_name = "TASCAM", 179 .product_name = "US428", 180 .ifnum = 0, 181 .type = QUIRK_MIDI_FIXED_ENDPOINT, 182 .data = &quirk_data_2 183 }; 184 struct usb_device *dev = usX2Y(card)->chip.dev; 185 struct usb_interface *iface = usb_ifnum_to_if(dev, 0); 186 struct snd_usb_audio_quirk *quirk = 187 le16_to_cpu(dev->descriptor.idProduct) == USB_ID_US428 ? 188 &quirk_2 : &quirk_1; 189 190 snd_printdd("usX2Y_create_usbmidi \n"); 191 return snd_usb_create_midi_interface(&usX2Y(card)->chip, iface, quirk); 192 } 193 194 static int usX2Y_create_alsa_devices(struct snd_card *card) 195 { 196 int err; 197 198 do { 199 if ((err = usX2Y_create_usbmidi(card)) < 0) { 200 snd_printk(KERN_ERR "usX2Y_create_alsa_devices: usX2Y_create_usbmidi error %i \n", err); 201 break; 202 } 203 if ((err = usX2Y_audio_create(card)) < 0) 204 break; 205 if ((err = usX2Y_hwdep_pcm_new(card)) < 0) 206 break; 207 if ((err = snd_card_register(card)) < 0) 208 break; 209 } while (0); 210 211 return err; 212 } 213 214 static int snd_usX2Y_hwdep_dsp_load(struct snd_hwdep *hw, 215 struct snd_hwdep_dsp_image *dsp) 216 { 217 struct usX2Ydev *priv = hw->private_data; 218 int lret, err = -EINVAL; 219 snd_printdd( "dsp_load %s\n", dsp->name); 220 221 if (access_ok(VERIFY_READ, dsp->image, dsp->length)) { 222 struct usb_device* dev = priv->chip.dev; 223 char *buf = kmalloc(dsp->length, GFP_KERNEL); 224 if (!buf) 225 return -ENOMEM; 226 if (copy_from_user(buf, dsp->image, dsp->length)) { 227 kfree(buf); 228 return -EFAULT; 229 } 230 err = usb_set_interface(dev, 0, 1); 231 if (err) 232 snd_printk(KERN_ERR "usb_set_interface error \n"); 233 else 234 err = usb_bulk_msg(dev, usb_sndbulkpipe(dev, 2), buf, dsp->length, &lret, 6000); 235 kfree(buf); 236 } 237 if (err) 238 return err; 239 if (dsp->index == 1) { 240 msleep(250); // give the device some time 241 err = usX2Y_AsyncSeq04_init(priv); 242 if (err) { 243 snd_printk(KERN_ERR "usX2Y_AsyncSeq04_init error \n"); 244 return err; 245 } 246 err = usX2Y_In04_init(priv); 247 if (err) { 248 snd_printk(KERN_ERR "usX2Y_In04_init error \n"); 249 return err; 250 } 251 err = usX2Y_create_alsa_devices(hw->card); 252 if (err) { 253 snd_printk(KERN_ERR "usX2Y_create_alsa_devices error %i \n", err); 254 snd_card_free(hw->card); 255 return err; 256 } 257 priv->chip_status |= USX2Y_STAT_CHIP_INIT; 258 snd_printdd("%s: alsa all started\n", hw->name); 259 } 260 return err; 261 } 262 263 264 int usX2Y_hwdep_new(struct snd_card *card, struct usb_device* device) 265 { 266 int err; 267 struct snd_hwdep *hw; 268 269 if ((err = snd_hwdep_new(card, SND_USX2Y_LOADER_ID, 0, &hw)) < 0) 270 return err; 271 272 hw->iface = SNDRV_HWDEP_IFACE_USX2Y; 273 hw->private_data = usX2Y(card); 274 hw->ops.open = snd_usX2Y_hwdep_open; 275 hw->ops.release = snd_usX2Y_hwdep_release; 276 hw->ops.dsp_status = snd_usX2Y_hwdep_dsp_status; 277 hw->ops.dsp_load = snd_usX2Y_hwdep_dsp_load; 278 hw->ops.mmap = snd_us428ctls_mmap; 279 hw->ops.poll = snd_us428ctls_poll; 280 hw->exclusive = 1; 281 sprintf(hw->name, "/proc/bus/usb/%03d/%03d", device->bus->busnum, device->devnum); 282 return 0; 283 } 284 285