/* * Upload the bootblock(?) into the SoundScape. The only * purpose of this block of code seems to be to tell * us which version of the microcode we should be using. * * NOTE: The boot-block data resides in USER-SPACE!!! * However, we have already verified its memory * addresses by the time we get here. */ static int sscape_upload_bootblock(struct soundscape *sscape, struct sscape_bootblock __user *bb) { unsigned long flags; int data = 0; int ret; ret = upload_dma_data(sscape, bb->code, sizeof(bb->code)); spin_lock_irqsave(&sscape->lock, flags); if (ret == 0) { data = host_read_ctrl_unsafe(sscape->io_base, 100); } set_midi_mode_unsafe(sscape->io_base); spin_unlock_irqrestore(&sscape->lock, flags); if (ret == 0) { if (data < 0) { snd_printk(KERN_ERR "sscape: timeout reading firmware version\n"); ret = -EAGAIN; } else if (__copy_to_user(&bb->version, &data, sizeof(bb->version))) { ret = -EFAULT; } } return ret; }
/* * Upload the microcode into the SoundScape. The * microcode is 64K of data, and if we try to copy * it into a local variable then we will SMASH THE * KERNEL'S STACK! We therefore leave it in USER * SPACE, and save ourselves from copying it at all. */ static int sscape_upload_microcode(struct soundscape *sscape, const struct sscape_microcode __user *mc) { unsigned long flags; char __user *code; int err; /* * We are going to have to copy this data into a special * DMA-able buffer before we can upload it. We shall therefore * just check that the data pointer is valid for now. * * NOTE: This buffer is 64K long! That's WAY too big to * copy into a stack-temporary anyway. */ if ( get_user(code, &mc->code) || !access_ok(VERIFY_READ, code, SSCAPE_MICROCODE_SIZE) ) return -EFAULT; if ((err = upload_dma_data(sscape, code, SSCAPE_MICROCODE_SIZE)) == 0) { snd_printk(KERN_INFO "sscape: MIDI firmware loaded\n"); } spin_lock_irqsave(&sscape->lock, flags); set_midi_mode_unsafe(sscape->io_base); spin_unlock_irqrestore(&sscape->lock, flags); initialise_mpu401(sscape->mpu); return err; }
static int sscape_midi_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) { struct snd_cs4231 *chip = snd_kcontrol_chip(kctl); struct snd_card *card = chip->card; register struct soundscape *s = get_card_soundscape(card); unsigned long flags; spin_lock_irqsave(&s->lock, flags); set_host_mode_unsafe(s->io_base); if (host_write_ctrl_unsafe(s->io_base, CMD_GET_MIDI_VOL, 100)) { uctl->value.integer.value[0] = host_read_ctrl_unsafe(s->io_base, 100); } set_midi_mode_unsafe(s->io_base); spin_unlock_irqrestore(&s->lock, flags); return 0; }
static int sscape_midi_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) { struct snd_wss *chip = snd_kcontrol_chip(kctl); struct snd_card *card = chip->card; register struct soundscape *s = get_card_soundscape(card); unsigned long flags; int change; spin_lock_irqsave(&s->lock, flags); /* * We need to put the board into HOST mode before we * can send any volume-changing HOST commands ... */ set_host_mode_unsafe(s->io_base); /* * To successfully change the MIDI volume setting, you seem to * have to write a volume command, write the new volume value, * and then perform another volume-related command. Perhaps the * first command is an "open" and the second command is a "close"? */ if (s->midi_vol == ((unsigned char) uctl->value.integer. value[0] & 127)) { change = 0; goto __skip_change; } change = (host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100) && host_write_ctrl_unsafe(s->io_base, ((unsigned char) uctl->value.integer. value[0]) & 127, 100) && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100)); s->midi_vol = (unsigned char) uctl->value.integer.value[0] & 127; __skip_change: /* * Take the board out of HOST mode and back into MIDI mode ... */ set_midi_mode_unsafe(s->io_base); spin_unlock_irqrestore(&s->lock, flags); return change; }