source: cmedia/trunk/Sblive/midi.c@ 354

Last change on this file since 354 was 354, checked in by stevenhl, 17 years ago

Import untested baseline cmedia sources, work products and binaries
Binaries and work products should be deleted from repository.
once new builds are verified to work.

File size: 11.6 KB
Line 
1/* $Id: midi.c,v 1.2 2000/05/28 16:50:46 sandervl Exp $ */
2
3
4/*
5 **********************************************************************
6 * midi.c - /dev/midi interface for emu10k1 driver
7 * Copyright 1999, 2000 Creative Labs, Inc.
8 *
9 **********************************************************************
10 *
11 * Date Author Summary of changes
12 * ---- ------ ------------------
13 * October 20, 1999 Bertrand Lee base code release
14 *
15 **********************************************************************
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public
28 * License along with this program; if not, write to the Free
29 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
30 * USA.
31 *
32 **********************************************************************
33 */
34
35#define __NO_VERSION__
36#include <linux/module.h>
37#include <asm/uaccess.h>
38
39#include "hwaccess.h"
40#include "cardmo.h"
41#include "cardmi.h"
42#include "midi.h"
43
44static spinlock_t midi_spinlock = SPIN_LOCK_UNLOCKED;
45
46static void init_midi_hdr(struct midi_hdr *midihdr)
47{
48 midihdr->bufferlength = MIDIIN_BUFLEN;
49 midihdr->bytesrecorded = 0;
50 midihdr->flags = 0;
51}
52
53static int midiin_add_buffer(struct emu10k1_mididevice *midi_dev, struct midi_hdr **midihdrptr)
54{
55 struct midi_hdr *midihdr;
56
57#ifdef TARGET_OS2
58 if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL) {
59#else
60 if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL) {
61#endif
62 ERROR();
63 return -EINVAL;
64 }
65
66 init_midi_hdr(midihdr);
67
68 if ((midihdr->data = (u8 *) kmalloc(MIDIIN_BUFLEN, GFP_KERNEL)) == NULL) {
69 ERROR();
70 kfree(midihdr);
71 return CTSTATUS_ERROR;
72 }
73
74 if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) != CTSTATUS_SUCCESS) {
75 ERROR();
76 kfree(midihdr->data);
77 kfree(midihdr);
78 return CTSTATUS_ERROR;
79 }
80
81 *midihdrptr = midihdr;
82 list_add_tail(&midihdr->list, &midi_dev->mid_hdrs);
83
84 return CTSTATUS_SUCCESS;
85}
86
87static int emu10k1_midi_open(struct inode *inode, struct file *file)
88{
89 int minor = MINOR(inode->i_rdev);
90 struct emu10k1_card *card;
91 struct emu10k1_mididevice *midi_dev;
92 struct list_head *entry;
93
94 DPF(2, "emu10k1_midi_open()\n");
95
96 /* Check for correct device to open */
97 list_for_each(entry, &emu10k1_devs) {
98 card = list_entry(entry, struct emu10k1_card, list);
99
100 if (card->midi_num == minor)
101 break;
102 }
103
104 if (entry == &emu10k1_devs)
105 return -ENODEV;
106
107 MOD_INC_USE_COUNT;
108
109 /* Wait for device to become free */
110 down(&card->open_sem);
111 while (card->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
112 if (file->f_flags & O_NONBLOCK) {
113 up(&card->open_sem);
114 MOD_DEC_USE_COUNT;
115 return -EBUSY;
116 }
117
118 up(&card->open_sem);
119 interruptible_sleep_on(&card->open_wait);
120
121 if (signal_pending(current)) {
122 MOD_DEC_USE_COUNT;
123 return -ERESTARTSYS;
124 }
125
126 down(&card->open_sem);
127 }
128
129 if ((midi_dev = (struct emu10k1_mididevice *) kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL) {
130 MOD_DEC_USE_COUNT;
131 return -EINVAL;
132 }
133
134 midi_dev->card = card;
135 midi_dev->mistate = MIDIIN_STATE_STOPPED;
136 init_waitqueue_head(&midi_dev->oWait);
137 init_waitqueue_head(&midi_dev->iWait);
138 midi_dev->ird = 0;
139 midi_dev->iwr = 0;
140 midi_dev->icnt = 0;
141 INIT_LIST_HEAD(&midi_dev->mid_hdrs);
142
143 if (file->f_mode & FMODE_READ) {
144 struct midi_openinfo dsCardMidiOpenInfo;
145 struct midi_hdr *midihdr1;
146 struct midi_hdr *midihdr2;
147
148 dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
149
150 if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo)
151 != CTSTATUS_SUCCESS) {
152 ERROR();
153 kfree(midi_dev);
154 MOD_DEC_USE_COUNT;
155 return -ENODEV;
156 }
157
158 /* Add two buffers to receive sysex buffer */
159 if (midiin_add_buffer(midi_dev, &midihdr1) != CTSTATUS_SUCCESS) {
160 kfree(midi_dev);
161 MOD_DEC_USE_COUNT;
162 return -ENODEV;
163 }
164
165 if (midiin_add_buffer(midi_dev, &midihdr2) != CTSTATUS_SUCCESS) {
166 list_del(&midihdr1->list);
167 kfree(midihdr1->data);
168 kfree(midihdr1);
169 kfree(midi_dev);
170 MOD_DEC_USE_COUNT;
171 return -ENODEV;
172 }
173 }
174
175 if (file->f_mode & FMODE_WRITE) {
176 struct midi_openinfo dsCardMidiOpenInfo;
177
178 dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
179
180 if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo)
181 != CTSTATUS_SUCCESS) {
182 ERROR();
183 kfree(midi_dev);
184 MOD_DEC_USE_COUNT;
185 return -ENODEV;
186 }
187 }
188
189 file->private_data = (void *) midi_dev;
190
191 card->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
192
193 up(&card->open_sem);
194
195 return 0;
196}
197
198static int emu10k1_midi_release(struct inode *inode, struct file *file)
199{
200 struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
201 struct emu10k1_card *card = midi_dev->card;
202
203 DPF(2, "emu10k1_midi_release()\n");
204
205 if (file->f_mode & FMODE_WRITE) {
206 if (!(file->f_flags & O_NONBLOCK)) {
207
208 while (!signal_pending(current) && (card->mpuout->firstmidiq != NULL)) {
209 DPF(4, "Cannot close - buffers not empty\n");
210
211 interruptible_sleep_on(&midi_dev->oWait);
212
213 }
214 }
215
216 emu10k1_mpuout_close(card);
217 }
218
219 if (file->f_mode & FMODE_READ) {
220 struct midi_hdr *midihdr;
221
222 if (midi_dev->mistate == MIDIIN_STATE_STARTED) {
223 emu10k1_mpuin_stop(card);
224 midi_dev->mistate = MIDIIN_STATE_STOPPED;
225 }
226
227 emu10k1_mpuin_reset(card);
228 emu10k1_mpuin_close(card);
229
230 while (!list_empty(&midi_dev->mid_hdrs)) {
231 midihdr = list_entry(midi_dev->mid_hdrs.next, struct midi_hdr, list);
232
233 list_del(midi_dev->mid_hdrs.next);
234 kfree(midihdr->data);
235 kfree(midihdr);
236 }
237 }
238
239 kfree(midi_dev);
240
241 down(&card->open_sem);
242 card->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE));
243 up(&card->open_sem);
244 wake_up_interruptible(&card->open_wait);
245
246 MOD_DEC_USE_COUNT;
247
248 return 0;
249}
250
251static ssize_t emu10k1_midi_read(struct file *file, char *buffer, size_t count, loff_t * pos)
252{
253 struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
254 ssize_t ret = 0;
255 u16 cnt;
256 unsigned long flags;
257
258 DPD(4, "emu10k1_midi_read(), count %x\n", (u32) count);
259
260 if (pos != &file->f_pos)
261 return -ESPIPE;
262
263 if (!access_ok(VERIFY_WRITE, buffer, count))
264 return -EFAULT;
265
266 if (midi_dev->mistate == MIDIIN_STATE_STOPPED) {
267 if (emu10k1_mpuin_start(midi_dev->card)
268 != CTSTATUS_SUCCESS) {
269 ERROR();
270 return -EINVAL;
271 }
272
273 midi_dev->mistate = MIDIIN_STATE_STARTED;
274 }
275
276 while (count > 0) {
277 cnt = MIDIIN_BUFLEN - midi_dev->ird;
278
279 spin_lock_irqsave(&midi_spinlock, flags);
280
281 if (midi_dev->icnt < cnt)
282 cnt = midi_dev->icnt;
283
284 spin_unlock_irqrestore(&midi_spinlock, flags);
285
286 if (cnt > count)
287 cnt = count;
288
289 if (cnt <= 0) {
290 if (file->f_flags & O_NONBLOCK)
291 return ret ? ret : -EAGAIN;
292 DPF(2, " Go to sleep...\n");
293
294 interruptible_sleep_on(&midi_dev->iWait);
295
296 if (signal_pending(current))
297 return ret ? ret : -ERESTARTSYS;
298
299 continue;
300 }
301
302 if (copy_to_user(buffer, midi_dev->iBuf + midi_dev->ird, cnt)) {
303 ERROR();
304 return ret ? ret : -EFAULT;
305 }
306
307 midi_dev->ird += cnt;
308 midi_dev->ird %= MIDIIN_BUFLEN;
309
310 spin_lock_irqsave(&midi_spinlock, flags);
311
312 midi_dev->icnt -= cnt;
313
314 spin_unlock_irqrestore(&midi_spinlock, flags);
315
316 count -= cnt;
317 buffer += cnt;
318 ret += cnt;
319
320 if (midi_dev->icnt == 0)
321 break;
322 }
323
324 return ret;
325}
326
327static ssize_t emu10k1_midi_write(struct file *file, const char *buffer, size_t count, loff_t * pos)
328{
329 struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
330 struct midi_hdr *midihdr;
331 ssize_t ret = 0;
332 unsigned long flags;
333
334 DPD(4, "emu10k1_midi_write(), count=%x\n", (u32) count);
335
336 if (pos != &file->f_pos)
337 return -ESPIPE;
338
339 if (!access_ok(VERIFY_READ, buffer, count))
340 return -EFAULT;
341
342#ifdef TARGET_OS2
343 if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL)
344#else
345 if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL)
346#endif
347 return -EINVAL;
348
349 midihdr->bufferlength = count;
350 midihdr->bytesrecorded = 0;
351 midihdr->flags = 0;
352
353 if ((midihdr->data = (u8 *) kmalloc(count, GFP_KERNEL)) == NULL) {
354 ERROR();
355 kfree(midihdr);
356 return -EINVAL;
357 }
358
359 if (copy_from_user(midihdr->data, buffer, count)) {
360 kfree(midihdr->data);
361 kfree(midihdr);
362 return ret ? ret : -EFAULT;
363 }
364
365 spin_lock_irqsave(&midi_spinlock, flags);
366
367 if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) != CTSTATUS_SUCCESS) {
368 ERROR();
369 kfree(midihdr->data);
370 kfree(midihdr);
371 spin_unlock_irqrestore(&midi_spinlock, flags);
372 return -EINVAL;
373 }
374
375 spin_unlock_irqrestore(&midi_spinlock, flags);
376
377 return count;
378}
379
380static unsigned int emu10k1_midi_poll(struct file *file, struct poll_table_struct *wait)
381{
382 DPF(4, "emu10k1_midi_poll() called\n");
383 return 0;
384}
385
386int emu10k1_midi_callback(unsigned long msg, unsigned long refdata, unsigned long *pmsg)
387{
388 struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) refdata;
389 struct midi_hdr *midihdr = NULL;
390 unsigned long flags;
391 int i;
392
393 DPF(4, "emu10k1_midi_callback()\n");
394
395 spin_lock_irqsave(&midi_spinlock, flags);
396
397 switch (msg) {
398 case ICARDMIDI_OUTLONGDATA:
399 midihdr = (struct midi_hdr *) pmsg[2];
400
401 kfree(midihdr->data);
402 kfree(midihdr);
403 wake_up_interruptible(&midi_dev->oWait);
404
405 break;
406
407 case ICARDMIDI_INLONGDATA:
408 midihdr = (struct midi_hdr *) pmsg[2];
409
410 for (i = 0; i < midihdr->bytesrecorded; i++) {
411 midi_dev->iBuf[midi_dev->iwr++] = midihdr->data[i];
412 midi_dev->iwr %= MIDIIN_BUFLEN;
413 }
414
415 midi_dev->icnt += midihdr->bytesrecorded;
416
417 if (midi_dev->mistate == MIDIIN_STATE_STARTED) {
418 init_midi_hdr(midihdr);
419 emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr);
420 wake_up_interruptible(&midi_dev->iWait);
421 }
422 break;
423
424 case ICARDMIDI_INDATA:
425 {
426 u8 *pBuf = (u8 *) & pmsg[1];
427 u16 bytesvalid = pmsg[2];
428
429 for (i = 0; i < bytesvalid; i++) {
430 midi_dev->iBuf[midi_dev->iwr++] = pBuf[i];
431 midi_dev->iwr %= MIDIIN_BUFLEN;
432 }
433
434 midi_dev->icnt += bytesvalid;
435 }
436
437 wake_up_interruptible(&midi_dev->iWait);
438 break;
439
440 default: /* Unknown message */
441 return CTSTATUS_ERROR;
442 }
443
444 spin_unlock_irqrestore(&midi_spinlock, flags);
445
446 return CTSTATUS_SUCCESS;
447}
448
449/* MIDI file operations */
450#ifdef TARGET_OS2
451//Hello!?! Use standard C!
452struct file_operations emu10k1_midi_fops =
453{
454 NULL,
455 &emu10k1_midi_read,
456 &emu10k1_midi_write,
457 NULL, /* readdir */
458 &emu10k1_midi_poll,
459 NULL, /* ioctl */
460 NULL, /* mmap */
461 &emu10k1_midi_open,
462#if LINUX_VERSION_CODE >= 0x020100
463 NULL, /* flush */
464#endif
465 &emu10k1_midi_release,
466 NULL, /* fsync */
467 NULL, /* fasync */
468 NULL, /* check_media_change */
469#if LINUX_VERSION_CODE >= 0x020100
470 NULL, /* revalidate */
471 NULL /* lock */
472#endif
473};
474#else
475struct file_operations emu10k1_midi_fops = {
476 read:emu10k1_midi_read,
477 write:emu10k1_midi_write,
478 poll:emu10k1_midi_poll,
479 open:emu10k1_midi_open,
480 release:emu10k1_midi_release,
481};
482#endif
Note: See TracBrowser for help on using the repository browser.