Open Sound System |
Do you have problems with sound/audio application development? Don't panic! Click here for help! |
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) { }