source: sbliveos2/trunk/drv16/mpu401.cpp@ 146

Last change on this file since 146 was 142, checked in by ktk, 25 years ago

Import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.0 KB
Line 
1/* $Id: mpu401.cpp 142 2000-04-23 14:55:46Z ktk $ */
2
3/* SCCSID = %W% %E% */
4/****************************************************************************
5 * *
6 * Copyright (c) IBM Corporation 1994 - 1997. *
7 * *
8 * The following IBM OS/2 source code is provided to you solely for the *
9 * the purpose of assisting you in your development of OS/2 device drivers. *
10 * You may use this code in accordance with the IBM License Agreement *
11 * provided in the IBM Device Driver Source Kit for OS/2. *
12 * *
13 ****************************************************************************/
14/**@internal %W%
15 * MPU_401 object implementation.
16 * @version %I%
17 * @context
18 * Unless otherwise noted, all interfaces are Ring-0, 16-bit, kernel stack.
19 * @notes
20 * @history
21 */
22
23extern "C" { // 16-bit header files are not C++ aware
24#define INCL_NOPMAPI
25#define INCL_DOSMISC
26#include <os2.h>
27}
28#include <os2medef.h> // DATATYPE_MIDI
29#include <include.h> // cli, sti, inp, outp
30#include <string.h> // strcpy(), strcat()
31#include "sizedefs.h" //### NUM_DEVICES, MAX_MPU401
32#include "..\midi\midi_idc.h" // RTMIDI i/f
33#include "iodelay.h"
34#include "malloc.h"
35#include "mpu401.hpp" // Object definition.
36#include "timer.hpp" // Object definition.
37#include "stream.hpp" // Prereq to includeing midistrm.h
38#include "midistrm.hpp" // Object definition.
39
40#include "parse.h"
41
42
43/* Constructor. */
44
45MPU_401::MPU_401(TIMER* pTimer ) :
46 MIDIAUDIO ( AUDIOHW_MPU401_PLAY, pTimer )
47{
48 static char szName[] = "SBLive #"; // Instance name for RTMIDI. A number will be appended.
49 static char szSuffix[] = "0"; // Printable char that is appended to szName.
50
51 usDataPort = 0x300;
52 usStatPort = 0x300 + 1;
53
54 // RTMIDI (MIDI.SYS) related stuff
55 ++szSuffix[0]; // Bump number in instance name.
56 strcpy( szRTMIDI_Name, szName ); // Setup instance name.
57 strcat( szRTMIDI_Name, szSuffix ); // Append ASCII number to instance name.
58 ulRTMIDI_Caps = MIDICAPSA_INPUT; // Set RTMIDI caps.
59 // When we have an IRQ and a send capability, add next line.
60 // ulCapabilities |= MIDICAPSA_OUTPUT;
61}
62
63
64#define TIMEOUT 60000
65
66unsigned MPUcommand(USHORT usDataPort, BYTE b)
67/* Returns 0 when command is properly accepted by the specified port;
68 * Returns 1 - 4 to indicate various timeout conditions.
69 */
70{
71 unsigned i;
72 const usStatPort = usDataPort + 1;
73
74 i=1000;
75 while (--i) {
76 if (inp(usStatPort) & DSR) break;
77 inp(usDataPort);
78 iodelay(1); // Delay >= 0.5 uSec
79 }
80 if ( !i ) { // >500 millisecond wait?
81 return 4;
82 }
83
84 for (i=0; i<TIMEOUT; i++) {
85 if (!(inp(usStatPort) & DRR)) { // wait until it's ready
86 iodelay(1); // just to be safe
87 outp(usStatPort,b);
88 iodelay(1); // just to be safe
89 for (i=0; i<TIMEOUT; i++) {
90 if (!(inp(usStatPort) & DSR)) {
91 iodelay(1); // just to be safe
92 i=inp(usDataPort);
93 if (i == 0xFE)
94 return 0;
95 else {
96 return 3;
97 }
98 }
99 iodelay(1);
100 }
101 if (b == 0xFF) {
102 return 0;
103 }
104 else {
105 return 1;
106 }
107 }
108 iodelay(1);
109 }
110
111 return 2;
112}
113
114virtual void MPU_401::noteOff( BYTE mchan, BYTE note, BYTE velocity )
115{
116 writeByte( (BYTE) 0x80 | mchan );
117 writeByte( note );
118 writeByte( velocity );
119}
120
121virtual void MPU_401::noteOn( BYTE mchan, BYTE note, BYTE velocity )
122{
123 writeByte( (BYTE) 0x90 | mchan );
124 writeByte( note );
125 writeByte( velocity );
126}
127
128virtual void MPU_401::polyphonicPressure( BYTE mchan, BYTE note, BYTE value )
129{
130 writeByte( (BYTE) 0xA0 | mchan );
131 writeByte( note );
132 writeByte( value );
133}
134
135virtual void MPU_401::controlChange( BYTE mchan, BYTE control_number, BYTE value )
136{
137 writeByte( (BYTE) 0xB0 | mchan );
138 writeByte( control_number );
139 writeByte( value );
140}
141
142virtual void MPU_401::programChange( BYTE mchan, BYTE program_number )
143{
144 writeByte( (BYTE) 0xC0 | mchan );
145 writeByte( program_number );
146}
147
148virtual void MPU_401::channelPressure( BYTE mchan, BYTE value )
149{
150 writeByte( (BYTE) 0xD0 | mchan );
151 writeByte( value );
152}
153
154virtual void MPU_401::pitchBend( BYTE mchan, BYTE value_lsb, BYTE value_msb )
155{
156 writeByte( (BYTE) 0xE0 | mchan );
157 writeByte( value_lsb );
158 writeByte( value_msb );
159}
160
161
162int MPU_401::_iAllNotesOff(void)
163{
164 for (int iChannel=0; iChannel<16; iChannel++) {
165 writeByte((BYTE) (0xB0 + iChannel)); // channel mode
166 writeByte(123); // all notes off
167 writeByte(0);
168 }
169
170 return TRUE;
171}
172
173
174int MPU_401::writeByte(BYTE b)
175{
176 unsigned i;
177
178 for (i=0; i<TIMEOUT; i++) {
179 cli();
180 if (!(inp(usStatPort) & DRR)) {
181 outp(usDataPort, b);
182 sti();
183 return 1;
184 }
185 sti();
186 iodelay(1);
187 }
188 return 0;
189}
190
191int MPU_401::readByte(void)
192{
193 unsigned i;
194
195 for (i=0; i<TIMEOUT; i++) {
196 cli();
197 if (!(inp(usStatPort) & DSR)) {
198 i=inp(usDataPort);
199 sti();
200 return i;
201 }
202 sti();
203 iodelay(1);
204 }
205 return -1;
206}
207
208/* MPU_401::_iInitialize
209 * ### Need cleanup return codes - currently they are not consistent
210 * ### or documented. Currently, returns 0 on SUCCESS.
211 */
212int MPU_401::_iInitialize(void)
213{
214 int rc; // Return code from MPUcommand().
215
216 rc = MPUcommand(usDataPort, 0xFF);
217 if (rc == 0)
218 rc = MPUcommand(usDataPort, 0x3F);
219
220 return rc;
221}
222
223#pragma off (unreferenced)
224
225int MPU_401::Reset(STREAM *stream)
226{
227 return 0;
228}
229
230int MPU_401::Start( STREAM *stream )
231{
232 BOOL rc;
233 _iInitialize();
234
235 // Start timer on 4 mSec interval.
236 rc = getTimer()->Start();
237 return rc;
238}
239
240
241int MPU_401::Stop(STREAM *stream)
242{
243 getTimer()->Stop();
244 _iAllNotesOff();
245 return 0;
246}
247
248
249int MPU_401::Pause(STREAM *stream)
250{
251 getTimer()->Pause();
252 _iAllNotesOff();
253 return 0;
254}
255
256
257int MPU_401::Resume(STREAM *stream)
258{
259 getTimer()->Resume();
260 return 0;
261}
262
263USHORT MPU_401::RTMIDI_OpenReceive(void)
264{
265 //### Need to add serialization b/t MMPM/2 + RTMIDI, plus mult RTMIDI opens.
266
267 USHORT us = _iInitialize();
268 if (us)
269 return MIDIERRA_HW_FAILED;
270 else
271 return 0;
272}
273
274USHORT MPU_401::RTMIDI_OpenSend(void)
275{
276 //### Need to add serialization b/t MMPM/2 + RTMIDI, plus mult RTMIDI opens.
277 //### Send capability pending but not currently implemented.
278
279 return MIDIERRA_HW_FAILED;
280}
281
282USHORT MPU_401::RTMIDI_CloseReceive(void)
283{
284 MPUcommand(usDataPort, 0xFF);
285 return 0;
286}
287
288USHORT MPU_401::RTMIDI_CloseSend(void)
289{
290 MPUcommand(usDataPort, 0xFF);
291 return 0;
292}
293
Note: See TracBrowser for help on using the repository browser.