📄 rawmidi.c
字号:
return -ENOIOCTLCMD;}/** * snd_rawmidi_receive - receive the input data from the device * @substream: the rawmidi substream * @buffer: the buffer pointer * @count: the data size to read * * Reads the data from the internal buffer. * * Returns the size of read data, or a negative error code on failure. */int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, const unsigned char *buffer, int count){ unsigned long flags; int result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; if (runtime->buffer == NULL) { snd_printd("snd_rawmidi_receive: input is not active!!!\n"); return -EINVAL; } spin_lock_irqsave(&runtime->lock, flags); if (count == 1) { /* special case, faster code */ substream->bytes++; if (runtime->avail < runtime->buffer_size) { runtime->buffer[runtime->hw_ptr++] = buffer[0]; runtime->hw_ptr %= runtime->buffer_size; runtime->avail++; result++; } else { runtime->xruns++; } } else { substream->bytes += count; count1 = runtime->buffer_size - runtime->hw_ptr; if (count1 > count) count1 = count; if (count1 > (int)(runtime->buffer_size - runtime->avail)) count1 = runtime->buffer_size - runtime->avail; memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1); runtime->hw_ptr += count1; runtime->hw_ptr %= runtime->buffer_size; runtime->avail += count1; count -= count1; result += count1; if (count > 0) { buffer += count1; count1 = count; if (count1 > (int)(runtime->buffer_size - runtime->avail)) { count1 = runtime->buffer_size - runtime->avail; runtime->xruns += count - count1; } if (count1 > 0) { memcpy(runtime->buffer, buffer, count1); runtime->hw_ptr = count1; runtime->avail += count1; result += count1; } } } if (result > 0) { if (runtime->event) tasklet_hi_schedule(&runtime->tasklet); else if (snd_rawmidi_ready(substream)) wake_up(&runtime->sleep); } spin_unlock_irqrestore(&runtime->lock, flags); return result;}static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, unsigned char *buf, long count, int kernel){ unsigned long flags; long result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; if (count1 > count) count1 = count; spin_lock_irqsave(&runtime->lock, flags); if (count1 > (int)runtime->avail) count1 = runtime->avail; if (kernel) { memcpy(buf + result, runtime->buffer + runtime->appl_ptr, count1); } else { spin_unlock_irqrestore(&runtime->lock, flags); if (copy_to_user((char __user *)buf + result, runtime->buffer + runtime->appl_ptr, count1)) { return result > 0 ? result : -EFAULT; } spin_lock_irqsave(&runtime->lock, flags); } runtime->appl_ptr += count1; runtime->appl_ptr %= runtime->buffer_size; runtime->avail -= count1; spin_unlock_irqrestore(&runtime->lock, flags); result += count1; count -= count1; } return result;}long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream, unsigned char *buf, long count){ snd_rawmidi_input_trigger(substream, 1); return snd_rawmidi_kernel_read1(substream, buf, count, 1);}static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count, loff_t *offset){ long result; int count1; struct snd_rawmidi_file *rfile; struct snd_rawmidi_substream *substream; struct snd_rawmidi_runtime *runtime; rfile = file->private_data; substream = rfile->input; if (substream == NULL) return -EIO; runtime = substream->runtime; snd_rawmidi_input_trigger(substream, 1); result = 0; while (count > 0) { spin_lock_irq(&runtime->lock); while (!snd_rawmidi_ready(substream)) { wait_queue_t wait; if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { spin_unlock_irq(&runtime->lock); return result > 0 ? result : -EAGAIN; } init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irq(&runtime->lock); schedule(); remove_wait_queue(&runtime->sleep, &wait); if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (!runtime->avail) return result > 0 ? result : -EIO; spin_lock_irq(&runtime->lock); } spin_unlock_irq(&runtime->lock); count1 = snd_rawmidi_kernel_read1(substream, (unsigned char __force *)buf, count, 0); if (count1 < 0) return result > 0 ? result : count1; result += count1; buf += count1; count -= count1; } return result;}/** * snd_rawmidi_transmit_empty - check whether the output buffer is empty * @substream: the rawmidi substream * * Returns 1 if the internal output buffer is empty, 0 if not. */int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream){ struct snd_rawmidi_runtime *runtime = substream->runtime; int result; unsigned long flags; if (runtime->buffer == NULL) { snd_printd("snd_rawmidi_transmit_empty: output is not active!!!\n"); return 1; } spin_lock_irqsave(&runtime->lock, flags); result = runtime->avail >= runtime->buffer_size; spin_unlock_irqrestore(&runtime->lock, flags); return result; }/** * snd_rawmidi_transmit_peek - copy data from the internal buffer * @substream: the rawmidi substream * @buffer: the buffer pointer * @count: data size to transfer * * Copies data from the internal output buffer to the given buffer. * * Call this in the interrupt handler when the midi output is ready, * and call snd_rawmidi_transmit_ack() after the transmission is * finished. * * Returns the size of copied data, or a negative error code on failure. */int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count){ unsigned long flags; int result, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; if (runtime->buffer == NULL) { snd_printd("snd_rawmidi_transmit_peek: output is not active!!!\n"); return -EINVAL; } result = 0; spin_lock_irqsave(&runtime->lock, flags); if (runtime->avail >= runtime->buffer_size) { /* warning: lowlevel layer MUST trigger down the hardware */ goto __skip; } if (count == 1) { /* special case, faster code */ *buffer = runtime->buffer[runtime->hw_ptr]; result++; } else { count1 = runtime->buffer_size - runtime->hw_ptr; if (count1 > count) count1 = count; if (count1 > (int)(runtime->buffer_size - runtime->avail)) count1 = runtime->buffer_size - runtime->avail; memcpy(buffer, runtime->buffer + runtime->hw_ptr, count1); count -= count1; result += count1; if (count > 0) { if (count > (int)(runtime->buffer_size - runtime->avail - count1)) count = runtime->buffer_size - runtime->avail - count1; memcpy(buffer + count1, runtime->buffer, count); result += count; } } __skip: spin_unlock_irqrestore(&runtime->lock, flags); return result;}/** * snd_rawmidi_transmit_ack - acknowledge the transmission * @substream: the rawmidi substream * @count: the tranferred count * * Advances the hardware pointer for the internal output buffer with * the given size and updates the condition. * Call after the transmission is finished. * * Returns the advanced size if successful, or a negative error code on failure. */int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count){ unsigned long flags; struct snd_rawmidi_runtime *runtime = substream->runtime; if (runtime->buffer == NULL) { snd_printd("snd_rawmidi_transmit_ack: output is not active!!!\n"); return -EINVAL; } spin_lock_irqsave(&runtime->lock, flags); snd_assert(runtime->avail + count <= runtime->buffer_size, ); runtime->hw_ptr += count; runtime->hw_ptr %= runtime->buffer_size; runtime->avail += count; substream->bytes += count; if (count > 0) { if (runtime->drain || snd_rawmidi_ready(substream)) wake_up(&runtime->sleep); } spin_unlock_irqrestore(&runtime->lock, flags); return count;}/** * snd_rawmidi_transmit - copy from the buffer to the device * @substream: the rawmidi substream * @buffer: the buffer pointer * @count: the data size to transfer * * Copies data from the buffer to the device and advances the pointer. * * Returns the copied size if successful, or a negative error code on failure. */int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count){ count = snd_rawmidi_transmit_peek(substream, buffer, count); if (count < 0) return count; return snd_rawmidi_transmit_ack(substream, count);}static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, const unsigned char *buf, long count, int kernel){ unsigned long flags; long count1, result; struct snd_rawmidi_runtime *runtime = substream->runtime; snd_assert(buf != NULL, return -EINVAL); snd_assert(runtime->buffer != NULL, return -EINVAL); result = 0; spin_lock_irqsave(&runtime->lock, flags); if (substream->append) { if ((long)runtime->avail < count) { spin_unlock_irqrestore(&runtime->lock, flags); return -EAGAIN; } } while (count > 0 && runtime->avail > 0) { count1 = runtime->buffer_size - runtime->appl_ptr; if (count1 > count) count1 = count; if (count1 > (long)runtime->avail) count1 = runtime->avail; if (kernel) { memcpy(runtime->buffer + runtime->appl_ptr, buf, count1); } else { spin_unlock_irqrestore(&runtime->lock, flags); if (copy_from_user(runtime->buffer + runtime->appl_ptr, (char __user *)buf, count1)) { spin_lock_irqsave(&runtime->lock, flags); result = result > 0 ? result : -EFAULT; goto __end; } spin_lock_irqsave(&runtime->lock, flags); } runtime->appl_ptr += count1; runtime->appl_ptr %= runtime->buffer_size; runtime->avail -= count1; result += count1; buf += count1; count -= count1; } __end: count1 = runtime->avail < runtime->buffer_size; spin_unlock_irqrestore(&runtime->lock, flags); if (count1) snd_rawmidi_output_trigger(substream, 1); return result;}long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream, const unsigned char *buf, long count){ return snd_rawmidi_kernel_write1(substream, buf, count, 1);}static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, size_t count, loff_t *offset){ long result, timeout; int count1; struct snd_rawmidi_file *rfile; struct snd_rawmidi_runtime *runtime; struct snd_rawmidi_substream *substream; rfile = file->private_data; substream = rfile->output; runtime = substream->runtime; /* we cannot put an atomic message to our buffer */ if (substream->append && count > runtime->buffer_size) return -EIO; result = 0; while (count > 0) { spin_lock_irq(&runtime->lock); while (!snd_rawmidi_ready_append(substream, count)) { wait_queue_t wait; if (file->f_flags & O_NONBLOCK) { spin_unlock_irq(&runtime->lock); return result > 0 ? result : -EAGAIN; } init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irq(&runtime->lock); timeout = schedule_timeout(30 * HZ); remove_wait_queue(&runtime->sleep, &wait); if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (!runtime->avail && !timeout) return result > 0 ? result : -EIO; spin_lock_irq(&runtime->lock); } spin_unlock_irq(&runtime->lock); count1 = snd_rawmidi_kernel_write1(substream, (unsigned char __force *)buf, count, 0); if (count1 < 0) return result > 0 ? result : count1; result += count1; buf += count1; if ((size_t)count1 < count && (file->f_flags & O_NONBLOCK)) break; count -= count1; } if (file->f_flags & O_SYNC) { spin_lock_irq(&runtime->lock); while (runtime->avail != runtime->buffer_size) { wait_queue_t wait; unsigned int last_avail = runtime->avail; init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irq(&runtime->lock); timeout = schedule_timeout(30 * HZ); remove_wait_queue(&runtime->sleep, &wait); if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (runtime->avail == last_avail && !timeout) return result > 0 ? result : -EIO; spin_lock_irq(&runtime->lock); } spin_unlock_irq(&runtime->lock); } return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -