Google
 

Open Sound System
The Hitchhiker's Guide to OSS 4.1 Internals

Do you have problems with sound/audio application development? Don't panic! Click here for help!

oss_usb/ossusb_midi.c

USB MIDI streaming interface support

Description




This file is part of Open Sound System.

Copyright (C) 4Front Technologies 1996-2008.

This this source file is released under GPL v2 license (no other versions). See the COPYING file included in the main directory of this source distribution for the license terms and conditions.


#include "oss_config.h"
#include "ossusb.h"

#define RECBUF_SIZE	32
#define PLAYBUF_SIZE	32


MS Class-Specific Interface Descriptor Subtypes

#define MS_HEADER		0x01
#define MIDI_IN_JACK		0x02
#define MIDI_OUT_JACK		0x03
#define ELEMENT			0x04

/* Jack types */
#define JT_EMBEDDED		0x01
#define JT_EXTERNAL		0x02

static int usb_midi_start_input (ossusb_devc * devc, ossusb_midic * midic);

static void
record_callback (udi_usb_request_t * request, void *arg)
{
  ossusb_midic *midic = arg;
  ossusb_devc *devc = midic->devc;
  int i, l;

  l = udi_usb_request_actlen (request);
  if (l == 0)
    goto restart;

  for (i = 0; i < l; i++)
    cmn_err (CE_CONT, "%02x ", devc->recbuf[i]);
  cmn_err (CE_CONT, "\n");

restart:
  usb_midi_start_input (devc, midic);
}

static int
usb_midi_start_input (ossusb_devc * devc, ossusb_midic * midic)
{
  oss_native_word flags;
  int err = 0;

  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);

  if ((err =
       udi_usb_submit_request (devc->input_pipe, record_callback, midic,
			       midic->in_endpoint_handle,
			       UDI_USBXFER_BULK_READ, devc->recbuf,
			       RECBUF_SIZE)) < 0)
    {
      cmn_err (CE_WARN, "usbmidi: udi_usb_submit_request failed, err=%d\n",
	       err);
    }
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);

  return err;
}

static int usb_midi_start_output (ossusb_devc * devc, ossusb_midic * midic);

 /*ARGSUSED*/ static void
play_callback (udi_usb_request_t * request, void *arg)
{
  ossusb_midic *midic = arg;
  ossusb_devc *devc = midic->devc;

  devc->output_busy = 0;
  usb_midi_start_output (devc, midic);
}

static int
usb_midi_start_output (ossusb_devc * devc, ossusb_midic * midic)
{
  oss_native_word flags;
  int err = 0, l = 0;

  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);

  l = devc->q_nbytes;
  if (l > PLAYBUF_SIZE)
    l = PLAYBUF_SIZE;

  if (l == 0 || devc->output_busy)
    {
      MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
      return 0;
    }

  memcpy (devc->playbuf, devc->queue, l);

  if ((err =
       udi_usb_submit_request (devc->output_pipe, play_callback, midic,
			       midic->out_endpoint_handle,
			       UDI_USBXFER_BULK_WRITE, devc->playbuf, l)) < 0)
    {
      cmn_err (CE_WARN, "usbmidi: udi_usb_submit_request() failed, err=%d\n",
	       err);
    }
  else
    devc->output_busy = 1;

  /* Remove the vbytes from the queue */
  if (l >= devc->q_nbytes)
    devc->q_nbytes = 0;
  else
    {
      int n = devc->q_nbytes - l;
      memcpy (devc->queue, devc->queue + l, n);
      devc->q_nbytes -= l;
    }
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);

  return err;
}

static void
usb_midi_close (int dev, int mode)
{
  oss_native_word flags;
  ossusb_midic *midic;
  ossusb_devc *devc;

  midic = midi_devs[dev]->devc;
  devc = midic->devc;

  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
  midic->open_mode = 0;
  midic->midi_input_intr = NULL;
  midic->midi_output_intr = NULL;
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);

  if (mode & OPEN_READ)
    {
      if (devc->input_pipe != NULL)
	udi_usb_cancel_request (devc->input_pipe);
      devc->input_pipe = NULL;

      if (devc->recbuf != NULL)
	CONTIG_FREE (devc->osdev, devc->recbuf, RECBUF_SIZE, devc->recbuf_dma_handle);
      devc->recbuf = NULL;
      if (devc->playbuf != NULL)
	CONTIG_FREE (devc->osdev, devc->playbuf, PLAYBUF_SIZE, devc->playbuf_dma_handle);
      devc->playbuf = NULL;
      udi_close_endpoint (midic->in_endpoint_handle);
    }

  if (mode & OPEN_WRITE)
    {
      udi_usb_cancel_request (devc->output_pipe);
      udi_close_endpoint (midic->out_endpoint_handle);
    }
}

 /*ARGSUSED*/ static int
