mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 17:18:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
480
sound/oss/uart401.c
Normal file
480
sound/oss/uart401.c
Normal file
|
@ -0,0 +1,480 @@
|
|||
/*
|
||||
* sound/oss/uart401.c
|
||||
*
|
||||
* MPU-401 UART driver (formerly uart401_midi.c)
|
||||
*
|
||||
*
|
||||
* Copyright (C) by Hannu Savolainen 1993-1997
|
||||
*
|
||||
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
|
||||
* Version 2 (June 1991). See the "COPYING" file distributed with this software
|
||||
* for more info.
|
||||
*
|
||||
* Changes:
|
||||
* Alan Cox Reformatted, removed sound_mem usage, use normal Linux
|
||||
* interrupt allocation. Protect against bogus unload
|
||||
* Fixed to allow IRQ > 15
|
||||
* Christoph Hellwig Adapted to module_init/module_exit
|
||||
* Arnaldo C. de Melo got rid of check_region
|
||||
*
|
||||
* Status:
|
||||
* Untested
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include "sound_config.h"
|
||||
|
||||
#include "mpu401.h"
|
||||
|
||||
struct uart401_devc
|
||||
{
|
||||
int base;
|
||||
int irq;
|
||||
int *osp;
|
||||
void (*midi_input_intr) (int dev, unsigned char data);
|
||||
int opened, disabled;
|
||||
volatile unsigned char input_byte;
|
||||
int my_dev;
|
||||
int share_irq;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
#define DATAPORT (devc->base)
|
||||
#define COMDPORT (devc->base+1)
|
||||
#define STATPORT (devc->base+1)
|
||||
|
||||
static int uart401_status(struct uart401_devc *devc)
|
||||
{
|
||||
return inb(STATPORT);
|
||||
}
|
||||
|
||||
#define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL))
|
||||
#define output_ready(devc) (!(uart401_status(devc)&OUTPUT_READY))
|
||||
|
||||
static void uart401_cmd(struct uart401_devc *devc, unsigned char cmd)
|
||||
{
|
||||
outb((cmd), COMDPORT);
|
||||
}
|
||||
|
||||
static int uart401_read(struct uart401_devc *devc)
|
||||
{
|
||||
return inb(DATAPORT);
|
||||
}
|
||||
|
||||
static void uart401_write(struct uart401_devc *devc, unsigned char byte)
|
||||
{
|
||||
outb((byte), DATAPORT);
|
||||
}
|
||||
|
||||
#define OUTPUT_READY 0x40
|
||||
#define INPUT_AVAIL 0x80
|
||||
#define MPU_ACK 0xFE
|
||||
#define MPU_RESET 0xFF
|
||||
#define UART_MODE_ON 0x3F
|
||||
|
||||
static int reset_uart401(struct uart401_devc *devc);
|
||||
static void enter_uart_mode(struct uart401_devc *devc);
|
||||
|
||||
static void uart401_input_loop(struct uart401_devc *devc)
|
||||
{
|
||||
int work_limit=30000;
|
||||
|
||||
while (input_avail(devc) && --work_limit)
|
||||
{
|
||||
unsigned char c = uart401_read(devc);
|
||||
|
||||
if (c == MPU_ACK)
|
||||
devc->input_byte = c;
|
||||
else if (devc->opened & OPEN_READ && devc->midi_input_intr)
|
||||
devc->midi_input_intr(devc->my_dev, c);
|
||||
}
|
||||
if(work_limit==0)
|
||||
printk(KERN_WARNING "Too much work in interrupt on uart401 (0x%X). UART jabbering ??\n", devc->base);
|
||||
}
|
||||
|
||||
irqreturn_t uart401intr(int irq, void *dev_id)
|
||||
{
|
||||
struct uart401_devc *devc = dev_id;
|
||||
|
||||
if (devc == NULL)
|
||||
{
|
||||
printk(KERN_ERR "uart401: bad devc\n");
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (input_avail(devc))
|
||||
uart401_input_loop(devc);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int
|
||||
uart401_open(int dev, int mode,
|
||||
void (*input) (int dev, unsigned char data),
|
||||
void (*output) (int dev)
|
||||
)
|
||||
{
|
||||
struct uart401_devc *devc = (struct uart401_devc *)
|
||||
midi_devs[dev]->devc;
|
||||
|
||||
if (devc->opened)
|
||||
return -EBUSY;
|
||||
|
||||
/* Flush the UART */
|
||||
|
||||
while (input_avail(devc))
|
||||
uart401_read(devc);
|
||||
|
||||
devc->midi_input_intr = input;
|
||||
devc->opened = mode;
|
||||
enter_uart_mode(devc);
|
||||
devc->disabled = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uart401_close(int dev)
|
||||
{
|
||||
struct uart401_devc *devc = (struct uart401_devc *)
|
||||
midi_devs[dev]->devc;
|
||||
|
||||
reset_uart401(devc);
|
||||
devc->opened = 0;
|
||||
}
|
||||
|
||||
static int uart401_out(int dev, unsigned char midi_byte)
|
||||
{
|
||||
int timeout;
|
||||
unsigned long flags;
|
||||
struct uart401_devc *devc = (struct uart401_devc *)
|
||||
midi_devs[dev]->devc;
|
||||
|
||||
if (devc->disabled)
|
||||
return 1;
|
||||
/*
|
||||
* Test for input since pending input seems to block the output.
|
||||
*/
|
||||
|
||||
spin_lock_irqsave(&devc->lock,flags);
|
||||
if (input_avail(devc))
|
||||
uart401_input_loop(devc);
|
||||
|
||||
spin_unlock_irqrestore(&devc->lock,flags);
|
||||
|
||||
/*
|
||||
* Sometimes it takes about 13000 loops before the output becomes ready
|
||||
* (After reset). Normally it takes just about 10 loops.
|
||||
*/
|
||||
|
||||
for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);
|
||||
|
||||
if (!output_ready(devc))
|
||||
{
|
||||
printk(KERN_WARNING "uart401: Timeout - Device not responding\n");
|
||||
devc->disabled = 1;
|
||||
reset_uart401(devc);
|
||||
enter_uart_mode(devc);
|
||||
return 1;
|
||||
}
|
||||
uart401_write(devc, midi_byte);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int uart401_start_read(int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int uart401_end_read(int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void uart401_kick(int dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int uart401_buffer_status(int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MIDI_SYNTH_NAME "MPU-401 UART"
|
||||
#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
|
||||
#include "midi_synth.h"
|
||||
|
||||
static const struct midi_operations uart401_operations =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.info = {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401},
|
||||
.converter = &std_midi_synth,
|
||||
.in_info = {0},
|
||||
.open = uart401_open,
|
||||
.close = uart401_close,
|
||||
.outputc = uart401_out,
|
||||
.start_read = uart401_start_read,
|
||||
.end_read = uart401_end_read,
|
||||
.kick = uart401_kick,
|
||||
.buffer_status = uart401_buffer_status,
|
||||
};
|
||||
|
||||
static void enter_uart_mode(struct uart401_devc *devc)
|
||||
{
|
||||
int ok, timeout;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&devc->lock,flags);
|
||||
for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);
|
||||
|
||||
devc->input_byte = 0;
|
||||
uart401_cmd(devc, UART_MODE_ON);
|
||||
|
||||
ok = 0;
|
||||
for (timeout = 50000; timeout > 0 && !ok; timeout--)
|
||||
if (devc->input_byte == MPU_ACK)
|
||||
ok = 1;
|
||||
else if (input_avail(devc))
|
||||
if (uart401_read(devc) == MPU_ACK)
|
||||
ok = 1;
|
||||
|
||||
spin_unlock_irqrestore(&devc->lock,flags);
|
||||
}
|
||||
|
||||
static int reset_uart401(struct uart401_devc *devc)
|
||||
{
|
||||
int ok, timeout, n;
|
||||
|
||||
/*
|
||||
* Send the RESET command. Try again if no success at the first time.
|
||||
*/
|
||||
|
||||
ok = 0;
|
||||
|
||||
for (n = 0; n < 2 && !ok; n++)
|
||||
{
|
||||
for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);
|
||||
devc->input_byte = 0;
|
||||
uart401_cmd(devc, MPU_RESET);
|
||||
|
||||
/*
|
||||
* Wait at least 25 msec. This method is not accurate so let's make the
|
||||
* loop bit longer. Cannot sleep since this is called during boot.
|
||||
*/
|
||||
|
||||
for (timeout = 50000; timeout > 0 && !ok; timeout--)
|
||||
{
|
||||
if (devc->input_byte == MPU_ACK) /* Interrupt */
|
||||
ok = 1;
|
||||
else if (input_avail(devc))
|
||||
{
|
||||
if (uart401_read(devc) == MPU_ACK)
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Flush input before enabling interrupts */
|
||||
if (ok)
|
||||
uart401_input_loop(devc);
|
||||
else
|
||||
DDB(printk("Reset UART401 failed - No hardware detected.\n"));
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
int probe_uart401(struct address_info *hw_config, struct module *owner)
|
||||
{
|
||||
struct uart401_devc *devc;
|
||||
char *name = "MPU-401 (UART) MIDI";
|
||||
int ok = 0;
|
||||
unsigned long flags;
|
||||
|
||||
DDB(printk("Entered probe_uart401()\n"));
|
||||
|
||||
/* Default to "not found" */
|
||||
hw_config->slots[4] = -1;
|
||||
|
||||
if (!request_region(hw_config->io_base, 4, "MPU-401 UART")) {
|
||||
printk(KERN_INFO "uart401: could not request_region(%d, 4)\n", hw_config->io_base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
devc = kmalloc(sizeof(struct uart401_devc), GFP_KERNEL);
|
||||
if (!devc) {
|
||||
printk(KERN_WARNING "uart401: Can't allocate memory\n");
|
||||
goto cleanup_region;
|
||||
}
|
||||
|
||||
devc->base = hw_config->io_base;
|
||||
devc->irq = hw_config->irq;
|
||||
devc->osp = hw_config->osp;
|
||||
devc->midi_input_intr = NULL;
|
||||
devc->opened = 0;
|
||||
devc->input_byte = 0;
|
||||
devc->my_dev = 0;
|
||||
devc->share_irq = 0;
|
||||
spin_lock_init(&devc->lock);
|
||||
|
||||
spin_lock_irqsave(&devc->lock,flags);
|
||||
ok = reset_uart401(devc);
|
||||
spin_unlock_irqrestore(&devc->lock,flags);
|
||||
|
||||
if (!ok)
|
||||
goto cleanup_devc;
|
||||
|
||||
if (hw_config->name)
|
||||
name = hw_config->name;
|
||||
|
||||
if (devc->irq < 0) {
|
||||
devc->share_irq = 1;
|
||||
devc->irq *= -1;
|
||||
} else
|
||||
devc->share_irq = 0;
|
||||
|
||||
if (!devc->share_irq)
|
||||
if (request_irq(devc->irq, uart401intr, 0, "MPU-401 UART", devc) < 0) {
|
||||
printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq);
|
||||
devc->share_irq = 1;
|
||||
}
|
||||
devc->my_dev = sound_alloc_mididev();
|
||||
enter_uart_mode(devc);
|
||||
|
||||
if (devc->my_dev == -1) {
|
||||
printk(KERN_INFO "uart401: Too many midi devices detected\n");
|
||||
goto cleanup_irq;
|
||||
}
|
||||
conf_printf(name, hw_config);
|
||||
midi_devs[devc->my_dev] = kmemdup(&uart401_operations,
|
||||
sizeof(struct midi_operations),
|
||||
GFP_KERNEL);
|
||||
if (!midi_devs[devc->my_dev]) {
|
||||
printk(KERN_ERR "uart401: Failed to allocate memory\n");
|
||||
goto cleanup_unload_mididev;
|
||||
}
|
||||
|
||||
if (owner)
|
||||
midi_devs[devc->my_dev]->owner = owner;
|
||||
|
||||
midi_devs[devc->my_dev]->devc = devc;
|
||||
midi_devs[devc->my_dev]->converter = kmemdup(&std_midi_synth,
|
||||
sizeof(struct synth_operations),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!midi_devs[devc->my_dev]->converter) {
|
||||
printk(KERN_WARNING "uart401: Failed to allocate memory\n");
|
||||
goto cleanup_midi_devs;
|
||||
}
|
||||
strcpy(midi_devs[devc->my_dev]->info.name, name);
|
||||
midi_devs[devc->my_dev]->converter->id = "UART401";
|
||||
midi_devs[devc->my_dev]->converter->midi_dev = devc->my_dev;
|
||||
|
||||
if (owner)
|
||||
midi_devs[devc->my_dev]->converter->owner = owner;
|
||||
|
||||
hw_config->slots[4] = devc->my_dev;
|
||||
sequencer_init();
|
||||
devc->opened = 0;
|
||||
return 1;
|
||||
cleanup_midi_devs:
|
||||
kfree(midi_devs[devc->my_dev]);
|
||||
cleanup_unload_mididev:
|
||||
sound_unload_mididev(devc->my_dev);
|
||||
cleanup_irq:
|
||||
if (!devc->share_irq)
|
||||
free_irq(devc->irq, devc);
|
||||
cleanup_devc:
|
||||
kfree(devc);
|
||||
cleanup_region:
|
||||
release_region(hw_config->io_base, 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void unload_uart401(struct address_info *hw_config)
|
||||
{
|
||||
struct uart401_devc *devc;
|
||||
int n=hw_config->slots[4];
|
||||
|
||||
/* Not set up */
|
||||
if(n==-1 || midi_devs[n]==NULL)
|
||||
return;
|
||||
|
||||
/* Not allocated (erm ??) */
|
||||
|
||||
devc = midi_devs[hw_config->slots[4]]->devc;
|
||||
if (devc == NULL)
|
||||
return;
|
||||
|
||||
reset_uart401(devc);
|
||||
release_region(hw_config->io_base, 4);
|
||||
|
||||
if (!devc->share_irq)
|
||||
free_irq(devc->irq, devc);
|
||||
if (devc)
|
||||
{
|
||||
kfree(midi_devs[devc->my_dev]->converter);
|
||||
kfree(midi_devs[devc->my_dev]);
|
||||
kfree(devc);
|
||||
devc = NULL;
|
||||
}
|
||||
/* This kills midi_devs[x] */
|
||||
sound_unload_mididev(hw_config->slots[4]);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(probe_uart401);
|
||||
EXPORT_SYMBOL(unload_uart401);
|
||||
EXPORT_SYMBOL(uart401intr);
|
||||
|
||||
static struct address_info cfg_mpu;
|
||||
|
||||
static int io = -1;
|
||||
static int irq = -1;
|
||||
|
||||
module_param(io, int, 0444);
|
||||
module_param(irq, int, 0444);
|
||||
|
||||
|
||||
static int __init init_uart401(void)
|
||||
{
|
||||
cfg_mpu.irq = irq;
|
||||
cfg_mpu.io_base = io;
|
||||
|
||||
/* Can be loaded either for module use or to provide functions
|
||||
to others */
|
||||
if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) {
|
||||
printk(KERN_INFO "MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997");
|
||||
if (!probe_uart401(&cfg_mpu, THIS_MODULE))
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cleanup_uart401(void)
|
||||
{
|
||||
if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1)
|
||||
unload_uart401(&cfg_mpu);
|
||||
}
|
||||
|
||||
module_init(init_uart401);
|
||||
module_exit(cleanup_uart401);
|
||||
|
||||
#ifndef MODULE
|
||||
static int __init setup_uart401(char *str)
|
||||
{
|
||||
/* io, irq */
|
||||
int ints[3];
|
||||
|
||||
str = get_options(str, ARRAY_SIZE(ints), ints);
|
||||
|
||||
io = ints[1];
|
||||
irq = ints[2];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("uart401=", setup_uart401);
|
||||
#endif
|
||||
MODULE_LICENSE("GPL");
|
Loading…
Add table
Add a link
Reference in a new issue