linux/sound/oss/uart401.c
<<
>>
Prefs
   1/*
   2 * sound/oss/uart401.c
   3 *
   4 * MPU-401 UART driver (formerly uart401_midi.c)
   5 *
   6 *
   7 * Copyright (C) by Hannu Savolainen 1993-1997
   8 *
   9 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  10 * Version 2 (June 1991). See the "COPYING" file distributed with this software
  11 * for more info.
  12 *
  13 * Changes:
  14 *      Alan Cox                Reformatted, removed sound_mem usage, use normal Linux
  15 *                              interrupt allocation. Protect against bogus unload
  16 *                              Fixed to allow IRQ > 15
  17 *      Christoph Hellwig       Adapted to module_init/module_exit
  18 *      Arnaldo C. de Melo      got rid of check_region
  19 *
  20 * Status:
  21 *              Untested
  22 */
  23
  24#include <linux/init.h>
  25#include <linux/interrupt.h>
  26#include <linux/module.h>
  27#include <linux/slab.h>
  28#include <linux/spinlock.h>
  29#include "sound_config.h"
  30
  31#include "mpu401.h"
  32
  33typedef struct uart401_devc
  34{
  35        int             base;
  36        int             irq;
  37        int            *osp;
  38        void            (*midi_input_intr) (int dev, unsigned char data);
  39        int             opened, disabled;
  40        volatile unsigned char input_byte;
  41        int             my_dev;
  42        int             share_irq;
  43        spinlock_t      lock;
  44}
  45uart401_devc;
  46
  47#define DATAPORT   (devc->base)
  48#define COMDPORT   (devc->base+1)
  49#define STATPORT   (devc->base+1)
  50
  51static int uart401_status(uart401_devc * devc)
  52{
  53        return inb(STATPORT);
  54}
  55
  56#define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL))
  57#define output_ready(devc)      (!(uart401_status(devc)&OUTPUT_READY))
  58
  59static void uart401_cmd(uart401_devc * devc, unsigned char cmd)
  60{
  61        outb((cmd), COMDPORT);
  62}
  63
  64static int uart401_read(uart401_devc * devc)
  65{
  66        return inb(DATAPORT);
  67}
  68
  69static void uart401_write(uart401_devc * devc, unsigned char byte)
  70{
  71        outb((byte), DATAPORT);
  72}
  73
  74#define OUTPUT_READY    0x40
  75#define INPUT_AVAIL     0x80
  76#define MPU_ACK         0xFE
  77#define MPU_RESET       0xFF
  78#define UART_MODE_ON    0x3F
  79
  80static int      reset_uart401(uart401_devc * devc);
  81static void     enter_uart_mode(uart401_devc * devc);
  82
  83static void uart401_input_loop(uart401_devc * devc)
  84{
  85        int work_limit=30000;
  86        
  87        while (input_avail(devc) && --work_limit)
  88        {
  89                unsigned char   c = uart401_read(devc);
  90
  91                if (c == MPU_ACK)
  92                        devc->input_byte = c;
  93                else if (devc->opened & OPEN_READ && devc->midi_input_intr)
  94                        devc->midi_input_intr(devc->my_dev, c);
  95        }
  96        if(work_limit==0)
  97                printk(KERN_WARNING "Too much work in interrupt on uart401 (0x%X). UART jabbering ??\n", devc->base);
  98}
  99
 100irqreturn_t uart401intr(int irq, void *dev_id)
 101{
 102        uart401_devc *devc = dev_id;
 103
 104        if (devc == NULL)
 105        {
 106                printk(KERN_ERR "uart401: bad devc\n");
 107                return IRQ_NONE;
 108        }
 109
 110        if (input_avail(devc))
 111                uart401_input_loop(devc);
 112        return IRQ_HANDLED;
 113}
 114
 115static int
 116uart401_open(int dev, int mode,
 117             void            (*input) (int dev, unsigned char data),
 118             void            (*output) (int dev)
 119)
 120{
 121        uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
 122
 123        if (devc->opened)
 124                return -EBUSY;
 125
 126        /* Flush the UART */
 127        
 128        while (input_avail(devc))
 129                uart401_read(devc);
 130
 131        devc->midi_input_intr = input;
 132        devc->opened = mode;
 133        enter_uart_mode(devc);
 134        devc->disabled = 0;
 135
 136        return 0;
 137}
 138
 139static void uart401_close(int dev)
 140{
 141        uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
 142
 143        reset_uart401(devc);
 144        devc->opened = 0;
 145}
 146
 147static int uart401_out(int dev, unsigned char midi_byte)
 148{
 149        int timeout;
 150        unsigned long flags;
 151        uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
 152
 153        if (devc->disabled)
 154                return 1;
 155        /*
 156         * Test for input since pending input seems to block the output.
 157         */
 158
 159        spin_lock_irqsave(&devc->lock,flags);   
 160        if (input_avail(devc))
 161                uart401_input_loop(devc);
 162
 163        spin_unlock_irqrestore(&devc->lock,flags);
 164
 165        /*
 166         * Sometimes it takes about 13000 loops before the output becomes ready
 167         * (After reset). Normally it takes just about 10 loops.
 168         */
 169
 170        for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);
 171
 172        if (!output_ready(devc))
 173        {
 174                  printk(KERN_WARNING "uart401: Timeout - Device not responding\n");
 175                  devc->disabled = 1;
 176                  reset_uart401(devc);
 177                  enter_uart_mode(devc);
 178                  return 1;
 179        }
 180        uart401_write(devc, midi_byte);
 181        return 1;
 182}
 183
 184static inline int uart401_start_read(int dev)
 185{
 186        return 0;
 187}
 188
 189static inline int uart401_end_read(int dev)
 190{
 191        return 0;
 192}
 193
 194static inline void uart401_kick(int dev)
 195{
 196}
 197
 198static inline int uart401_buffer_status(int dev)
 199{
 200        return 0;
 201}
 202
 203#define MIDI_SYNTH_NAME "MPU-401 UART"
 204#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
 205#include "midi_synth.h"
 206
 207static const struct midi_operations uart401_operations =
 208{
 209        .owner          = THIS_MODULE,
 210        .info           = {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401},
 211        .converter      = &std_midi_synth,
 212        .in_info        = {0},
 213        .open           = uart401_open,
 214        .close          = uart401_close,
 215        .outputc        = uart401_out,
 216        .start_read     = uart401_start_read,
 217        .end_read       = uart401_end_read,
 218        .kick           = uart401_kick,
 219        .buffer_status  = uart401_buffer_status,
 220};
 221
 222static void enter_uart_mode(uart401_devc * devc)
 223{
 224        int ok, timeout;
 225        unsigned long flags;
 226
 227        spin_lock_irqsave(&devc->lock,flags);   
 228        for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);
 229
 230        devc->input_byte = 0;
 231        uart401_cmd(devc, UART_MODE_ON);
 232
 233        ok = 0;
 234        for (timeout = 50000; timeout > 0 && !ok; timeout--)
 235                if (devc->input_byte == MPU_ACK)
 236                        ok = 1;
 237                else if (input_avail(devc))
 238                        if (uart401_read(devc) == MPU_ACK)
 239                                ok = 1;
 240
 241        spin_unlock_irqrestore(&devc->lock,flags);
 242}
 243
 244static int reset_uart401(uart401_devc * devc)
 245{
 246        int ok, timeout, n;
 247
 248        /*
 249         * Send the RESET command. Try again if no success at the first time.
 250         */
 251
 252        ok = 0;
 253
 254        for (n = 0; n < 2 && !ok; n++)
 255        {
 256                for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);
 257                devc->input_byte = 0;
 258                uart401_cmd(devc, MPU_RESET);
 259
 260                /*
 261                 * Wait at least 25 msec. This method is not accurate so let's make the
 262                 * loop bit longer. Cannot sleep since this is called during boot.
 263                 */
 264
 265                for (timeout = 50000; timeout > 0 && !ok; timeout--)
 266                {
 267                        if (devc->input_byte == MPU_ACK)        /* Interrupt */
 268                                ok = 1;
 269                        else if (input_avail(devc))
 270                        {
 271                                if (uart401_read(devc) == MPU_ACK)
 272                                        ok = 1;
 273                        }
 274                }
 275        }
 276
 277
 278        if (ok)
 279        {
 280                DEB(printk("Reset UART401 OK\n"));
 281        }
 282        else
 283                DDB(printk("Reset UART401 failed - No hardware detected.\n"));
 284
 285        if (ok)
 286                uart401_input_loop(devc);       /*
 287                                                 * Flush input before enabling interrupts
 288                                                 */
 289
 290        return ok;
 291}
 292
 293int probe_uart401(struct address_info *hw_config, struct module *owner)
 294{
 295        uart401_devc *devc;
 296        char *name = "MPU-401 (UART) MIDI";
 297        int ok = 0;
 298        unsigned long flags;
 299
 300        DDB(printk("Entered probe_uart401()\n"));
 301
 302        /* Default to "not found" */
 303        hw_config->slots[4] = -1;
 304
 305        if (!request_region(hw_config->io_base, 4, "MPU-401 UART")) {
 306                printk(KERN_INFO "uart401: could not request_region(%d, 4)\n", hw_config->io_base);
 307                return 0;
 308        }
 309
 310        devc = kmalloc(sizeof(uart401_devc), GFP_KERNEL);
 311        if (!devc) {
 312                printk(KERN_WARNING "uart401: Can't allocate memory\n");
 313                goto cleanup_region;
 314        }
 315
 316        devc->base = hw_config->io_base;
 317        devc->irq = hw_config->irq;
 318        devc->osp = hw_config->osp;
 319        devc->midi_input_intr = NULL;
 320        devc->opened = 0;
 321        devc->input_byte = 0;
 322        devc->my_dev = 0;
 323        devc->share_irq = 0;
 324        spin_lock_init(&devc->lock);
 325
 326        spin_lock_irqsave(&devc->lock,flags);   
 327        ok = reset_uart401(devc);
 328        spin_unlock_irqrestore(&devc->lock,flags);
 329
 330        if (!ok)
 331                goto cleanup_devc;
 332
 333        if (hw_config->name)
 334                name = hw_config->name;
 335
 336        if (devc->irq < 0) {
 337                devc->share_irq = 1;
 338                devc->irq *= -1;
 339        } else
 340                devc->share_irq = 0;
 341
 342        if (!devc->share_irq)
 343                if (request_irq(devc->irq, uart401intr, 0, "MPU-401 UART", devc) < 0) {
 344                        printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq);
 345                        devc->share_irq = 1;
 346                }
 347        devc->my_dev = sound_alloc_mididev();
 348        enter_uart_mode(devc);
 349
 350        if (devc->my_dev == -1) {
 351                printk(KERN_INFO "uart401: Too many midi devices detected\n");
 352                goto cleanup_irq;
 353        }
 354        conf_printf(name, hw_config);
 355        midi_devs[devc->my_dev] = kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
 356        if (!midi_devs[devc->my_dev]) {
 357                printk(KERN_ERR "uart401: Failed to allocate memory\n");
 358                goto cleanup_unload_mididev;
 359        }
 360        memcpy(midi_devs[devc->my_dev], &uart401_operations, sizeof(struct midi_operations));
 361
 362        if (owner)
 363                midi_devs[devc->my_dev]->owner = owner;
 364        
 365        midi_devs[devc->my_dev]->devc = devc;
 366        midi_devs[devc->my_dev]->converter = kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
 367        if (!midi_devs[devc->my_dev]->converter) {
 368                printk(KERN_WARNING "uart401: Failed to allocate memory\n");
 369                goto cleanup_midi_devs;
 370        }
 371        memcpy(midi_devs[devc->my_dev]->converter, &std_midi_synth, sizeof(struct synth_operations));
 372        strcpy(midi_devs[devc->my_dev]->info.name, name);
 373        midi_devs[devc->my_dev]->converter->id = "UART401";
 374        midi_devs[devc->my_dev]->converter->midi_dev = devc->my_dev;
 375
 376        if (owner)
 377                midi_devs[devc->my_dev]->converter->owner = owner;
 378
 379        hw_config->slots[4] = devc->my_dev;
 380        sequencer_init();
 381        devc->opened = 0;
 382        return 1;
 383cleanup_midi_devs:
 384        kfree(midi_devs[devc->my_dev]);
 385cleanup_unload_mididev:
 386        sound_unload_mididev(devc->my_dev);
 387cleanup_irq:
 388        if (!devc->share_irq)
 389                free_irq(devc->irq, devc);
 390cleanup_devc:
 391        kfree(devc);
 392cleanup_region:
 393        release_region(hw_config->io_base, 4);
 394        return 0;
 395}
 396
 397void unload_uart401(struct address_info *hw_config)
 398{
 399        uart401_devc *devc;
 400        int n=hw_config->slots[4];
 401        
 402        /* Not set up */
 403        if(n==-1 || midi_devs[n]==NULL)
 404                return;
 405                
 406        /* Not allocated (erm ??) */
 407        
 408        devc = midi_devs[hw_config->slots[4]]->devc;
 409        if (devc == NULL)
 410                return;
 411
 412        reset_uart401(devc);
 413        release_region(hw_config->io_base, 4);
 414
 415        if (!devc->share_irq)
 416                free_irq(devc->irq, devc);
 417        if (devc)
 418        {
 419                kfree(midi_devs[devc->my_dev]->converter);
 420                kfree(midi_devs[devc->my_dev]);
 421                kfree(devc);
 422                devc = NULL;
 423        }
 424        /* This kills midi_devs[x] */
 425        sound_unload_mididev(hw_config->slots[4]);
 426}
 427
 428EXPORT_SYMBOL(probe_uart401);
 429EXPORT_SYMBOL(unload_uart401);
 430EXPORT_SYMBOL(uart401intr);
 431
 432static struct address_info cfg_mpu;
 433
 434static int io = -1;
 435static int irq = -1;
 436
 437module_param(io, int, 0444);
 438module_param(irq, int, 0444);
 439
 440
 441static int __init init_uart401(void)
 442{
 443        cfg_mpu.irq = irq;
 444        cfg_mpu.io_base = io;
 445
 446        /* Can be loaded either for module use or to provide functions
 447           to others */
 448        if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) {
 449                printk(KERN_INFO "MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997");
 450                if (!probe_uart401(&cfg_mpu, THIS_MODULE))
 451                        return -ENODEV;
 452        }
 453
 454        return 0;
 455}
 456
 457static void __exit cleanup_uart401(void)
 458{
 459        if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1)
 460                unload_uart401(&cfg_mpu);
 461}
 462
 463module_init(init_uart401);
 464module_exit(cleanup_uart401);
 465
 466#ifndef MODULE
 467static int __init setup_uart401(char *str)
 468{
 469        /* io, irq */
 470        int ints[3];
 471        
 472        str = get_options(str, ARRAY_SIZE(ints), ints);
 473
 474        io = ints[1];
 475        irq = ints[2];
 476        
 477        return 1;
 478}
 479
 480__setup("uart401=", setup_uart401);
 481#endif
 482MODULE_LICENSE("GPL");
 483
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.