⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 midibuf.c

📁 freebsd v4.4内核源码
💻 C
字号:
/* * sound/midibuf.c * * Device file manager for /dev/midi# * * Copyright by Hannu Savolainen 1993 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */#include <i386/isa/sound/sound_config.h>static void drain_midi_queue __P((int dev));#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)/* * Don't make MAX_QUEUE_SIZE larger than 4000 */#define MAX_QUEUE_SIZE	4000DEFINE_WAIT_QUEUES (midi_sleeper[MAX_MIDI_DEV], midi_sleep_flag[MAX_MIDI_DEV]);DEFINE_WAIT_QUEUES (input_sleeper[MAX_MIDI_DEV], input_sleep_flag[MAX_MIDI_DEV]);struct midi_buf  {    int             len, head, tail;    unsigned char   queue[MAX_QUEUE_SIZE];  };struct midi_parms  {    int             prech_timeout;	/*					 * Timeout before the first ch					 */  };static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] ={NULL};static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] ={NULL};static struct midi_parms parms[MAX_MIDI_DEV];static void     midi_poll (unsigned long dummy);DEFINE_TIMER (poll_timer, midi_poll);static volatile int open_devs = 0;#define DATA_AVAIL(q) (q->len)#define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len)#define QUEUE_BYTE(q, data) \	if (SPACE_AVAIL(q)) \	{ \	  unsigned long flags; \	  DISABLE_INTR(flags); \	  q->queue[q->tail] = (data); \	  q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \	  RESTORE_INTR(flags); \	}#define REMOVE_BYTE(q, data) \	if (DATA_AVAIL(q)) \	{ \	  unsigned long flags; \	  DISABLE_INTR(flags); \	  data = q->queue[q->head]; \	  q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \	  RESTORE_INTR(flags); \	}static voiddrain_midi_queue (int dev){  /*   * Give the Midi driver time to drain its output queues   */  if (midi_devs[dev]->buffer_status != NULL)    while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) &&	   midi_devs[dev]->buffer_status (dev))      DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], HZ / 10);}static voidmidi_input_intr (int dev, unsigned char data){  if (midi_in_buf[dev] == NULL)    return;  if (data == 0xfe)		/*				 * Active sensing				 */    return;			/*				 * Ignore				 */  if (SPACE_AVAIL (midi_in_buf[dev]))    {      QUEUE_BYTE (midi_in_buf[dev], data);      if (SOMEONE_WAITING (input_sleeper[dev], input_sleep_flag[dev]))	WAKE_UP (input_sleeper[dev], input_sleep_flag[dev]);    }#if defined(__FreeBSD__)  if (selinfo[dev].si_pid)    selwakeup(&selinfo[dev]);#endif}static voidmidi_output_intr (int dev){  /*   * Currently NOP   */#if defined(__FreeBSD__)  if (selinfo[dev].si_pid)    selwakeup(&selinfo[dev]);#endif}static voidmidi_poll (unsigned long dummy){  unsigned long   flags;  int             dev;  DISABLE_INTR (flags);  if (open_devs)    {      for (dev = 0; dev < num_midis; dev++)	if (midi_out_buf[dev] != NULL)	  {	    while (DATA_AVAIL (midi_out_buf[dev]) &&		   midi_devs[dev]->putc (dev,			 midi_out_buf[dev]->queue[midi_out_buf[dev]->head]))	      {		midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;		midi_out_buf[dev]->len--;	      }	    if (DATA_AVAIL (midi_out_buf[dev]) < 100 &&		SOMEONE_WAITING (midi_sleeper[dev], midi_sleep_flag[dev]))	      WAKE_UP (midi_sleeper[dev], midi_sleep_flag[dev]);	  }      ACTIVATE_TIMER (poll_timer, midi_poll, 1);	/*							 * Come back later							 */    }  RESTORE_INTR (flags);}intMIDIbuf_open (int dev, struct fileinfo *file){  int             mode, err;  unsigned long   flags;  dev = dev >> 4;  mode = file->mode & O_ACCMODE;  if (num_midis > MAX_MIDI_DEV)    {      printk ("Sound: FATAL ERROR: Too many midi interfaces\n");      num_midis = MAX_MIDI_DEV;    }  if (dev < 0 || dev >= num_midis)    {      printk ("Sound: Nonexistent MIDI interface %d\n", dev);      return RET_ERROR (ENXIO);    }  /*     *    Interrupts disabled. Be careful   */  DISABLE_INTR (flags);  if ((err = midi_devs[dev]->open (dev, mode,				   midi_input_intr, midi_output_intr)) < 0)    {      RESTORE_INTR (flags);      return err;    }  parms[dev].prech_timeout = 0;  RESET_WAIT_QUEUE (midi_sleeper[dev], midi_sleep_flag[dev]);  RESET_WAIT_QUEUE (input_sleeper[dev], input_sleep_flag[dev]);  midi_in_buf[dev] = (struct midi_buf *) KERNEL_MALLOC (sizeof (struct midi_buf));  if (midi_in_buf[dev] == NULL)    {      printk ("midi: Can't allocate buffer\n");      midi_devs[dev]->close (dev);      RESTORE_INTR (flags);      return RET_ERROR (EIO);    }  midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;  midi_out_buf[dev] = (struct midi_buf *) KERNEL_MALLOC (sizeof (struct midi_buf));  if (midi_out_buf[dev] == NULL)    {      printk ("midi: Can't allocate buffer\n");      midi_devs[dev]->close (dev);      KERNEL_FREE (midi_in_buf[dev]);      midi_in_buf[dev] = NULL;      RESTORE_INTR (flags);      return RET_ERROR (EIO);    }  midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;  if (!open_devs)    ACTIVATE_TIMER (poll_timer, midi_poll, 1);	/*						 * Come back later						 */  open_devs++;  RESTORE_INTR (flags);  return err;}voidMIDIbuf_release (int dev, struct fileinfo *file){  int             mode;  unsigned long   flags;  dev = dev >> 4;  mode = file->mode & O_ACCMODE;  DISABLE_INTR (flags);  /*     * Wait until the queue is empty   */  if (mode != OPEN_READ)    {      midi_devs[dev]->putc (dev, 0xfe);		/*						   * Active sensing to shut the						   * devices						 */      while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) &&	     DATA_AVAIL (midi_out_buf[dev]))	DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], 0);	/*								 * Sync								 */      drain_midi_queue (dev);	/*				 * Ensure the output queues are empty				 */    }  midi_devs[dev]->close (dev);  KERNEL_FREE (midi_in_buf[dev]);  KERNEL_FREE (midi_out_buf[dev]);  midi_in_buf[dev] = NULL;  midi_out_buf[dev] = NULL;  open_devs--;  RESTORE_INTR (flags);}intMIDIbuf_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count){  unsigned long   flags;  int             c, n, i;  unsigned char   tmp_data;  dev = dev >> 4;  if (!count)    return 0;  DISABLE_INTR (flags);  c = 0;  while (c < count)    {      n = SPACE_AVAIL (midi_out_buf[dev]);      if (n == 0)		/*				 * No space just now. We have to sleep				 */	{	  DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], 0);	  if (PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]))	    {	      RESTORE_INTR (flags);	      return RET_ERROR (EINTR);	    }	  n = SPACE_AVAIL (midi_out_buf[dev]);	}      if (n > (count - c))	n = count - c;      for (i = 0; i < n; i++)	{	  COPY_FROM_USER (&tmp_data, buf, c, 1);	  QUEUE_BYTE (midi_out_buf[dev], tmp_data);	  c++;	}    }  RESTORE_INTR (flags);  return c;}intMIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count){  int             n, c = 0;  unsigned long   flags;  unsigned char   tmp_data;  dev = dev >> 4;  DISABLE_INTR (flags);  if (!DATA_AVAIL (midi_in_buf[dev]))	/*					 * No data yet, wait					 */    {      DO_SLEEP (input_sleeper[dev], input_sleep_flag[dev],		parms[dev].prech_timeout);      if (PROCESS_ABORTING (input_sleeper[dev], input_sleep_flag[dev]))	c = RET_ERROR (EINTR);	/*				 * The user is getting restless				 */    }  if (c == 0 && DATA_AVAIL (midi_in_buf[dev]))	/*						 * Got some bytes						 */    {      n = DATA_AVAIL (midi_in_buf[dev]);      if (n > count)	n = count;      c = 0;      while (c < n)	{	  REMOVE_BYTE (midi_in_buf[dev], tmp_data);	  COPY_TO_USER (buf, c, &tmp_data, 1);	  c++;	}    }  RESTORE_INTR (flags);  return c;}intMIDIbuf_ioctl (int dev, struct fileinfo *file,	       unsigned int cmd, unsigned int arg){  int             val;  dev = dev >> 4;  if (((cmd >> 8) & 0xff) == 'C')    {      if (midi_devs[dev]->coproc)	/* Coprocessor ioctl */	return midi_devs[dev]->coproc->ioctl (midi_devs[dev]->coproc->devc, cmd, arg, 0);      else	printk ("/dev/midi%d: No coprocessor for this device\n", dev);      return RET_ERROR (EREMOTEIO);    }  else    switch (cmd)      {      case SNDCTL_MIDI_PRETIME:	val = IOCTL_IN (arg);	if (val < 0)	  val = 0;	val = (HZ * val) / 10;	parms[dev].prech_timeout = val;	return IOCTL_OUT (arg, val);	break;      default:	return midi_devs[dev]->ioctl (dev, cmd, arg);      }}#ifdef ALLOW_SELECTintMIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait){  dev = dev >> 4;  switch (sel_type)    {    case SEL_IN:      if (!DATA_AVAIL (midi_in_buf[dev]))	{#if defined(__FreeBSD__)	  selrecord(wait, &selinfo[dev]);#else	  input_sleep_flag[dev].mode = WK_SLEEP;	  select_wait (&input_sleeper[dev], wait);#endif	  return 0;	}      return 1;      break;    case SEL_OUT:      if (SPACE_AVAIL (midi_out_buf[dev]))	{#if defined(__FreeBSD__)	  selrecord(wait, &selinfo[dev]);#else	  midi_sleep_flag[dev].mode = WK_SLEEP;	  select_wait (&midi_sleeper[dev], wait);#endif	  return 0;	}      return 1;      break;    case SEL_EX:      return 0;    }  return 0;}#endif /* ALLOW_SELECT */longMIDIbuf_init (long mem_start){  return mem_start;}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -