diff options
| -rw-r--r-- | sound/pci/oxygen/oxygen.h | 6 | ||||
| -rw-r--r-- | sound/pci/oxygen/oxygen_io.c | 21 | ||||
| -rw-r--r-- | sound/pci/oxygen/oxygen_lib.c | 32 | 
3 files changed, 57 insertions, 2 deletions
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index f82a96290f7..19107c6307e 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -79,6 +79,7 @@ struct oxygen_model {  	void (*update_dac_volume)(struct oxygen *chip);  	void (*update_dac_mute)(struct oxygen *chip);  	void (*gpio_changed)(struct oxygen *chip); +	void (*uart_input)(struct oxygen *chip);  	void (*ac97_switch)(struct oxygen *chip,  			    unsigned int reg, unsigned int mute);  	const unsigned int *dac_tlv; @@ -125,6 +126,8 @@ struct oxygen {  		__le32 _32[OXYGEN_IO_SIZE / 4];  	} saved_registers;  	u16 saved_ac97_registers[2][0x40]; +	unsigned int uart_input_count; +	u8 uart_input[32];  	struct oxygen_model model;  }; @@ -174,6 +177,9 @@ void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,  void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);  void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data); +void oxygen_reset_uart(struct oxygen *chip); +void oxygen_write_uart(struct oxygen *chip, u8 data); +  static inline void oxygen_set_bits8(struct oxygen *chip,  				    unsigned int reg, u8 value)  { diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c index 83f135f80df..deba7389aec 100644 --- a/sound/pci/oxygen/oxygen_io.c +++ b/sound/pci/oxygen/oxygen_io.c @@ -20,6 +20,7 @@  #include <linux/delay.h>  #include <linux/sched.h>  #include <sound/core.h> +#include <sound/mpu401.h>  #include <asm/io.h>  #include "oxygen.h" @@ -232,3 +233,23 @@ void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data)  		      device | OXYGEN_2WIRE_DIR_WRITE);  }  EXPORT_SYMBOL(oxygen_write_i2c); + +static void _write_uart(struct oxygen *chip, unsigned int port, u8 data) +{ +	if (oxygen_read8(chip, OXYGEN_MPU401 + 1) & MPU401_TX_FULL) +		msleep(1); +	oxygen_write8(chip, OXYGEN_MPU401 + port, data); +} + +void oxygen_reset_uart(struct oxygen *chip) +{ +	_write_uart(chip, 1, MPU401_RESET); +	_write_uart(chip, 1, MPU401_ENTER_UART); +} +EXPORT_SYMBOL(oxygen_reset_uart); + +void oxygen_write_uart(struct oxygen *chip, u8 data) +{ +	_write_uart(chip, 0, data); +} +EXPORT_SYMBOL(oxygen_write_uart); diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index b1997216b4a..84f481d41ef 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -35,6 +35,30 @@ MODULE_DESCRIPTION("C-Media CMI8788 helper library");  MODULE_LICENSE("GPL v2"); +static inline int oxygen_uart_input_ready(struct oxygen *chip) +{ +	return !(oxygen_read8(chip, OXYGEN_MPU401 + 1) & MPU401_RX_EMPTY); +} + +static void oxygen_read_uart(struct oxygen *chip) +{ +	if (unlikely(!oxygen_uart_input_ready(chip))) { +		/* no data, but read it anyway to clear the interrupt */ +		oxygen_read8(chip, OXYGEN_MPU401); +		return; +	} +	do { +		u8 data = oxygen_read8(chip, OXYGEN_MPU401); +		if (data == MPU401_ACK) +			continue; +		if (chip->uart_input_count >= ARRAY_SIZE(chip->uart_input)) +			chip->uart_input_count = 0; +		chip->uart_input[chip->uart_input_count++] = data; +	} while (oxygen_uart_input_ready(chip)); +	if (chip->model.uart_input) +		chip->model.uart_input(chip); +} +  static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)  {  	struct oxygen *chip = dev_id; @@ -87,8 +111,12 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)  	if (status & OXYGEN_INT_GPIO)  		schedule_work(&chip->gpio_work); -	if ((status & OXYGEN_INT_MIDI) && chip->midi) -		snd_mpu401_uart_interrupt(0, chip->midi->private_data); +	if (status & OXYGEN_INT_MIDI) { +		if (chip->midi) +			snd_mpu401_uart_interrupt(0, chip->midi->private_data); +		else +			oxygen_read_uart(chip); +	}  	if (status & OXYGEN_INT_AC97)  		wake_up(&chip->ac97_waitqueue);  |