Quantcast
Channel: [EN] OpenPLi Third-Party Development
Viewing all articles
Browse latest Browse all 1692

Broadcom drivers

$
0
0

Maybe someone would be willing to take a closer look at these drivers? https://github.com/mlewertTiVo/google-stb.platform.vendor.broadcom.refsw So far, I wrote a primitive pilot service for fun :)

#include <linux/slab.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <media/rc-core.h>

#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/serial_8250.h>

#include <asm/io.h>
#include <linux/io.h>

#include "rc.h"

#include <linux/ktime.h>
#include <linux/delay.h>

#define MODULE_NAME "bcmrc"

#define BASE_REG_ADDR 0x08000000

/* com0 (ttyS0) registers */
#define UARTA_REG_START	0x0040c000
#define UARTA_REG_END	0x0040c01c
#define UARTA_IRQ 128

/* com1 (ttyS1) registers */
#define UARTB_REG_START	0x0040d000
#define UARTB_REG_END	0x0040d01c
#define UARTB_IRQ 129

/* com2 (ttyS2) registers */
#define UARTC_REG_START	0x0040e000
#define UARTC_REG_END	0x0040e01c
#define UARTC_IRQ 130

#define UART_ADDRSIZE 0x1000

enum {
	COM0 = 0,
	COM1 = 1,
	COM2 = 2,
};

#define COM_PORT COM2
#define COM_ADDRSIZE UART_ADDRSIZE
#define COM_IRQ UARTC_IRQ

#define bcmrc_debug(fmt, arg...) printk(KERN_DEBUG "%s: %s " fmt, MODULE_NAME, __func__, ##arg)
#define bcmrc_info(fmt, arg...) printk(KERN_INFO "%s: %s " fmt, MODULE_NAME, __func__, ##arg)
#define bcmrc_error(fmt, arg...) printk(KERN_ERR "%s: %s " fmt, MODULE_NAME, __func__, ##arg)
#define bcmrc_warning(fmt, arg...) printk(KERN_WARNING "%s: %s " fmt, MODULE_NAME, __func__, ##arg)
#define bcmrc_alert(fmt, arg...) printk(KERN_ALERT "%s: %s " fmt, MODULE_NAME, __func__, ##arg)

static const unsigned short vuduo4k_remote_key_table[] = {
	KEY_POWER,
	KEY_TEXT,
	KEY_SUBTITLE,
	KEY_HELP,
	KEY_0,
	KEY_1,
	KEY_2,
	KEY_3,
	KEY_4,
	KEY_5,
	KEY_6,
	KEY_7,
	KEY_8,
	KEY_9,
	KEY_PREVIOUS,
	KEY_NEXT,
	KEY_RED,
	KEY_GREEN,
	KEY_YELLOW,
	KEY_BLUE,
	KEY_VIDEO,
	KEY_MENU,
	KEY_EXIT,
	KEY_INFO,
	KEY_OK,
	KEY_UP,
	KEY_DOWN,
	KEY_RIGHT,
	KEY_LEFT,
	KEY_VOLUMEUP,
	KEY_VOLUMEDOWN,
	KEY_CHANNELUP,
	KEY_CHANNELDOWN,
	KEY_AUDIO,
	KEY_MUTE,
	KEY_EDIT,
	KEY_REWIND,
	KEY_PLAY,
	KEY_PLAYPAUSE,
	KEY_FASTFORWARD,
	KEY_TV,
	KEY_RECORD,
	KEY_STOP,
	KEY_RADIO,
};

struct bcmrc_par {
	struct input_dev *input;
	struct uart_8250_port uart;
	void __iomem *iomem_base;
	spinlock_t hardware_lock;
	int i;
	unsigned char buffer[16];
	int irq;
	unsigned short keymap[ARRAY_SIZE(vuduo4k_remote_key_table)];
};

static struct bcmrc_par bcmrc;

static unsigned int get_com_membase_reg(int com_nr)
{
	unsigned int result;
	switch (com_nr) {
		case COM0:
			result = UARTA_REG_START + BASE_REG_ADDR;
			break;
		case COM1:
			result = UARTB_REG_START + BASE_REG_ADDR;
			break;
		case COM2:
			result = UARTC_REG_START + BASE_REG_ADDR;
			break;
	}
	return result;
}

static unsigned int get_com_irq(int com_nr)
{
	unsigned int result;
	switch (com_nr) {
		case COM0:
			result = UARTA_IRQ;
			break;
		case COM1:
			result = UARTB_IRQ;
			break;
		case COM2:
			result = UARTC_IRQ;
			break;
	}
	return result;
}

static inline unsigned int serial_in(struct uart_8250_port *up, unsigned int offset)
{
	unsigned int result;
	offset = offset << up->port.regshift;

	switch (up->port.iotype) {
		case UPIO_HUB6:
			outb(up->port.hub6 - 1 + offset, up->port.iobase);
			result = inb(up->port.iobase + 1);
			//bcmrc_info("UPIO_HUB6, iobase 0x%.4x, offset: 0x%.4x, result: %d\n", up->port.iobase, offset, result);
			break;

		case UPIO_MEM:
			result = readb(up->port.membase + offset);
			//bcmrc_info("UPIO_MEM, membase 0x%.4x, offset: 0x%.4x, reg: 0x%.4x, result: %d\n", up->port.membase, offset, up->port.membase + offset, result);
			break;

		case UPIO_MEM32:
			result = readl(up->port.membase + offset);
			//bcmrc_info("UPIO_MEM32, membase 0x%.4x, offset: 0x%.4x, result: %d\n", up->port.membase, offset, result);
			break;

		default:
			//return ioread32(up->port.membase + offset);
			result = inb(up->port.iobase + offset);
			//bcmrc_info("default, membase 0x%.4x, offset: 0x%.4x, result: %d\n", up->port.iobase, offset, result);
			break;
	}
	return result;
}

static inline void serial_out(struct uart_8250_port *up, unsigned int offset, unsigned int value)
{
	offset = offset << up->port.regshift;

	switch (up->port.iotype) {
		case UPIO_HUB6:
			//bcmrc_info("UPIO_HUB6, iobase 0x%.4x, offset: 0x%.4x, value: %d\n", up->port.iobase, offset, value);
			outb(up->port.hub6 - 1 + offset, up->port.iobase);
			outb(value, up->port.iobase + 1);
			break;

		case UPIO_MEM:
			//bcmrc_info("UPIO_MEM, membase 0x%.4x, offset: 0x%.4x, reg: 0x%.4x, value: %d\n", up->port.membase, offset, up->port.membase + offset, value);
			writeb(value, up->port.membase + offset);
			break;

		case UPIO_MEM32:
			//bcmrc_info("UPIO_MEM32, membase 0x%.4x, offset: 0x%.4x, value: %d\n", up->port.membase, offset, value);
			writel(value, up->port.membase + offset);
			break;

		default:
			//bcmrc_info("default, membase 0x%.4x, offset: 0x%.4x, value %d\n", up->port.iobase, offset, value);
			//iowrite32(value, up->port.membase + offset);
			outb(value, up->port.iobase + offset);
			break;
	}
}

static int bcmrc_open(struct input_dev *dev)
{
	struct bcmrc_par *par = input_get_drvdata(dev);
	unsigned long flags;
#if 0
	/* initialize timestamp */
	//par->lastkt = ktime_get();

	spin_lock_irqsave(&par->hardware_lock, flags);

	/* Set DLAB 0. */
	serial_out(&par->uart, UART_LCR, serial_in(&par->uart, (UART_LCR) & (~UART_LCR_DLAB)));

	serial_out(&par->uart, UART_IER, serial_in(&par->uart, (UART_IER) | UART_IER_MSI));

	spin_unlock_irqrestore(&par->hardware_lock, flags);
#endif
	return 0;
}

static void bcmrc_close(struct input_dev *dev)
{
	struct bcmrc_par *par = input_get_drvdata(dev);
	unsigned long flags;
#if 0
	spin_lock_irqsave(&par->hardware_lock, flags);

	/* Set DLAB 0. */
	serial_out(&par->uart, UART_LCR, serial_in(&par->uart, (UART_LCR) & (~UART_LCR_DLAB)));

	/* First of all, disable all interrupts */
	serial_out(&par->uart, UART_IER, serial_in(&par->uart, (UART_IER) & (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))));

	spin_unlock_irqrestore(&par->hardware_lock, flags);
#endif
}

static long bcmrc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
	struct bcmrc_par *par = (struct bcmrc_par*) filep->private_data;
	int result;

	switch (cmd) {

	}

	return result;
}

static int bcmrc_frontpanel_key_mapping(struct input_dev *dev, unsigned int key)
{
	struct bcmrc_par *par = input_get_drvdata(dev);
	unsigned int result;

	switch (key) {
		case 0x01:
			result = KEY_POWER;
			break;
		case 0x02:
			result = KEY_VOLUMEUP;
			break;
		case 0x04:
			result = KEY_VOLUMEDOWN;
			break;
		case 0x08:
			result = KEY_CHANNELUP;
			break;
		case 0x80:
			result = KEY_CHANNELDOWN;
			break;
		default:
			bcmrc_info("Unhandled key: 0x%.2x\n", key);
			result = 0;
			break;
	}
	return result;
}

static int bcmrc_remote_key_mapping(struct input_dev *dev, unsigned int key)
{
	struct bcmrc_par *par = input_get_drvdata(dev);
	unsigned int result;

	switch (key) {
		case 0x0c:
			result = KEY_POWER;
			break;
		case 0x3c:
			result = KEY_TEXT;
			break;
		case 0x4b:
			result = KEY_SUBTITLE;
			break;
		case 0x81:
			result = KEY_HELP;
			break;
		case 0x00:
			result = KEY_0;
			break;
		case 0x01:
			result = KEY_1;
			break;
		case 0x02:
			result = KEY_2;
			break;
		case 0x03:
			result = KEY_3;
			break;
		case 0x04:
			result = KEY_4;
			break;
		case 0x05:
			result = KEY_5;
			break;
		case 0x06:
			result = KEY_6;
			break;
		case 0x07:
			result = KEY_7;
			break;
		case 0x08:
			result = KEY_8;
			break;
		case 0x09:
			result = KEY_9;
			break;
		case 0xbb:
			result = KEY_PREVIOUS;
			break;
		case 0xbc:
			result = KEY_NEXT;
			break;
		case 0x6d:
			result = KEY_RED;
			break;
		case 0x6e:
			result = KEY_GREEN;
			break;
		case 0x6f:
			result = KEY_YELLOW;
			break;
		case 0x70:
			result = KEY_BLUE;
			break;
		case 0x49:
			result = KEY_VIDEO;
			break;
		case 0x54:
			result = KEY_MENU;
			break;
		case 0xcc:
			result = KEY_EXIT;
			break;
		case 0x55:
			result = KEY_INFO;
			break;
		case 0x5c:
			result = KEY_OK;
			break;
		case 0x58:
			result = KEY_UP;
			break;
		case 0x59:
			result = KEY_DOWN;
			break;
		case 0x5b:
			result = KEY_RIGHT;
			break;
		case 0x5a:
			result = KEY_LEFT;
			break;
		case 0x10:
			result = KEY_VOLUMEUP;
			break;
		case 0x11:
			result = KEY_VOLUMEDOWN;
			break;
		case 0x20:
			result = KEY_CHANNELUP;
			break;
		case 0x21:
			result = KEY_CHANNELDOWN;
			break;
		case 0xe5:
			result = KEY_AUDIO;
			break;
		case 0x0d:
			result = KEY_MUTE;
			break;
		case 0xe6:
			result = KEY_EDIT;
			break;
		case 0x29:
			result = KEY_REWIND;
			break;
		case 0x2c:
			result = KEY_PLAY;
			break;
		case 0x30:
			result = KEY_PLAYPAUSE;
			break;
		case 0x28:
			result = KEY_FASTFORWARD;
			break;
		case 0xe4:
			result = KEY_TV;
			break;
		case 0x37:
			result = KEY_RECORD;
			break;
		case 0x31:
			result = KEY_STOP;
			break;
		case 0xf2:
			result = KEY_RADIO;
			break;
		default:
			bcmrc_info("Unhandled key: 0x%.2x\n", key);
			result = 0;
			break;
	}
	return result;
}

static irqreturn_t bcmrc_irq_handler(int irq, void *dev_id)
{
	struct bcmrc_par *par = (struct bcmrc_par *)dev_id;
	struct input_dev *input = par->input;
	unsigned long flags;
	unsigned int iir, lsr, i = 0;
	int counter = 0, max_count = 8;

	while ((iir = serial_in(&par->uart, UART_IIR & UART_IIR_ID))) {
		if (++counter > 256) {
			//bcmrc_error("Trapped in interrupt, counter %d\n", counter);
			break;
		}

		switch (iir & UART_IIR_ID) {
			case UART_IIR_MSI:
				(void) serial_in(&par->uart, UART_MSR);
				break;
			case UART_IIR_RLSI:
			case UART_IIR_THRI:
				(void) serial_in(&par->uart, UART_LSR);
				break;
			case UART_IIR_RDI:
				spin_lock_irqsave(&par->hardware_lock, flags);
				do {
					par->buffer[par->i++] = serial_in(&par->uart, UART_RX);
					if (par->i == 7) {
						//bcmrc_info("first packet 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x\n", par->buffer[0], par->buffer[1], par->buffer[2], par->buffer[3], par->buffer[4], par->buffer[5], par->buffer[6], par->buffer[7]);
						if (par->buffer[0] == 0xd1)
							input_report_key(par->input, bcmrc_frontpanel_key_mapping(par->input, par->buffer[1]), 1);
						else if (par->buffer[0] == 0xd2)
							input_report_key(par->input, bcmrc_remote_key_mapping(par->input, par->buffer[1]), 1);
						input_sync(par->input);
					}
					if (par->i == 15) {
						//bcmrc_info("second packet 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x\n", par->buffer[8], par->buffer[9], par->buffer[10], par->buffer[11], par->buffer[12], par->buffer[13], par->buffer[14], par->buffer[15]);
						if (par->buffer[0] == 0xd1)
							input_report_key(par->input, bcmrc_frontpanel_key_mapping(par->input, par->buffer[1]), 0);
						else if (par->buffer[0] == 0xd2)
							input_report_key(par->input, bcmrc_remote_key_mapping(par->input, par->buffer[1]), 0);
						input_sync(par->input);
						par->i = 0;
					}
					lsr = serial_in(&par->uart, UART_LSR);
				} while (lsr & UART_LSR_DR);
				spin_unlock_irqrestore(&par->hardware_lock, flags);
				break;
			default:
				break;
		}
	}

	return IRQ_RETVAL(1);
}

int init_bcmrcdev(void)
{
	int result, i;
	struct bcmrc_par *par;
	struct input_dev *input_dev;
	struct uart_8250_port uart;

	unsigned long flags;

	par = kzalloc(sizeof(struct bcmrc_par), GFP_KERNEL);
	if (!par) {
		bcmrc_error("Error allocate primary structure!");
		return -ENOMEM;
		goto err_free_mem;
	}

	par->uart = uart;

	par->irq = get_com_irq(COM2);

	par->iomem_base = ioremap(get_com_membase_reg(COM2), COM_ADDRSIZE);
	if (!par->iomem_base) {
		bcmrc_error("Error remap memory!");
		goto err_iounmap;
	}

	result = request_threaded_irq(par->irq, bcmrc_irq_handler, 0, 0, "serial", par);
	if (result < 0) {
		if (result == -EBUSY)
			bcmrc_error("IRQ %d busy\n", par->irq);
		else if (result == -EINVAL)
			bcmrc_error("Bad irq number\n");
		return -EBUSY;
		goto err_free_input;
	}

	memset(&par->uart, 0, sizeof(par->uart));

	par->uart.port.type = PORT_16550A;
	par->uart.port.irq = par->irq;
	par->uart.port.uartclk = 5062500; /* 3686400 */
	par->uart.port.flags = UPF_SHARE_IRQ;
	par->uart.port.iotype = UPIO_MEM;
	par->uart.port.membase = par->iomem_base;
	par->uart.port.regshift = 2;

	spin_lock_irqsave(&par->hardware_lock, flags);

	serial_out(&par->uart, UART_IER, 0);

	/* Set DLAB 0. */
	serial_out(&par->uart, UART_LCR, serial_in(&par->uart, (UART_LCR) & (~UART_LCR_DLAB)));

	/* First of all, disable all interrupts */
	serial_out(&par->uart, UART_IER, serial_in(&par->uart, (UART_IER) & (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))));

	/* Clear registers. */
	serial_in(&par->uart, UART_LSR);
	serial_in(&par->uart, UART_RX);
	serial_in(&par->uart, UART_IIR);
	serial_in(&par->uart, UART_MSR);

	serial_out(&par->uart, UART_IER, 1);

	/* Clear registers again to be sure. */
	serial_in(&par->uart, UART_LSR);
	serial_in(&par->uart, UART_RX);
	serial_in(&par->uart, UART_IIR);
	serial_in(&par->uart, UART_MSR);

	spin_unlock_irqrestore(&par->hardware_lock, flags);

	input_dev = input_allocate_device();
	if (!input_dev) {
		bcmrc_error("Error alocate input device structure!");
		return -ENOMEM;
		goto err_free_input;
	}

	memcpy(par->keymap, vuduo4k_remote_key_table, sizeof(par->keymap));

	input_dev->keycode = par->keymap;
	input_dev->keycodesize = sizeof(unsigned short);
	input_dev->keycodemax = ARRAY_SIZE(par->keymap);

	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
	__set_bit(EV_KEY, input_dev->evbit);
	for (i = 0; i < ARRAY_SIZE(vuduo4k_remote_key_table); i++)
		__set_bit(vuduo4k_remote_key_table[i], input_dev->keybit);
	__clear_bit(KEY_RESERVED, input_dev->keybit);

	input_dev->name = "dreambox advanced remote control (native)";
	input_dev->phys = "event0";

	input_dev->id.bustype = BUS_HOST;

	input_dev->open = bcmrc_open;
	input_dev->close = bcmrc_close;

	par->input = input_dev;

	input_set_drvdata(par->input, par);

	result = input_register_device(par->input);
	if (result) {
		return -1;
	}

	return 0;

err_free_input:
	input_free_device(input_dev);
err_iounmap:
	iounmap(par->iomem_base);
err_free_mem_region:
	release_mem_region(get_com_membase_reg(COM2), COM_ADDRSIZE);
err_free_mem:
	input_free_device(input_dev);
	kfree(par);
	return result;
}

void exit_bcmrcdev(void)
{
	struct input_dev *input_dev;
	input_unregister_device(input_dev);
	input_free_device(input_dev);
}

 


Viewing all articles
Browse latest Browse all 1692

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>