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(snd_card_t* 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_OOM); 52 vaddr = (char*)((usX2Ydev_t*)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(snd_hwdep_t * hw, struct file *filp, struct vm_area_struct *area) 68 { 69 unsigned long size = (unsigned long)(area->vm_end - area->vm_start); 70 usX2Ydev_t *us428 = (usX2Ydev_t*)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 (!(((usX2Ydev_t*)hw->private_data)->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_SIZE - 1 + sizeof(us428ctls_sharedmem_t)) / PAGE_SIZE) * PAGE_SIZE) { 79 snd_printd( "%lu > %lu\n", size, (unsigned long)sizeof(us428ctls_sharedmem_t)); 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(us428ctls_sharedmem_t), GFP_KERNEL))) 86 return -ENOMEM; 87 memset(us428->us428ctls_sharedmem, -1, sizeof(us428ctls_sharedmem_t)); 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(snd_hwdep_t *hw, struct file *file, poll_table *wait) 97 { 98 unsigned int mask = 0; 99 usX2Ydev_t *us428 = (usX2Ydev_t*)hw->private_data; 100 us428ctls_sharedmem_t *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(snd_hwdep_t *hw, struct file *file) 114 { 115 return 0; 116 } 117 118 static int snd_usX2Y_hwdep_release(snd_hwdep_t *hw, struct file *file) 119 { 120 return 0; 121 } 122 123 static int snd_usX2Y_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info) 124 { 125 static char *type_ids[USX2Y_TYPE_NUMS] = { 126 [USX2Y_TYPE_122] = "us122", 127 [USX2Y_TYPE_224] = "us224", 128 [USX2Y_TYPE_428] = "us428", 129 }; 130 int id = -1; 131 132 switch (le16_to_cpu(((usX2Ydev_t*)hw->private_data)->chip.dev->descriptor.idProduct)) { 133 case USB_ID_US122: 134 id = USX2Y_TYPE_122; 135 break; 136 case USB_ID_US224: 137 id = USX2Y_TYPE_224; 138 break; 139 case USB_ID_US428: 140 id = USX2Y_TYPE_428; 141 break; 142 } 143 if (0 > id) 144 return -ENODEV; 145 strcpy(info->id, type_ids[id]); 146 info->num_dsps = 2; // 0: Prepad Data, 1: FPGA Code 147 if (((usX2Ydev_t*)hw->private_data)->chip_status & USX2Y_STAT_CHIP_INIT) 148 info->chip_ready = 1; 149 info->version = USX2Y_DRIVER_VERSION; 150 return 0; 151 } 152 153 154 static int usX2Y_create_usbmidi(snd_card_t* card ) 155 { 156 static snd_usb_midi_endpoint_info_t quirk_data_1 = { 157 .out_ep =0x06, 158 .in_ep = 0x06, 159 .out_cables = 0x001, 160 .in_cables = 0x001 161 }; 162 static snd_usb_audio_quirk_t quirk_1 = { 163 .vendor_name = "TASCAM", 164 .product_name = NAME_ALLCAPS, 165 .ifnum = 0, 166 .type = QUIRK_MIDI_FIXED_ENDPOINT, 167 .data = &quirk_data_1 168 }; 169 static snd_usb_midi_endpoint_info_t quirk_data_2 = { 170 .out_ep =0x06, 171 .in_ep = 0x06, 172 .out_cables = 0x003, 173 .in_cables = 0x003 174 }; 175 static snd_usb_audio_quirk_t quirk_2 = { 176 .vendor_name = "TASCAM", 177 .product_name = "US428", 178 .ifnum = 0, 179 .type = QUIRK_MIDI_FIXED_ENDPOINT, 180 .data = &quirk_data_2 181 }; 182 struct usb_device *dev = usX2Y(card)->chip.dev; 183 struct usb_interface *iface = usb_ifnum_to_if(dev, 0); 184 snd_usb_audio_quirk_t *quirk = le16_to_cpu(dev->descriptor.idProduct) == USB_ID_US428 ? &quirk_2 : &quirk_1; 185 186 snd_printdd("usX2Y_create_usbmidi \n"); 187 return snd_usb_create_midi_interface(&usX2Y(card)->chip, iface, quirk); 188 } 189 190 static int usX2Y_create_alsa_devices(snd_card_t* card) 191 { 192 int err; 193 194 do { 195 if ((err = usX2Y_create_usbmidi(card)) < 0) { 196 snd_printk("usX2Y_create_alsa_devices: usX2Y_create_usbmidi error %i \n", err); 197 break; 198 } 199 if ((err = usX2Y_audio_create(card)) < 0) 200 break; 201 if ((err = usX2Y_hwdep_pcm_new(card)) < 0) 202 break; 203 if ((err = snd_card_register(card)) < 0) 204 break; 205 } while (0); 206 207 return err; 208 } 209 210 static int snd_usX2Y_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) 211 { 212 usX2Ydev_t *priv = hw->private_data; 213 int lret, err = -EINVAL; 214 snd_printdd( "dsp_load %s\n", dsp->name); 215 216 if (access_ok(VERIFY_READ, dsp->image, dsp->length)) { 217 struct usb_device* dev = priv->chip.dev; 218 char *buf = kmalloc(dsp->length, GFP_KERNEL); 219 if (!buf) 220 return -ENOMEM; 221 if (copy_from_user(buf, dsp->image, dsp->length)) { 222 kfree(buf); 223 return -EFAULT; 224 } 225 err = usb_set_interface(dev, 0, 1); 226 if (err) 227 snd_printk("usb_set_interface error \n"); 228 else 229 err = usb_bulk_msg(dev, usb_sndbulkpipe(dev, 2), buf, dsp->length, &lret, 6000); 230 kfree(buf); 231 } 232 if (err) 233 return err; 234 if (dsp->index == 1) { 235 set_current_state(TASK_UNINTERRUPTIBLE); 236 schedule_timeout(HZ/4); // give the device some time 237 err = usX2Y_AsyncSeq04_init(priv); 238 if (err) { 239 snd_printk("usX2Y_AsyncSeq04_init error \n"); 240 return err; 241 } 242 err = usX2Y_In04_init(priv); 243 if (err) { 244 snd_printk("usX2Y_In04_init error \n"); 245 return err; 246 } 247 err = usX2Y_create_alsa_devices(hw->card); 248 if (err) { 249 snd_printk("usX2Y_create_alsa_devices error %i \n", err); 250 snd_card_free(hw->card); 251 return err; 252 } 253 priv->chip_status |= USX2Y_STAT_CHIP_INIT; 254 snd_printdd("%s: alsa all started\n", hw->name); 255 } 256 return err; 257 } 258 259 260 int usX2Y_hwdep_new(snd_card_t* card, struct usb_device* device) 261 { 262 int err; 263 snd_hwdep_t *hw; 264 265 if ((err = snd_hwdep_new(card, SND_USX2Y_LOADER_ID, 0, &hw)) < 0) 266 return err; 267 268 hw->iface = SNDRV_HWDEP_IFACE_USX2Y; 269 hw->private_data = usX2Y(card); 270 hw->ops.open = snd_usX2Y_hwdep_open; 271 hw->ops.release = snd_usX2Y_hwdep_release; 272 hw->ops.dsp_status = snd_usX2Y_hwdep_dsp_status; 273 hw->ops.dsp_load = snd_usX2Y_hwdep_dsp_load; 274 hw->ops.mmap = snd_us428ctls_mmap; 275 hw->ops.poll = snd_us428ctls_poll; 276 hw->exclusive = 1; 277 sprintf(hw->name, "/proc/bus/usb/%03d/%03d", device->bus->busnum, device->devnum); 278 return 0; 279 } 280 281