usb_midi_open (int dev, int mode, oss_midi_inputbyte_t inputbyte,
	       oss_midi_inputbuf_t inputbuf, oss_midi_outputintr_t outputintr)
{
  oss_native_word flags, phaddr;
  ossusb_midic *midic;
  ossusb_devc *devc;

  midic = midi_devs[dev]->devc;
  devc = midic->devc;

  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
  if (midic->open_mode)
    {
      MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
      return OSS_EBUSY;
    }

  midic->open_mode = mode;
  midic->midi_input_intr = inputbyte;
  midic->midi_output_intr = outputintr;
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);

  if (mode & OPEN_WRITE)
    {
      if ((midic->out_endpoint_handle =
	   udi_open_endpoint (midic->usbdev,
			      midic->out_endpoint_desc)) == NULL)
	{
	  usb_midi_close (dev, mode);
	  cmn_err (CE_WARN, "Cannot open midi output pipe\n");
	  return OSS_ENOMEM;
	}

      if ((devc->output_pipe =
	   udi_usb_alloc_request (midic->usbdev, midic->out_endpoint_handle,
				  1, UDI_USBXFER_BULK_WRITE)) == NULL)
	{
	  cmn_err (CE_WARN, "usbmidi: Failed to allocate output pipe\n");
	}

      devc->playbuf =
	CONTIG_MALLOC (devc->osdev, PLAYBUF_SIZE, MEMLIMIT_32BITS, &phaddr, devc->playbuf_dma_handle);

      devc->output_busy = 0;
      devc->q_nbytes = 0;
    }

  if (mode & OPEN_READ)
    {
      int err;

      if ((midic->in_endpoint_handle =
	   udi_open_endpoint (midic->usbdev,
			      midic->in_endpoint_desc)) == NULL)
	{
	  usb_midi_close (dev, mode);
	  cmn_err (CE_WARN, "Cannot open midi input pipe\n");
	  return OSS_ENOMEM;
	}
      if ((devc->input_pipe =
	   udi_usb_alloc_request (midic->usbdev, midic->in_endpoint_handle, 1,
				  UDI_USBXFER_BULK_READ)) == NULL)
	{
	  cmn_err (CE_WARN, "usbmidi: Failed to allocate input pipe\n");
	}
      devc->recbuf =
	CONTIG_MALLOC (devc->osdev, RECBUF_SIZE, MEMLIMIT_32BITS, &phaddr, devc->recbuf_dma_handle);

      if ((err = usb_midi_start_input (devc, midic)) < 0)
	{
	  cmn_err (CE_WARN, "usbmidi: Input error %d\n", err);
	  usb_midi_close (dev, mode);
	  return OSS_EIO;
	}
    }

  return 0;
}

static int
usb_midi_out (int dev, unsigned char data)
{
  ossusb_midic *midic = midi_devs[dev]->devc;
  ossusb_devc *devc;
  oss_native_word flags;
  unsigned char *buf;

  devc = midic->devc;

  cmn_err (CE_CONT, "Send %02x\n", data);
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
  if ((devc->q_nbytes + 4) >= Q_MAX)
    {
      MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
      return 0;
    }

  buf = devc->queue + devc->q_nbytes;

  memset (buf, 0, 4);
  buf[0] = 0x0f;
  buf[1] = data;

  devc->q_nbytes += 4;
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);

  usb_midi_start_output (devc, midic);
  return 1;
}

 /*ARGSUSED*/ static int
usb_midi_ioctl (int dev, unsigned cmd, ioctl_arg arg)
{
  return OSS_EINVAL;
}

static midi_driver_t usb_midi_driver = {
  usb_midi_open,
  usb_midi_close,
  usb_midi_ioctl,
  usb_midi_out,
};

 /*ARGSUSED*/
  ossusb_devc *
