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

📄 mpu401.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
  devc->uart_mode = 0;  return ok;}static voidset_uart_mode (int dev, struct mpu_config *devc, int arg){  if (!arg && devc->version == 0)    {      return;    }  if ((devc->uart_mode == 0) == (arg == 0))    {      return;			/* Already set */    }  reset_mpu401 (devc);		/* This exits the uart mode */  if (arg)    {      if (exec_cmd (dev, UART_MODE_ON, 0) < 0)	{	  printk ("MPU%d: Can't enter UART mode\n", devc->devno);	  devc->uart_mode = 0;	  return;	}    }  devc->uart_mode = arg;}intprobe_mpu401 (struct address_info *hw_config){  int             ok = 0;  struct mpu_config tmp_devc;  tmp_devc.base = hw_config->io_base;  tmp_devc.irq = hw_config->irq;  tmp_devc.initialized = 0;#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MPU401)  /*     * Initialize Audio Excel DSP 16 to MPU-401, before any operation.   */  InitAEDSP16_MPU401 (hw_config);#endif  if (hw_config->always_detect)    return 1;  if (INB (hw_config->io_base + 1) == 0xff)    return 0;			/* Just bus float? */  ok = reset_mpu401 (&tmp_devc);  return ok;}/***************************************************** *      Timer stuff ****************************************************/#if !defined(EXCLUDE_SEQUENCER)static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0;static volatile int curr_tempo, curr_timebase, hw_timebase;static int      max_timebase = 8;	/* 8*24=192 ppqn */static volatile unsigned long next_event_time;static volatile unsigned long curr_ticks, curr_clocks;static unsigned long prev_event_time;static int      metronome_mode;static unsigned longclocks2ticks (unsigned long clocks){  /*     * The MPU-401 supports just a limited set of possible timebase values.     * Since the applications require more choices, the driver has to     * program the HW to do it's best and to convert between the HW and     * actual timebases.   */  return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase;}static voidset_timebase (int midi_dev, int val){  int             hw_val;  if (val < 48)    val = 48;  if (val > 1000)    val = 1000;  hw_val = val;  hw_val = (hw_val + 23) / 24;  if (hw_val > max_timebase)    hw_val = max_timebase;  if (exec_cmd (midi_dev, 0xC0 | (hw_val & 0x0f), 0) < 0)    {      printk ("MPU: Can't set HW timebase to %d\n", hw_val * 24);      return;    }  hw_timebase = hw_val * 24;  curr_timebase = val;}static voidtmr_reset (void){  unsigned long   flags;  DISABLE_INTR (flags);  next_event_time = 0xffffffff;  prev_event_time = 0;  curr_ticks = curr_clocks = 0;  RESTORE_INTR (flags);}static voidset_timer_mode (int midi_dev){  if (timer_mode & TMR_MODE_CLS)    exec_cmd (midi_dev, 0x3c, 0);	/* Use CLS sync */  else if (timer_mode & TMR_MODE_SMPTE)    exec_cmd (midi_dev, 0x3d, 0);	/* Use SMPTE sync */  if (timer_mode & TMR_INTERNAL)    {      exec_cmd (midi_dev, 0x80, 0);	/* Use MIDI sync */    }  else    {      if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS))	{	  exec_cmd (midi_dev, 0x82, 0);		/* Use MIDI sync */	  exec_cmd (midi_dev, 0x91, 0);		/* Enable ext MIDI ctrl */	}      else if (timer_mode & TMR_MODE_FSK)	exec_cmd (midi_dev, 0x81, 0);	/* Use FSK sync */    }}static voidstop_metronome (int midi_dev){  exec_cmd (midi_dev, 0x84, 0);	/* Disable metronome */}static voidsetup_metronome (int midi_dev){  int             numerator, denominator;  int             clks_per_click, num_32nds_per_beat;  int             beats_per_measure;  numerator = ((unsigned) metronome_mode >> 24) & 0xff;  denominator = ((unsigned) metronome_mode >> 16) & 0xff;  clks_per_click = ((unsigned) metronome_mode >> 8) & 0xff;  num_32nds_per_beat = (unsigned) metronome_mode & 0xff;  beats_per_measure = (numerator * 4) >> denominator;  if (!metronome_mode)    exec_cmd (midi_dev, 0x84, 0);	/* Disable metronome */  else    {      exec_cmd (midi_dev, 0xE4, clks_per_click);      exec_cmd (midi_dev, 0xE6, beats_per_measure);      exec_cmd (midi_dev, 0x83, 0);	/* Enable metronome without accents */    }}static intstart_timer (int midi_dev){  tmr_reset ();  set_timer_mode (midi_dev);  if (tmr_running)    return TIMER_NOT_ARMED;	/* Already running */  if (timer_mode & TMR_INTERNAL)    {      exec_cmd (midi_dev, 0x02, 0);	/* Send MIDI start */      tmr_running = 1;      return TIMER_NOT_ARMED;    }  else    {      exec_cmd (midi_dev, 0x35, 0);	/* Enable mode messages to PC */      exec_cmd (midi_dev, 0x38, 0);	/* Enable sys common messages to PC */      exec_cmd (midi_dev, 0x39, 0);	/* Enable real time messages to PC */      exec_cmd (midi_dev, 0x97, 0);	/* Enable system exclusive messages to PC */    }  return TIMER_ARMED;}static intmpu_timer_open (int dev, int mode){  int             midi_dev = sound_timer_devs[dev]->devlink;  if (timer_open)    return RET_ERROR (EBUSY);  tmr_reset ();  curr_tempo = 50;  exec_cmd (midi_dev, 0xE0, 50);  curr_timebase = hw_timebase = 120;  set_timebase (midi_dev, 120);  timer_open = 1;  metronome_mode = 0;  set_timer_mode (midi_dev);  exec_cmd (midi_dev, 0xe7, 0x04);	/* Send all clocks to host */  exec_cmd (midi_dev, 0x95, 0);	/* Enable clock to host */  return 0;}static voidmpu_timer_close (int dev){  int             midi_dev = sound_timer_devs[dev]->devlink;  timer_open = tmr_running = 0;  exec_cmd (midi_dev, 0x15, 0);	/* Stop all */  exec_cmd (midi_dev, 0x94, 0);	/* Disable clock to host */  exec_cmd (midi_dev, 0x8c, 0);	/* Disable measure end messages to host */  stop_metronome (midi_dev);}static intmpu_timer_event (int dev, unsigned char *event){  unsigned char   command = event[1];  unsigned long   parm = *(unsigned int *) &event[4];  int             midi_dev = sound_timer_devs[dev]->devlink;  switch (command)    {    case TMR_WAIT_REL:      parm += prev_event_time;    case TMR_WAIT_ABS:      if (parm > 0)	{	  long            time;	  if (parm <= curr_ticks)	/* It's the time */	    return TIMER_NOT_ARMED;	  time = parm;	  next_event_time = prev_event_time = time;	  return TIMER_ARMED;	}      break;    case TMR_START:      if (tmr_running)	break;      return start_timer (midi_dev);      break;    case TMR_STOP:      exec_cmd (midi_dev, 0x01, 0);	/* Send MIDI stop */      stop_metronome (midi_dev);      tmr_running = 0;      break;    case TMR_CONTINUE:      if (tmr_running)	break;      exec_cmd (midi_dev, 0x03, 0);	/* Send MIDI continue */      setup_metronome (midi_dev);      tmr_running = 1;      break;    case TMR_TEMPO:      if (parm)	{	  if (parm < 8)	    parm = 8;	  if (parm > 250)	    parm = 250;	  if (exec_cmd (midi_dev, 0xE0, parm) < 0)	    printk ("MPU: Can't set tempo to %d\n", (int) parm);	  curr_tempo = parm;	}      break;    case TMR_ECHO:      seq_copy_to_input (event, 8);      break;    case TMR_TIMESIG:      if (metronome_mode)	/* Metronome enabled */	{	  metronome_mode = parm;	  setup_metronome (midi_dev);	}      break;    default:;    }  return TIMER_NOT_ARMED;}static unsigned longmpu_timer_get_time (int dev){  if (!timer_open)    return 0;  return curr_ticks;}static intmpu_timer_ioctl (int dev,		 unsigned int command, unsigned int arg){  int             midi_dev = sound_timer_devs[dev]->devlink;  switch (command)    {    case SNDCTL_TMR_SOURCE:      {	int             parm = IOCTL_IN (arg) & timer_caps;	if (parm != 0)	  {	    timer_mode = parm;	    if (timer_mode & TMR_MODE_CLS)	      exec_cmd (midi_dev, 0x3c, 0);	/* Use CLS sync */	    else if (timer_mode & TMR_MODE_SMPTE)	      exec_cmd (midi_dev, 0x3d, 0);	/* Use SMPTE sync */	  }	return IOCTL_OUT (arg, timer_mode);      }      break;    case SNDCTL_TMR_START:      start_timer (midi_dev);      return 0;      break;    case SNDCTL_TMR_STOP:      tmr_running = 0;      exec_cmd (midi_dev, 0x01, 0);	/* Send MIDI stop */      stop_metronome (midi_dev);      return 0;      break;    case SNDCTL_TMR_CONTINUE:      if (tmr_running)	return 0;      tmr_running = 1;      exec_cmd (midi_dev, 0x03, 0);	/* Send MIDI continue */      return 0;      break;    case SNDCTL_TMR_TIMEBASE:      {	int             val = IOCTL_IN (arg);	if (val)	  set_timebase (midi_dev, val);	return IOCTL_OUT (arg, curr_timebase);      }      break;    case SNDCTL_TMR_TEMPO:      {	int             val = IOCTL_IN (arg);	int             ret;	if (val)	  {	    if (val < 8)	      val = 8;	    if (val > 250)	      val = 250;	    if ((ret = exec_cmd (midi_dev, 0xE0, val)) < 0)	      {		printk ("MPU: Can't set tempo to %d\n", (int) val);		return ret;	      }	    curr_tempo = val;	  }	return IOCTL_OUT (arg, curr_tempo);      }      break;    case SNDCTL_SEQ_CTRLRATE:      if (IOCTL_IN (arg) != 0)	/* Can't change */	return RET_ERROR (EINVAL);      return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);      break;    case SNDCTL_TMR_METRONOME:      metronome_mode = IOCTL_IN (arg);      setup_metronome (midi_dev);      return 0;      break;    default:    }  return RET_ERROR (EINVAL);}static voidmpu_timer_arm (int dev, long time){  if (time < 0)    time = curr_ticks + 1;  else if (time <= curr_ticks)	/* It's the time */    return;  next_event_time = prev_event_time = time;  return;}static struct sound_timer_operations mpu_timer ={  {"MPU-401 Timer", 0},  10,				/* Priority */  0,				/* Local device link */  mpu_timer_open,  mpu_timer_close,  mpu_timer_event,  mpu_timer_get_time,  mpu_timer_ioctl,  mpu_timer_arm};static voidmpu_timer_interrupt (void){  if (!timer_open)    return;  if (!tmr_running)    return;  curr_clocks++;  curr_ticks = clocks2ticks (curr_clocks);  if (curr_ticks >= next_event_time)    {      next_event_time = 0xffffffff;      sequencer_timer ();    }}static voidtimer_ext_event (struct mpu_config *devc, int event, int parm){  int             midi_dev = devc->devno;  if (!devc->timer_flag)    return;  switch (event)    {    case TMR_CLOCK:      printk ("<MIDI clk>");      break;    case TMR_START:      printk ("Ext MIDI start\n");      if (!tmr_running)	if (timer_mode & TMR_EXTERNAL)	  {	    tmr_running = 1;	    setup_metronome (midi_dev);	    next_event_time = 0;	    STORE (SEQ_START_TIMER ());	  }      break;    case TMR_STOP:      printk ("Ext MIDI stop\n");      if (timer_mode & TMR_EXTERNAL)	{	  tmr_running = 0;	  stop_metronome (midi_dev);	  STORE (SEQ_STOP_TIMER ());	}      break;    case TMR_CONTINUE:      printk ("Ext MIDI continue\n");      if (timer_mode & TMR_EXTERNAL)	{	  tmr_running = 1;	  setup_metronome (midi_dev);	  STORE (SEQ_CONTINUE_TIMER ());	}      break;    case TMR_SPP:      printk ("Songpos: %d\n", parm);      if (timer_mode & TMR_EXTERNAL)	{	  STORE (SEQ_SONGPOS (parm));	}      break;    }}static voidmpu_timer_init (int midi_dev){  struct mpu_config *devc;  int             n;  devc = &dev_conf[midi_dev];  if (timer_initialized)    return;			/* There is already a similar timer */  timer_initialized = 1;  mpu_timer.devlink = midi_dev;  dev_conf[midi_dev].timer_flag = 1;#if 1  if (num_sound_timers >= MAX_TIMER_DEV)    n = 0;			/* Overwrite the system timer */  else    n = num_sound_timers++;#else  n = 0;#endif  sound_timer_devs[n] = &mpu_timer;  if (devc->version < 0x20)	/* Original MPU-401 */    timer_caps = TMR_INTERNAL | TMR_EXTERNAL | TMR_MODE_FSK | TMR_MODE_MIDI;  else    {      /*         * The version number 2.0 is used (at least) by the         * MusicQuest cards and the Roland Super-MPU.         *         * MusicQuest has given a special meaning to the bits of the         * revision number. The Super-MPU returns 0.       */      if (devc->revision)	timer_caps |= TMR_EXTERNAL | TMR_MODE_MIDI;      if (devc->revision & 0x02)	timer_caps |= TMR_MODE_CLS;#if 0      if (devc->revision & 0x04)	timer_caps |= TMR_MODE_SMPTE;#endif      if (devc->revision & 0x40)	max_timebase = 10;	/* Has the 216 and 240 ppqn modes */    }  timer_mode = (TMR_INTERNAL | TMR_MODE_MIDI) & timer_caps;}#endif#endif#endif

⌨️ 快捷键说明

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