ossusb_init_midistream (ossusb_devc * devc, udi_usb_devc * usbdev, int inum,
			int reinit)
{
  int i, n;
  int p, l;
  char tmp[64];
  unsigned char *in_endpoints[16], *out_endpoints[16];
  void *in_endpoint_desc = NULL, *out_endpoint_desc = NULL;
  int num_in_endpoints = 0, num_out_endpoints = 0;
  int cin = 0, cout = 0;
  ossusb_midic *midic;
  unsigned char *desc, *d;
  int desc_len;

  for (i = 0; i < 32; i++)
    if ((desc = udi_usbdev_get_endpoint (usbdev, 0, i, &desc_len)) != NULL)
      {
	unsigned char *ep;

	if (desc_len > 100)
	  desc_len = 100;

	cmn_err (CE_CONT, "Endpoint %d (%d)", i, desc_len);
	ossusb_dump_desc (desc, desc_len);
	ep = desc;

	if (desc[2] & 0x80)
	  {
	    in_endpoints[num_in_endpoints++] = ep;
	  }
	else
	  {
	    out_endpoints[num_out_endpoints++] = ep;
	  }
      }

  cmn_err (CE_CONT, "%d input endpoints: ", num_in_endpoints);
  for (i = 0; i < num_in_endpoints; i++)
    cmn_err (CE_CONT, "%02x ", in_endpoints[i][2]);
  cmn_err (CE_CONT, "\n");
  cmn_err (CE_CONT, "%d input endpoints: ", num_out_endpoints);
  for (i = 0; i < num_out_endpoints; i++)
    cmn_err (CE_CONT, "%02x ", out_endpoints[i][2]);
  cmn_err (CE_CONT, "\n");

  cmn_err (CE_CONT, "USB MIDI stream\n");
  desc = udi_usbdev_get_altsetting (usbdev, 0, &desc_len);
  if (desc == NULL || desc_len < 3)
    {
      cmn_err (CE_WARN, "usbmidi: bad altsetting\n");
      return NULL;
    }
  // ossusb_dump_desc (desc, desc_len);
  p = 0;
  while (p < desc_len)
    {
      d = desc + p;

      l = *d;
      //if (usb_trace > 1)
      {
	cmn_err (CE_CONT, "MIDI streaming desc: ");
	for (i = 0; i < l; i++)
	  cmn_err (CE_CONT, "%02x ", d[i]);
	cmn_err (CE_CONT, "\n");
      }

      if (d[1] != CS_INTERFACE)
	{
	  cmn_err (CE_WARN, "usbmidi: Unrecognized descriptor: \n");
	  ossusb_dump_desc (d, l);
	  p += l;
	  continue;
	}

      switch (d[2])
	{
	case MS_HEADER:
	  cmn_err (CE_CONT, "MS_HEADER: ");
	  cmn_err (CE_CONT, "v%x.%02x ", d[3], d[4]);
	  break;

	case MIDI_IN_JACK:
	  cmn_err (CE_CONT, "MIDI_IN_JACK: ");
	  cmn_err (CE_CONT, "Type %d, ID %02x, iJack %d\n", d[3], d[4], d[5]);
	  in_endpoint_desc = in_endpoints[cin];
	  if (cin < num_in_endpoints - 1)
	    cin++;
	  break;

	case MIDI_OUT_JACK:
	  cmn_err (CE_CONT, "MIDI_OUT_JACK: ");
	  cmn_err (CE_CONT, "Type %d, ID %02x, iJack %d\n", d[3], d[4], d[5]);
	  n = d[5];
	  cmn_err (CE_CONT, "\t%d inputs: ", n);
	  for (i = 0; i < n; i++)
	    cmn_err (CE_CONT, "%02x/%02x ", d[6 + i * 2], d[6 + i * 2 + 1]);
	  cmn_err (CE_CONT, "\n");
	  out_endpoint_desc = out_endpoints[cout];
	  if (cout < num_out_endpoints - 1)
	    cout++;
	  break;

	case ELEMENT:
	  cmn_err (CE_CONT, "ELEMENT\n");
	  break;
	}

      p += l;
    }


#if 1
  if (reinit)
    for (i = 0; i < devc->num_mididevs; i++)
      if (devc->midic[i].in_endpoint_desc == in_endpoint_desc)	/* Already registered this */
	if (devc->midic[i].out_endpoint_desc == out_endpoint_desc)	/* Already registered this */
	  {
	    return devc;
	  }
#endif

  midic = &devc->midic[devc->num_mididevs];

  devc->osdev = devc->osdev;
  midic->devc = devc;
  midic->usbdev = usbdev;
  midic->in_endpoint_desc = in_endpoint_desc;
  midic->out_endpoint_desc = out_endpoint_desc;

  strcpy (tmp, devc->dev_name);

  midic->midi_dev =
    oss_install_mididev (OSS_MIDI_DRIVER_VERSION, "USBMIDI", tmp,
			 &usb_midi_driver, sizeof (midi_driver_t),
			 0, midic, devc->osdev);
  devc->num_mididevs++;

  return devc;
}

 /*ARGSUSED*/ void
ossusb_disconnect_midistream (ossusb_devc * devc)
{
}

Copyright (C) 4Front Technologies, 2007. All rights reserved.

Back to index OSS web site


Copyright (C) 4Front Technologies, 2007. All rights reserved.
Back to index OSS web site