lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:   Wed, 31 Mar 2021 21:21:03 +0200
From:   "Enrico Weigelt, metux IT consult" <info@...ux.net>
To:     Moriis Ku <saumah@...il.com>, lee.jones@...aro.org
Cc:     linux-kernel@...r.kernel.org
Subject: Re: [PATCH] Add Driver for SUNIX PCI(e) I/O expansion board

On 30.03.21 08:58, Moriis Ku wrote:

Hi folks,

> From: Morris <saumah@...il.com>
> 
> The board provide UART, DIO and CAN functions.

Oh no, not again ... we had about a hundred mails about the same thing
(at least the quite same device), many month ago. And it seems really
much of what had been said these days, wasn't taken account for :(

> Signed-off-by: Morris <saumah@...il.com>
> ---
>   drivers/mfd/bus.c          | 1524 +++++++++++++++
>   drivers/mfd/dio.c          |  529 +++++
>   drivers/mfd/dio_pack.c     | 3126 +++++++++++++++++++++++++++++
>   drivers/mfd/list.c         |   99 +
>   drivers/mfd/mem.c          |   37 +
>   drivers/mfd/sdc_define.h   |  668 +++++++
>   drivers/mfd/sdc_function.h |   96 +
>   drivers/mfd/sdc_include.h  |  108 +
>   drivers/mfd/spi.c          |  420 ++++
>   drivers/mfd/spi_pack.c     | 1506 ++++++++++++++
>   drivers/mfd/uart.c         | 3796 ++++++++++++++++++++++++++++++++++++
>   11 files changed, 11909 insertions(+)
>   create mode 100644 drivers/mfd/bus.c
>   create mode 100644 drivers/mfd/dio.c
>   create mode 100644 drivers/mfd/dio_pack.c
>   create mode 100644 drivers/mfd/list.c
>   create mode 100644 drivers/mfd/mem.c
>   create mode 100644 drivers/mfd/sdc_define.h
>   create mode 100644 drivers/mfd/sdc_function.h
>   create mode 100644 drivers/mfd/sdc_include.h
>   create mode 100644 drivers/mfd/spi.c
>   create mode 100644 drivers/mfd/spi_pack.c
>   create mode 100644 drivers/mfd/uart.c
> 
> diff --git a/drivers/mfd/bus.c b/drivers/mfd/bus.c
> new file mode 100644
> index 000000000000..7820072e918f
> --- /dev/null
> +++ b/drivers/mfd/bus.c
> @@ -0,0 +1,1524 @@
> +/*
> + *	Driver for SUNIX PCI(e) expansion board
> + *	Based on drivers/tty/serial/8250/8250_pci.c
> + *	by Linus Torvalds, Theodore Ts'o.
> + *
> + *	This program is free software; you can redistribute it and/or modify
> + *	it under the terms of the GNU General Public License as published by
> + *	the Free Software Foundation; either version 2 of the License.
> + */

Use spdx headers instead.

> +#include "sdc_include.h"
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))

Certainly not. We don't carry around dead code pieces for ancient kernel
versions. Please also make sure that your code really aligns to the
_current_ kernel, using helpers and infrastructure that had been
developed in the last decade ...

I doubt that anybody here seriously wants to read such code.

> +static  struct pci_device_id	sunix_pci_board_id[] =
> +{
> +	{0x1fd4, 0x2000, 0x1fd4, 0x0001, 0, 0, 123},
> +	{0}
> +};
> +MODULE_DEVICE_TABLE(pci, sunix_pci_board_id);
> +#else
> +typedef struct
> +{
> +	unsigned short vendor;
> +	unsigned short device;
> +	unsigned short subvendor;
> +	unsigned short subdevice;
> +	unsigned short driver_data;
> +	unsigned short part_number;
> +} sunix_pciInfo;
> +
> +static sunix_pciInfo sunix_pci_board_id[] =
> +{
> +	{0x1fd4, 0x2000, 0x1fd4, 0x0001, 123},
> +	{0}
> +};
> +#endif
> +
> +
> +struct sunix_sdc_board			sunix_sdc_board_table[SUNIX_SDC_BOARD_MAX];
> +struct sunix_sdc_uart_channel	sunix_sdc_uart_table[SUNIX_SDC_UART_MAX + 1];
> +struct sunix_sdc_dio_channel	sunix_sdc_dio_table[SUNIX_SDC_DIO_MAX];
> +struct sunix_sdc_spi_channel	sunix_sdc_spi_table[SUNIX_SDC_SPI_MAX];

Nope, never add such global fields. Per-Device data belongs into proper
struct in device's privdata ...

> +
> +struct kmem_cache *				sunix_sdc_dio_pack_cache;
> +struct kmem_cache *				sunix_sdc_spi_pack_cache;
> +
> +unsigned int					sunix_sdc_board_amount;
> +unsigned int					sunix_sdc_uart_amount;
> +unsigned int					sunix_sdc_dio_amount;
> +unsigned int					sunix_sdc_spi_amount;
> +
> +
> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
> +static irqreturn_t sunix_interrupt(int irq, void *dev_id)
> +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +static irqreturn_t sunix_interrupt(int irq, void *dev_id, struct pt_regs *regs)
	> +#else
> +static void sunix_interrupt(int irq, void *dev_id, struct pt_regs *regs)
> +#endif
> +{
> +	struct sunix_sdc_board *sb = NULL;
> +	struct sunix_sdc_uart_channel *uart_chl = NULL;
> +	struct sunix_sdc_dio_channel *dio_chl = NULL;
> +	struct sunix_sdc_spi_channel *spi_chl = NULL;
> +	int i, j, k;
> +	int status = 0;
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +	int handled = IRQ_NONE;
> +#endif
> +	unsigned int vector[8];
> +	unsigned int event_header;
> +	unsigned char chl_num;
> +
> +
> +	for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +	{
> +		if (dev_id == &(sunix_sdc_board_table[i]))

OMGS! No, give the irq a pointer to the device, not some table index.
And drop that global table completely.

> +		{
> +			sb = dev_id;
> +			break;
> +		}
> +	}
> +
> +	if (i == SUNIX_SDC_BOARD_MAX)
> +		status = 1;
> +
> +	if (!sb)
> +		status = 1;
> +
> +	if (sb->board_enum <= 0)
> +		status = 1;
> +
> +	if (status != 0)
> +	{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +		return handled;
> +#else
> +		return;
> +#endif
> +	}
> +
> +	vector[0] = mem_rx32(sb->bar0_membase, 0, 0);
> +	vector[1] = mem_rx32(sb->bar0_membase, 0, 1);
> +	vector[2] = mem_rx32(sb->bar0_membase, 0, 2);
> +	vector[3] = mem_rx32(sb->bar0_membase, 0, 3);
> +	vector[4] = mem_rx32(sb->bar0_membase, 0, 4);
> +	vector[5] = mem_rx32(sb->bar0_membase, 0, 5);
> +	vector[6] = mem_rx32(sb->bar0_membase, 0, 6);
> +	vector[7] = mem_rx32(sb->bar0_membase, 0, 7);
> +
> +	for (i = 0; i < 8; i++)
> +	{
> +		if (vector[i] & 0xffffffff)
> +		{
> +			for (j = 0; j < 32; j++)
> +			{
> +				if (vector[i] & (0x00000001 << j))
> +				{
> +					chl_num = (i * 8) + j;
> +
> +					event_header = mem_rx32(sb->bar0_membase, 0, 8 + chl_num);
> +
> +					for (k = 0; k < SUNIX_SDC_UART_MAX + 1; k++)
> +					{
> +						uart_chl = &sunix_sdc_uart_table[k];
> +
> +						// uart
> +						if ((uart_chl->port.iobase != 0) &&
> +							(uart_chl->port.bus_number == sb->bus_number) &&
> +							(uart_chl->port.dev_number == sb->dev_number) &&
> +							(uart_chl->port.cib_info.num == chl_num) &&
> +							(uart_chl->port.cib_info.type == 0x01))
> +						{
> +							//printk("SUNIX: bus_num:%d, dev_num:%d, chl_num:%d, event:x%08x, ttySDC%d has interrupt\n", uart_chl->port.bus_number, uart_chl->port.dev_number, chl_num, event_header, uart_chl->port.line);
> +							status = sb->uart_isr(uart_chl);
> +						}
> +					}

Really too deep nesting, to big function. Split it.

> +
> +					for (k = 0; k < SUNIX_SDC_DIO_MAX; k++)
> +					{
> +						dio_chl = &sunix_sdc_dio_table[k];
> +
> +						// dio
> +						if ((dio_chl->info.memsize != 0) &&
> +							(dio_chl->info.bus_number == sb->bus_number) &&
> +							(dio_chl->info.dev_number == sb->dev_number) &&
> +							(dio_chl->info.cib_info.num == chl_num) &&
> +							(dio_chl->info.cib_info.type == 0x02))
> +						{
> +							//printk("SUNIX: bus_num:%d, dev_num:%d, chl_num:%d, event:x%08x, SDCDIO%d has interrupt\n", dio_chl->info.bus_number, dio_chl->info.dev_number, chl_num, event_header, dio_chl->info.line);
> +							status = sb->dio_isr(dio_chl, event_header);
> +						}
> +					}
> +
> +					for (k = 0; k < SUNIX_SDC_SPI_MAX; k++)
> +					{
> +						spi_chl = &sunix_sdc_spi_table[k];
> +
> +						// spi
> +						if ((spi_chl->info.memsize != 0) &&
> +							(spi_chl->info.bus_number == sb->bus_number) &&
> +							(spi_chl->info.dev_number == sb->dev_number) &&
> +							(spi_chl->info.cib_info.num == chl_num) &&
> +							(spi_chl->info.cib_info.type == 0x03))
> +						{
> +							//printk("SUNIX: bus_num:%d, dev_num:%d, chl_num:%d, event:x%08x, SDCSPI%d has interrupt\n", spi_chl->info.bus_number, spi_chl->info.dev_number, chl_num, event_header, spi_chl->info.line);
> +							status = sb->spi_isr(spi_chl, event_header);
> +						}
> +					}
> +				}
> +			}
> +		}
> +	}
> +
> +	if (status != 0)
> +	{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +		return handled;
> +#else
> +		return;
> +#endif
> +	}
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +	handled = IRQ_HANDLED;
> +	return handled;
> +#endif
> +}
> +
> +
> +static int snx_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
> +{
> +	return 0;
> +}

What is that for ?

> +
> +
> +static int snx_suspend_one(struct pci_dev *pdev, pm_message_t state)
> +{
> +	return  0;
> +}
> +
> +
> +static int snx_set_port_termios(struct snx_ser_state *state)
> +{
> +	struct tty_struct *tty = state->info->tty;
> +	struct SNXTERMIOS *termios;
> +	int retval = 0;
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	termios = &tty->termios;
> +#else
> +	termios = tty->termios;
> +#endif
> +
> +	retval = snx_ser_startup(state, 0);
> +
> +	if (retval == 0)
> +	{
> +		snx_ser_update_termios(state);
> +	}
> +
> +	return 0;
> +}
> +
> +
> +static int snx_resume_port_termios(struct snx_ser_info *info)
> +{
> +	struct snx_ser_state *state = NULL;
> +	struct tty_struct *tty = info->tty ;
> +
> +
> +	state = tty->driver_data;
> +	snx_set_port_termios(state);
> +
> +	return 0;
> +}
> +
> +
> +static int snx_resume_port(struct sunix_sdc_uart_channel *uart_chl)
> +{
> +	struct snx_ser_port *port = &uart_chl->port;
> +	struct snx_ser_info *info = port->info;
> +
> +
> +	if (info)
> +	{
> +		snx_resume_port_termios(info);
> +	}
> +
> +	return 0;
> +}
> +
> +
> +static int snx_resume_one(struct pci_dev *pdev)
> +{
> +	struct sunix_sdc_board *sb = pci_get_drvdata(pdev);
> +	struct sunix_sdc_uart_channel *uart_chl = NULL;
> +	int j;
> +
> +
> +	if (sb == NULL)
> +	{
> +		return 0;
> +	}
> +
> +	for (j = 0; j < sb->uart_amount; j++)
> +	{
> +		uart_chl = &sunix_sdc_uart_table[sb->uart_start_index + j];
> +
> +		if (uart_chl == NULL)
> +		{
> +			return 0;
> +		}
> +
> +		if (uart_chl->port.suspended == 1)
> +		{
> +			snx_resume_port(uart_chl);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +
> +static int sunix_pci_board_probe(void)
> +{
> +	struct sunix_sdc_board *sb;
> +	struct pci_dev *pdev = NULL;
> +	struct pci_dev *pdev_array[4] = {NULL, NULL, NULL, NULL};
> +	int sunix_pci_board_id_cnt;
> +	int tablecnt;
> +	int board_amount = 0;
> +	int i, j;
> +	unsigned short int sub_device_id;
> +	int status;
> +	unsigned char data1B;
> +	unsigned int data8B;
> +
> +
> +	// clear and init some variable
> +	memset(sunix_sdc_board_table, 0, SUNIX_SDC_BOARD_MAX * sizeof(struct sunix_sdc_board));
> +
> +	for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +	{
> +		sunix_sdc_board_table[i].board_enum = -1;
> +		sunix_sdc_board_table[i].board_number = -1;
> +		sunix_sdc_board_table[i].bar0_membase = NULL;
> +		sunix_sdc_board_table[i].bar2_membase = NULL;
> +	}

drop this global table. put it into device privdata.

> +	sunix_pci_board_id_cnt = (sizeof(sunix_pci_board_id) / sizeof(sunix_pci_board_id[0])) - 1;
> +
> +
> +	// search
> +	pdev = NULL;
> +	tablecnt = 0;
> +	sub_device_id = 0;
> +	status = 0;
> +
> +	while (tablecnt < sunix_pci_board_id_cnt)
> +	{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +		pdev = pci_get_device(0x1fd4, 0x2000, pdev);
> +#else
> +		pdev = pci_find_device(0x1fd4, 0x2000, pdev);
> +#endif

No, dont do this scan that manually. Make it a pci driver and register
it to the pci subsystem with ID table.

> +
> +		if (pdev == NULL)
> +		{
> +			tablecnt++;
> +			continue;
> +		}
> +
> +		if ((tablecnt > 0) && ((pdev == pdev_array[0]) || (pdev == pdev_array[1]) || (pdev == pdev_array[2]) || (pdev == pdev_array[3])))
> +		{
> +			continue;
> +		}
> +
> +		pci_read_config_word(pdev, 0x2e, &sub_device_id);
> +
> +		if (sub_device_id == 0)
> +		{
> +			printk("SUNIX: Board (bus:%d device:%d), in configuration space, subdevice id isn't vaild.\n", pdev->bus->number, PCI_SLOT(pdev->devfn));
> +			status = -EIO;
> +			return status;
> +		}
> +
> +		if (sub_device_id != sunix_pci_board_id[tablecnt].subdevice)
> +		{
> +			continue;
> +		}
> +
> +		if (pdev == NULL)
> +		{
> +			printk("SUNIX: PCI device object is an NULL pointer !\n");
> +			status = -EIO;
> +			return status;
> +		}
> +		else
> +		{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
> +
> +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 3))
> +			pci_disable_device(pdev);
> +#endif
> +			status = pci_enable_device(pdev);
> +			if (status != 0)
> +			{
> +				printk("SUNIX: Board Enable Fail !\n");
> +				status = -ENXIO;
> +				return status;
> +			}
> +		}
> +
> +		if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM))
> +		{
> +			printk("SUNIX: Incorrect BAR0 configuration.\n");
> +			status = -ENODEV;
> +			return status;
> +		}
> +		if (!(pci_resource_flags(pdev, 1) & IORESOURCE_IO))
> +		{
> +			printk("SUNIX: Incorrect BAR1 configuration.\n");
> +			status = -ENODEV;
> +			return status;
> +		}
> +		if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM))
> +		{
> +			printk("SUNIX: Incorrect BAR2 configuration.\n");
> +			status = -ENODEV;
> +			return status;
> +		}
> +
> +
> +		board_amount++;
> +		if (board_amount > SUNIX_SDC_BOARD_MAX)
> +		{
> +			printk("SUNIX: Driver support 4 boards in maximum !\n");
> +			status = -ENOSPC;
> +			return status;
> +		}
> +
> +		sb = &sunix_sdc_board_table[board_amount-1];
> +		pdev_array[board_amount-1] = pdev;
> +
> +
> +		sb->pdev = pdev;
> +		sb->board_enum = (int)sunix_pci_board_id[tablecnt].driver_data;
> +		sb->board_number = board_amount - 1;
> +		sb->bus_number = pdev->bus->number;
> +		sb->dev_number = PCI_SLOT(pdev->devfn);
> +		sb->irq = pdev->irq;
> +
> +		sb->bar0_membase = mem_get_bar_ioremap(pdev, 0);
> +		sb->bar1_iobase = pci_resource_start(pdev, 1);
> +		sb->bar2_membase = mem_get_bar_ioremap(pdev, 2);
> +		data8B = mem_rx32(sb->bar2_membase, 0, 0);
> +		sb->major_version = data8B & 0x000000ff;
> +		sb->minor_version = (data8B & 0x0000ff00) >> 8;
> +		sb->aval_channels = (data8B & 0x00ff0000) >> 16;
> +
> +		j = 0;
> +		memset(sb->model_name, 0, sizeof(sb->model_name));
> +		for (i = 0; i < 4; i++)
> +		{
> +			data8B = mem_rx32(sb->bar2_membase, 0, 2 + i);
> +
> +			data1B = data8B & 0x000000ff;
> +			if (data1B == 0x00)
> +				break;
> +			sb->model_name[j++] = data1B;
> +
> +			data1B = (data8B & 0x0000ff00) >> 8;
> +			if (data1B == 0x00)
> +				break;
> +			sb->model_name[j++] = data1B;
> +
> +			data1B = (data8B & 0x00ff0000) >> 16;
> +			if (data1B == 0x00)
> +				break;
> +			sb->model_name[j++] = data1B;
> +
> +			data1B = (data8B & 0xff000000) >> 24;
> +			if (data1B == 0x00)
> +				break;
> +			sb->model_name[j++] = data1B;
> +		}
> +	}
> +
> +
> +	if (board_amount == 0)
> +	{
> +		printk("SUNIX: No board found !\n");
> +		status = -ENXIO;
> +		return status;
> +	}
> +	else
> +	{
> +		for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +		{
> +			sb = &sunix_sdc_board_table[i];
> +
> +			if (sb->board_enum > 0)
> +			{
> +				printk("SUNIX: Found %s board (bus_num:%d, dev_num:%d, maj_v:%d, min_vr:%d)\n", sb->model_name, sb->bus_number, sb->dev_number, sb->major_version, sb->minor_version);
> +			}
> +		}
> +		sunix_sdc_board_amount  = board_amount;
> +    }
> +
> +	return status;
> +}
> +
> +
> +static int sunix_get_pci_board_conf(void)
> +{
> +    struct sunix_sdc_board *sb = NULL;
> +    int status = 0;
> +    int i, j, k, l;
> +	unsigned int data8B;
> +	unsigned int cib_addr;
> +	unsigned int cib_addr_offset;
> +	unsigned short next_ptr;
> +	int uart_amount;
> +	int dio_amount;
> +	int spi_amount;
> +	unsigned int dio_io_mask = 0;
> +	unsigned int dio_io_shift_bits = 0;
> +	unsigned int dio_io_direction = 0;
> +
> +
> +	for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +	{

drop that global table.

> +		sb = &sunix_sdc_board_table[i];
> +
> +		if (sb->board_enum > 0)
> +		{
> +			dio_io_shift_bits = 0;
> +
> +			data8B = mem_rx32(sb->bar2_membase, 0, 1);
> +			next_ptr = data8B & 0x0000ffff;
> +
> +			uart_amount = 0;
> +			dio_amount = 0;
> +			spi_amount = 0;
> +
> +			cib_addr = 0;
> +			for (j = 0; j < sb->aval_channels; j++)
> +			{
> +				cib_addr = next_ptr;
> +				cib_addr_offset = 0;
> +				data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +				sb->channel[j].num = data8B & 0x000000ff;
> +				sb->channel[j].type = (data8B & 0x0000ff00) >> 8;
> +				sb->channel[j].version = (data8B & 0x00ff0000) >> 16;
> +				sb->channel[j].lengthInDW = (data8B & 0xff000000) >> 24;
> +
> +				data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +				next_ptr = data8B & 0x0000ffff;
> +				sb->channel[j].capability = (data8B & 0x00ff0000) >> 16;
> +				sb->channel[j].event_header_type = (data8B & 0xff000000) >> 24;
> +
> +				if ((sb->channel[j].capability & 0x03) == 0x03)
> +				{
> +					data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +					sb->channel[j].io_addr_offset = data8B & 0x00ffffff;
> +					sb->channel[j].io_space_size = (data8B & 0xff000000) >> 24;
> +					data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +					sb->channel[j].mem_addr_offset = data8B;
> +					data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +					sb->channel[j].mem_space_size = data8B;
> +				}
> +				else if ((sb->channel[j].capability & 0x01) == 0x01)
> +				{
> +					data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +					sb->channel[j].io_addr_offset = data8B & 0x00ffffff;
> +					sb->channel[j].io_space_size = (data8B & 0xff000000) >> 24;
> +				}
> +				else if ((sb->channel[j].capability & 0x02) == 0x02)
> +				{
> +					data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +					sb->channel[j].mem_addr_offset = data8B;
> +					data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +					sb->channel[j].mem_space_size = data8B;
> +				}
> +
> +				if (sb->channel[j].type == 0x00)
> +				{
> +					// configuration controller
> +					data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +					sb->channel[j].cfg_ic_model = data8B & 0x000000ff;
> +				}
> +
> +				if (sb->channel[j].type == 0x01)
> +				{
> +					uart_amount++;
> +					// uart controller
> +					data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +					sb->channel[j].uart_tx_fifo_size = data8B & 0x0000ffff;
> +					sb->channel[j].uart_rx_fifo_size = (data8B & 0xffff0000) >> 16;
> +					data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +					sb->channel[j].uart_significand_of_clock = data8B & 0x00ffffff;
> +					sb->channel[j].uart_exponent_of_clock = (data8B & 0xff000000) >> 24;
> +					data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +					sb->channel[j].uart_RS232_cap = data8B & 0x00000001;
> +					sb->channel[j].uart_RS422_cap = (data8B & 0x00000002) >> 1;
> +					sb->channel[j].uart_RS485_cap = (data8B & 0x00000004) >> 2;
> +					sb->channel[j].uart_AHDC_cap = (data8B & 0x00000008) >> 3;
> +					sb->channel[j].uart_CS_cap = (data8B & 0x00000010) >> 4;
> +					sb->channel[j].uart_auto_RS422485_cap = (data8B & 0x00000020) >> 5;
> +					sb->channel[j].uart_RS422_termination_cap = (data8B & 0x00000040) >> 6;
> +					sb->channel[j].uart_RS485_termination_cap = (data8B & 0x00000080) >> 7;
> +					sb->channel[j].uart_RI_5V_cap = (data8B & 0x00000100) >> 8;
> +					sb->channel[j].uart_RI_12V_cap = (data8B & 0x00000200) >> 9;
> +					sb->channel[j].uart_DCD_5V_cap = (data8B & 0x00000400) >> 10;
> +					sb->channel[j].uart_DCD_12V_cap = (data8B & 0x00000800) >> 11;
> +					// switch to rs422 if support rs422
> +					if ((sb->channel[j].uart_RS232_cap == 0x00) && (sb->channel[j].uart_RS422_cap == 0x01))
> +					{
> +						outb(0x02, sb->bar1_iobase + sb->channel[j].io_addr_offset + 0x0e);
> +					}
> +				}
> +
> +				if (sb->channel[j].type == 0x02)
> +				{
> +					dio_amount++;
> +					// dio controller
> +					data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +					sb->channel[j].dio_number_of_banks = data8B & 0x000000ff;
> +					sb->channel[j].dio_shares_same_direction_ctrl_cap = (data8B & 0x00000100) >> 8;
> +					sb->channel[j].dio_writing_setting_to_flash_cap = (data8B & 0x00000200) >> 9;
> +
> +					for (k = 0; k < sb->channel[j].dio_number_of_banks; k++)
> +					{
> +						data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +						sb->channel[j].dio_bank_cap[k].number_of_io = data8B & 0x000000ff;
> +						sb->channel[j].dio_bank_cap[k].support_inputs = (data8B & 0x00000100) >> 8;
> +						sb->channel[j].dio_bank_cap[k].support_outputs = (data8B & 0x00000200) >> 9;
> +						sb->channel[j].dio_bank_cap[k].rising_edge_trigger_cap = (data8B & 0x00000400) >> 10;
> +						sb->channel[j].dio_bank_cap[k].falling_edge_trigger_cap = (data8B & 0x00000800) >> 11;
> +					}
> +
> +					dio_io_direction = mem_rx32(sb->bar2_membase, sb->channel[j].mem_addr_offset, 12);
> +					for (k = 0; k < sb->channel[j].dio_number_of_banks; k++)
> +					{
> +						dio_io_mask = 0;
> +						for (l = 0; l < sb->channel[j].dio_bank_cap[k].number_of_io; l++)
> +						{
> +							dio_io_mask |= 0x00000001;
> +							if (l < (sb->channel[j].dio_bank_cap[k].number_of_io - 1))
> +								dio_io_mask = dio_io_mask <<1;
> +						}
> +
> +						if (k > 0)
> +						{
> +							dio_io_shift_bits += sb->channel[j].dio_bank_cap[k-1].number_of_io;
> +							dio_io_mask = dio_io_mask << dio_io_shift_bits;
> +						}
> +
> +						sb->channel[j].dio_bank_cap[k].io_mask = dio_io_mask;
> +						sb->channel[j].dio_bank_cap[k].io_shift_bits = dio_io_shift_bits;
> +					}
> +				}
> +
> +				if (sb->channel[j].type == 0x03)
> +				{
> +					spi_amount++;
> +					// spi controller
> +					data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +					sb->channel[j].spi_significand_of_clock = data8B & 0x00ffffff;
> +					sb->channel[j].spi_exponent_of_clock = (data8B & 0xff000000) >> 24;
> +					data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +					sb->channel[j].spi_number_of_device = data8B & 0x000000ff;
> +
> +					for (k = 0; k < sb->channel[j].spi_number_of_device; k++)
> +					{
> +						data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +						sb->channel[j].spi_device_cap[k].type = data8B & 0x00000001;
> +						sb->channel[j].spi_device_cap[k].number_of_gpio_input = (data8B & 0x00000f00) >> 8;
> +						sb->channel[j].spi_device_cap[k].number_of_gpio_output = (data8B & 0x0000f000) >> 12;
> +
> +						memset(sb->channel[j].spi_device_cap[k].name, 0, 32);
> +						data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +						sb->channel[j].spi_device_cap[k].name[0] = data8B & 0x000000ff;
> +						sb->channel[j].spi_device_cap[k].name[1] = (data8B & 0x0000ff00) >> 8;
> +						sb->channel[j].spi_device_cap[k].name[2] = (data8B & 0x00ff0000) >> 16;
> +						sb->channel[j].spi_device_cap[k].name[3] = (data8B & 0xff000000) >> 24;
> +						data8B = mem_rx32(sb->bar2_membase, cib_addr, cib_addr_offset++);
> +						sb->channel[j].spi_device_cap[k].name[4] = data8B & 0x000000ff;
> +						sb->channel[j].spi_device_cap[k].name[5] = (data8B & 0x0000ff00) >> 8;
> +						sb->channel[j].spi_device_cap[k].name[6] = (data8B & 0x00ff0000) >> 16;
> +						sb->channel[j].spi_device_cap[k].name[7] = (data8B & 0xff000000) >> 24;
> +					}
> +				}
> +			}
> +
> +			sb->uart_amount = uart_amount;
> +			sunix_sdc_uart_amount = sunix_sdc_uart_amount + sb->uart_amount;
> +
> +			if (sunix_sdc_uart_amount > SUNIX_SDC_UART_MAX)
> +			{
> +				printk("SUNIX: Too much UART channel, maximum %d channels can be supported !\n", SUNIX_SDC_UART_MAX);
> +				status = -EIO;
> +				return status;
> +			}
> +
> +			sb->dio_amount = dio_amount;
> +			sunix_sdc_dio_amount = sunix_sdc_dio_amount + sb->dio_amount;
> +
> +			if (sunix_sdc_dio_amount > SUNIX_SDC_DIO_MAX)
> +			{
> +				printk("SUNIX: Too much DIO channel, maximum %d channels can be supported !\n", SUNIX_SDC_DIO_MAX);
> +				status = -EIO;
> +				return status;
> +			}
> +
> +			sb->spi_amount = spi_amount;
> +			sunix_sdc_spi_amount = sunix_sdc_spi_amount + sb->spi_amount;
> +
> +			if (sunix_sdc_spi_amount > SUNIX_SDC_SPI_MAX)
> +			{
> +				printk("SUNIX: Too much SPI channel, maximum %d channels can be supported !\n", SUNIX_SDC_SPI_MAX);
> +				status = -EIO;
> +				return status;
> +			}
> +		}
> +	}
> +
> +
> +
> +
> +#if (ENABLE_DEBUG_SDC_BUS == 1)

where does that symbol come from ?

> +	for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +	{
> +		sb = &sunix_sdc_board_table[i];
> +
> +		if (sb->board_enum > 0)
> + 		{
> +			printk("=================================\n");
> +			printk("board_enum         : %d\n", sb->board_enum);
> +			printk("board_number       : %d\n", sb->board_number);
> +			printk("bus_number         : %d\n", sb->bus_number);
> +			printk("dev_number         : %d\n", sb->dev_number);
> +			printk("irq                : %d\n", sb->irq);
> +			printk("bar0_membase       : %p\n", sb->bar0_membase);
> +			printk("bar1_iobase        : x%08x\n", sb->bar1_iobase);
> +			printk("bar2_membase       : %p\n", sb->bar2_membase);
> +			printk("major_version      : %d\n", sb->major_version);
> +			printk("minor_version      : %d\n", sb->minor_version);
> +			printk("aval_channels      : %d\n", sb->aval_channels);
> +			printk("model_name         : %s\n", sb->model_name);
> +			printk("uart_amount        : %d\n", sb->uart_amount);
> +			printk("dio_amount         : %d\n", sb->dio_amount);
> +			printk("spi_amount         : %d\n", sb->spi_amount);

certainly not such raw printk()'s (even w/o loglevels) in a driver.

> +			for (j = 0; j < sb->aval_channels; j++)
> +			{
> +				//
> +				if (sb->channel[j].type == 0x00)
> +				{
> +					printk("------------------------------, CONFIG\n");
> +					printk("num                : %d\n", sb->channel[j].num);
> +					printk("type               : %d\n", sb->channel[j].type);
> +					printk("version            : %d\n", sb->channel[j].version);
> +					printk("lengthInDW         : %d\n", sb->channel[j].lengthInDW);
> +					printk("capability         : x%02x\n", sb->channel[j].capability);
> +					printk("event_header_type  : x%02d\n", sb->channel[j].event_header_type);
> +					printk("mem_addr_offset    : x%08x\n", sb->channel[j].mem_addr_offset);
> +					printk("mem_space_size     : %d\n", sb->channel[j].mem_space_size);
> +					printk("cfg_ic_model       : x%02x\n", sb->channel[j].cfg_ic_model);
> +					printk("------------------------------\n");
> +				}
> +				//
> +				//
> +				if (sb->channel[j].type == 0x01)
> +				{
> +					printk("------------------------------, UART\n");
> +					printk("num                : %d\n", sb->channel[j].num);
> +					printk("type               : %d\n", sb->channel[j].type);
> +					printk("version            : %d\n", sb->channel[j].version);
> +					printk("lengthInDW         : %d\n", sb->channel[j].lengthInDW);
> +					printk("capability         : x%02x\n", sb->channel[j].capability);
> +					printk("event_header_type  : x%02d\n", sb->channel[j].event_header_type);
> +					printk("io_addr_offset     : x%08x\n", sb->channel[j].io_addr_offset);
> +					printk("io_space_size      : %d\n", sb->channel[j].io_space_size);
> +					printk("mem_addr_offset    : x%08x\n", sb->channel[j].mem_addr_offset);
> +					printk("mem_space_size     : %d\n", sb->channel[j].mem_space_size);
> +					printk("uart_tx_fifo_size  : %d\n", sb->channel[j].uart_tx_fifo_size);
> +					printk("uart_rx_fifo_size  : %d\n", sb->channel[j].uart_rx_fifo_size);
> +					printk("significand_clock  : %d\n", sb->channel[j].uart_significand_of_clock);
> +					printk("exponent_clock     : %d\n", sb->channel[j].uart_exponent_of_clock);
> +					printk("uart_RS232_cap     : %d\n", sb->channel[j].uart_RS232_cap);
> +					printk("uart_RS422_cap     : %d\n", sb->channel[j].uart_RS422_cap);
> +					printk("uart_RS485_cap     : %d\n", sb->channel[j].uart_RS485_cap);
> +					printk("uart_AHDC_cap      : %d\n", sb->channel[j].uart_AHDC_cap);
> +					printk("uart_CS_cap        : %d\n", sb->channel[j].uart_CS_cap);
> +					printk("uart_auto_RS422485 : %d\n", sb->channel[j].uart_auto_RS422485_cap);
> +					printk("uart_RS422_termin  : %d\n", sb->channel[j].uart_RS422_termination_cap);
> +					printk("uart_RS485_termin  : %d\n", sb->channel[j].uart_RS485_termination_cap);
> +					printk("uart_RI_5V_cap     : %d\n", sb->channel[j].uart_RI_5V_cap);
> +					printk("uart_RI_12V_cap    : %d\n", sb->channel[j].uart_RI_12V_cap);
> +					printk("uart_DCD_5V_cap    : %d\n", sb->channel[j].uart_DCD_5V_cap);
> +					printk("uart_DCD_12V_cap   : %d\n", sb->channel[j].uart_DCD_12V_cap);
> +					printk("------------------------------\n");
> +				}
> +				//
> +				//
> +				if (sb->channel[j].type == 0x02)
> +				{
> +					printk("------------------------------, DIO\n");
> +					printk("num                : %d\n", sb->channel[j].num);
> +					printk("type               : %d\n", sb->channel[j].type);
> +					printk("version            : %d\n", sb->channel[j].version);
> +					printk("lengthInDW         : %d\n", sb->channel[j].lengthInDW);
> +					printk("capability         : x%02x\n", sb->channel[j].capability);
> +					printk("event_header_type  : x%02d\n", sb->channel[j].event_header_type);
> +					printk("mem_addr_offset    : x%08x\n", sb->channel[j].mem_addr_offset);
> +					printk("mem_space_size     : %d\n", sb->channel[j].mem_space_size);
> +					printk("dio_number_of_banks: %d\n", sb->channel[j].dio_number_of_banks);
> +					printk("shares_same_direct : %d\n", sb->channel[j].dio_shares_same_direction_ctrl_cap);
> +					printk("writing_setting    : %d\n", sb->channel[j].dio_writing_setting_to_flash_cap);
> +					for (k = 0; k < sb->channel[j].dio_number_of_banks; k++)
> +					{
> +						printk("++++++++++++++++++++++++++++\n");
> +						printk("number_of_io       : %d\n", sb->channel[j].dio_bank_cap[k].number_of_io);
> +						printk("support_inputs     : %d\n", sb->channel[j].dio_bank_cap[k].support_inputs);
> +						printk("support_outputs    : %d\n", sb->channel[j].dio_bank_cap[k].support_outputs);
> +						printk("rising_trigger     : %d\n", sb->channel[j].dio_bank_cap[k].rising_edge_trigger_cap);
> +						printk("falling_trigger    : %d\n", sb->channel[j].dio_bank_cap[k].falling_edge_trigger_cap);
> +						printk("++++++++++++++++++++++++++++\n");
> +					}
> +					printk("------------------------------\n");
> +				}
> +				//
> +				//
> +				if (sb->channel[j].type == 0x03)
> +				{
> +					printk("------------------------------, SPI\n");
> +					printk("num                : %d\n", sb->channel[j].num);
> +					printk("type               : %d\n", sb->channel[j].type);
> +					printk("version            : %d\n", sb->channel[j].version);
> +					printk("lengthInDW         : %d\n", sb->channel[j].lengthInDW);
> +					printk("capability         : x%02x\n", sb->channel[j].capability);
> +					printk("event_header_type  : x%02d\n", sb->channel[j].event_header_type);
> +					printk("io_addr_offset     : x%08x\n", sb->channel[j].io_addr_offset);
> +					printk("io_space_size      : %d\n", sb->channel[j].io_space_size);
> +					printk("mem_addr_offset    : x%08x\n", sb->channel[j].mem_addr_offset);
> +					printk("mem_space_size     : %d\n", sb->channel[j].mem_space_size);
> +					printk("significand_clock  : %d\n", sb->channel[j].spi_significand_of_clock);
> +					printk("exponent_clock     : %d\n", sb->channel[j].spi_exponent_of_clock);
> +					printk("spi_number_device  : %d\n", sb->channel[j].spi_number_of_device);
> +					for (k = 0; k < sb->channel[j].spi_number_of_device; k++)
> +					{
> +						printk("++++++++++++++++++++++++++++\n");
> +						printk("type               : %d\n", sb->channel[j].spi_device_cap[k].type);
> +						printk("number_gpio_input  : %d\n", sb->channel[j].spi_device_cap[k].number_of_gpio_input);
> +						printk("number_gpio_output : %d\n", sb->channel[j].spi_device_cap[k].number_of_gpio_output);
> +						printk("name               : %s\n", sb->channel[j].spi_device_cap[k].name);
> +						printk("++++++++++++++++++++++++++++\n");
> +					}
> +					printk("------------------------------\n");
> +				}
> +				//
> +			}
> +			printk("=================================\n");
> +		}
> +	}
> +#endif
> +	return status;
> +}
> +
> +
> +static int sunix_assign_resource(void)
> +{
> +	struct sunix_sdc_board *sb = NULL;
> +	struct sunix_sdc_uart_channel *uart_chl = NULL;
> +	struct sunix_sdc_dio_channel *dio_chl = NULL;
> +	struct sunix_sdc_spi_channel *spi_chl = NULL;
> +	int status = 0;
> +	int i;
> +	int j;
> +	int uart_index = 0;
> +	int dio_index = 0;
> +	int spi_index = 0;
> +
> +
> +	memset(sunix_sdc_uart_table, 0, (SUNIX_SDC_UART_MAX + 1) * sizeof(struct sunix_sdc_uart_channel));
> +	memset(sunix_sdc_dio_table, 0, SUNIX_SDC_DIO_MAX * sizeof(struct sunix_sdc_dio_channel));
> +	memset(sunix_sdc_spi_table, 0, SUNIX_SDC_SPI_MAX * sizeof(struct sunix_sdc_spi_channel));
> +
> +	for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +	{
> +		sb = &sunix_sdc_board_table[i];
> +
> +		if (sb->board_enum > 0)
> +		{
> +			if (sb->uart_amount > 0)
> +			{
> +				sb->uart_start_index = uart_index;
> +
> +				for (j = 0; j < sb->aval_channels; j++)
> +				{
> +					if (sb->channel[j].type == 0x01)
> +					{
> +						uart_chl = &sunix_sdc_uart_table[uart_index];
> +
> +						uart_chl->port.iobase = sb->bar1_iobase + sb->channel[j].io_addr_offset;
> +						uart_chl->port.iosize = sb->channel[j].io_space_size;
> +						memcpy(&uart_chl->port.cib_info, &sb->channel[j], sizeof(struct sdc_cib));
> +						memcpy(uart_chl->port.model_name, sb->model_name, sizeof(sb->model_name));
> +
> +						uart_index++;
> +					}
> +				}
> +			}
> +
> +			if (sb->dio_amount > 0)
> +			{
> +				sb->dio_start_index = dio_index;
> +
> +				for (j = 0; j < sb->aval_channels; j++)
> +				{
> +					if (sb->channel[j].type == 0x02)
> +					{
> +						dio_chl = &sunix_sdc_dio_table[dio_index];
> +
> +						dio_chl->info.phy2_base_start = pci_resource_start(sb->pdev, 2);
> +						dio_chl->info.membase = sb->bar2_membase;
> +						dio_chl->info.memoffset = sb->channel[j].mem_addr_offset;
> +						dio_chl->info.memsize = sb->channel[j].mem_space_size;
> +						memcpy(&dio_chl->info.cib_info, &sb->channel[j], sizeof(struct sdc_cib));
> +						memcpy(dio_chl->info.model_name, sb->model_name, sizeof(sb->model_name));
> +
> +						dio_index++;
> +					}
> +				}
> +			}
> +
> +			if (sb->spi_amount > 0)
> +			{
> +				sb->spi_start_index = spi_index;
> +
> +				for (j = 0; j < sb->aval_channels; j++)
> +				{
> +					if (sb->channel[j].type == 0x03)
> +					{
> +						spi_chl = &sunix_sdc_spi_table[spi_index];
> +
> +						spi_chl->info.phy2_base_start = pci_resource_start(sb->pdev, 2);
> +						spi_chl->info.membase = sb->bar2_membase;
> +						spi_chl->info.memoffset = sb->channel[j].mem_addr_offset;
> +						spi_chl->info.memsize = sb->channel[j].mem_space_size;
> +						memcpy(&spi_chl->info.cib_info, &sb->channel[j], sizeof(struct sdc_cib));
> +						memcpy(spi_chl->info.model_name, sb->model_name, sizeof(sb->model_name));
> +
> +						spi_index++;
> +					}
> +				}
> +			}
> +		}
> +	}
> +
> +	return status;
> +}
> +
> +
> +static int sunix_uart_channel_table_init(void)
> +{
> +	struct sunix_sdc_board *sb = NULL;
> +	struct sunix_sdc_uart_channel *uart_chl = NULL;
> +	int status = 0;
> +	int i;
> +	int j;
> +	int n;
> +
> +
> +	for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +	{
> +		sb = &sunix_sdc_board_table[i];
> +
> +		if (sb == NULL)
> +		{
> +			status = -ENXIO;
> +			printk("SUNIX: Board table pointer error !\n");
> +			return status;
> +		}
> +
> +		if ((sb->board_enum > 0) && (sb->uart_amount > 0))
> +		{
> +			n = sb->uart_start_index;
> +
> +			uart_chl = &sunix_sdc_uart_table[n];
> +
> +			if (uart_chl == NULL)
> +			{
> +				status = -ENXIO;
> +				printk("SUNIX: UART port table pointer error !\n");
> +				return status;
> +			}
> +
> +			for (j = 0; j < sb->uart_amount; j++, n++, uart_chl++)
> +			{
> +				uart_chl->port.board_enum	= sb->board_enum;
> +				uart_chl->port.bus_number	= sb->bus_number;
> +				uart_chl->port.dev_number	= sb->dev_number;
> +				uart_chl->port.baud_base = 921600;
> +
> +				uart_chl->port.irq = sb->irq;
> +				uart_chl->port.line = n;
> +				uart_chl->port.uartclk = uart_chl->port.baud_base * 16;
> +				uart_chl->port.iotype = SNX_UPIO_PORT;
> +				uart_chl->port.flags = ASYNC_SHARE_IRQ;
> +				uart_chl->port.ldisc_stop_rx = 0;
> +
> +				spin_lock_init(&uart_chl->port.lock);
> +
> +				uart_chl->port.type = PORT_SER_16750;
> +				uart_chl->port.fifosize = uart_chl->port.cib_info.uart_rx_fifo_size - 8;
> +				uart_chl->port.rx_trigger = uart_chl->port.cib_info.uart_rx_fifo_size / 2;
> +
> +				uart_chl->port.setserial_flag = SNX_SER_BAUD_NOTSETSER;
> +			}
> +
> +			sb->uart_isr = sunix_ser_interrupt;
> +		}
> +		else
> +		{
> +			sb->uart_isr = NULL;
> +		}
> +	}
> +
> +    return status;
> +}
> +
> +
> +static int sunix_dio_channel_table_init(void)
> +{
> +	struct sunix_sdc_board *sb = NULL;
> +	struct sunix_sdc_dio_channel *dio_chl = NULL;
> +	int status = 0;
> +	int i;
> +	int j;
> +	int n;
> +
> +
> +	for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +	{
> +		sb = &sunix_sdc_board_table[i];
> +		if ((sb->board_enum > 0) && (sb->dio_amount > 0))
> +		{
> +			n = sb->dio_start_index;
> +
> +			dio_chl = &sunix_sdc_dio_table[n];
> +			for (j = 0; j < sb->dio_amount; j++, n++, dio_chl++)
> +			{
> +				dio_chl->info.bus_number	= sb->bus_number;
> +				dio_chl->info.dev_number	= sb->dev_number;
> +				dio_chl->info.irq = sb->irq;
> +				dio_chl->info.line = n;
> +
> +				spin_lock_init(&dio_chl->packLock);
> +				SxxListInit(&dio_chl->packList);
> +				init_waitqueue_head(&dio_chl->readWQ);
> +				sema_init(&dio_chl->sem, 1);
> +
> +				dio_chl->isOpened = false;
> +
> +				dio_chl->incomeBuff = NULL;
> +				dio_chl->outcomeBuff = NULL;
> +				dio_chl->translateBuff = NULL;
> +
> +				do
> +				{
> +					dio_chl->incomeBuff = (unsigned char *)kmalloc(SUNIX_SDC_DIO_BUFF, GFP_KERNEL);
> +					if (dio_chl->incomeBuff == NULL)
> +					{
> +						status = -ENOMEM;
> +						break;
> +					}
> +					memset(dio_chl->incomeBuff, 0, SUNIX_SDC_DIO_BUFF);
> +
> +					dio_chl->outcomeBuff = (unsigned char *)kmalloc(SUNIX_SDC_DIO_BUFF, GFP_KERNEL);
> +					if (dio_chl->outcomeBuff == NULL)
> +					{
> +						status = -ENOMEM;
> +						break;
> +					}
> +					memset(dio_chl->outcomeBuff, 0, SUNIX_SDC_DIO_BUFF);
> +
> +					dio_chl->translateBuff = (unsigned char *)kmalloc(SUNIX_SDC_DIO_BUFF, GFP_KERNEL);
> +					if (dio_chl->translateBuff == NULL)
> +					{
> +						status = -ENOMEM;
> +						break;
> +					}
> +					memset(dio_chl->translateBuff, 0, SUNIX_SDC_DIO_BUFF);
> +
> +				} while (false);
> +
> +				if (status != 0)
> +				{
> +					if (dio_chl->incomeBuff != NULL)
> +					{
> +						kfree(dio_chl->incomeBuff);
> +						dio_chl->incomeBuff = NULL;
> +					}
> +
> +					if (dio_chl->outcomeBuff != NULL)
> +					{
> +						kfree(dio_chl->outcomeBuff);
> +						dio_chl->outcomeBuff = NULL;
> +					}
> +
> +					if (dio_chl->translateBuff != NULL)
> +					{
> +						kfree(dio_chl->translateBuff);
> +						dio_chl->translateBuff = NULL;
> +					}
> +					break;
> +				}
> +			}
> +
> +			sb->dio_isr = sunix_dio_interrupt;
> +		}
> +		else
> +		{
> +			sb->dio_isr = NULL;
> +		}
> +
> +		if (status != 0)
> +		{
> +			break;
> +		}
> +	}
> +
> +    return status;
> +}
> +
> +
> +static void sunix_dio_channel_table_deinit(void)
> +{
> +	struct sunix_sdc_board *sb = NULL;
> +	struct sunix_sdc_dio_channel *dio_chl = NULL;
> +	int i;
> +	int j;
> +	int n;
> +
> +
> +	for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +	{
> +		sb = &sunix_sdc_board_table[i];
> +		if ((sb->board_enum > 0) && (sb->dio_amount > 0))
> +		{
> +			n = sb->dio_start_index;
> +
> +			dio_chl = &sunix_sdc_dio_table[n];
> +			for (j = 0; j < sb->dio_amount; j++, n++, dio_chl++)
> +			{
> +				if (dio_chl->incomeBuff != NULL)
> +				{
> +					kfree(dio_chl->incomeBuff);
> +					dio_chl->incomeBuff = NULL;
> +				}
> +
> +				if (dio_chl->outcomeBuff != NULL)
> +				{
> +					kfree(dio_chl->outcomeBuff);
> +					dio_chl->outcomeBuff = NULL;
> +				}
> +
> +				if (dio_chl->translateBuff != NULL)
> +				{
> +					kfree(dio_chl->translateBuff);
> +					dio_chl->translateBuff = NULL;
> +				}
> +			}
> +		}
> +	}
> +}
> +
> +
> +static int sunix_spi_channel_table_init(void)
> +{
> +	struct sunix_sdc_board *sb = NULL;
> +	struct sunix_sdc_spi_channel *spi_chl = NULL;
> +	int status = 0;
> +	int i;
> +	int j;
> +	int n;
> +
> +
> +	for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +	{
> +		sb = &sunix_sdc_board_table[i];
> +		if ((sb->board_enum > 0) && (sb->spi_amount > 0))
> +		{
> +			n = sb->spi_start_index;
> +
> +			spi_chl = &sunix_sdc_spi_table[n];
> +			for (j = 0; j < sb->spi_amount; j++, n++, spi_chl++)
> +			{
> +				spi_chl->info.bus_number	= sb->bus_number;
> +				spi_chl->info.dev_number	= sb->dev_number;
> +				spi_chl->info.irq = sb->irq;
> +				spi_chl->info.line = n;
> +
> +				spin_lock_init(&spi_chl->packLock);
> +				SxxListInit(&spi_chl->packList);
> +				init_waitqueue_head(&spi_chl->readWQ);
> +				sema_init(&spi_chl->sem, 1);
> +
> +				spi_chl->isOpened = false;
> +
> +				spi_chl->incomeBuff = NULL;
> +				spi_chl->outcomeBuff = NULL;
> +				spi_chl->translateBuff = NULL;
> +
> +				do
> +				{
> +					spi_chl->incomeBuff = (unsigned char *)kmalloc(SUNIX_SDC_SPI_BUFF, GFP_KERNEL);
> +					if (spi_chl->incomeBuff == NULL)
> +					{
> +						status = -ENOMEM;
> +						break;
> +					}
> +					memset(spi_chl->incomeBuff, 0, SUNIX_SDC_SPI_BUFF);
> +
> +					spi_chl->outcomeBuff = (unsigned char *)kmalloc(SUNIX_SDC_SPI_BUFF, GFP_KERNEL);
> +					if (spi_chl->outcomeBuff == NULL)
> +					{
> +						status = -ENOMEM;
> +						break;
> +					}
> +					memset(spi_chl->outcomeBuff, 0, SUNIX_SDC_SPI_BUFF);
> +
> +					spi_chl->translateBuff = (unsigned char *)kmalloc(SUNIX_SDC_SPI_BUFF, GFP_KERNEL);
> +					if (spi_chl->translateBuff == NULL)
> +					{
> +						status = -ENOMEM;
> +						break;
> +					}
> +					memset(spi_chl->translateBuff, 0, SUNIX_SDC_SPI_BUFF);
> +
> +				} while (false);
> +
> +				if (status != 0)
> +				{
> +					if (spi_chl->incomeBuff != NULL)
> +					{
> +						kfree(spi_chl->incomeBuff);
> +						spi_chl->incomeBuff = NULL;
> +					}
> +
> +					if (spi_chl->outcomeBuff != NULL)
> +					{
> +						kfree(spi_chl->outcomeBuff);
> +						spi_chl->outcomeBuff = NULL;
> +					}
> +
> +					if (spi_chl->translateBuff != NULL)
> +					{
> +						kfree(spi_chl->translateBuff);
> +						spi_chl->translateBuff = NULL;
> +					}
> +					break;
> +				}
> +			}
> +
> +			sb->spi_isr = sunix_spi_interrupt;
> +		}
> +		else
> +		{
> +			sb->spi_isr = NULL;
> +		}
> +
> +		if (status != 0)
> +		{
> +			break;
> +		}
> +	}
> +
> +    return status;
> +}
> +
> +
> +static void sunix_spi_channel_table_deinit(void)
> +{
> +	struct sunix_sdc_board *sb = NULL;
> +	struct sunix_sdc_spi_channel *spi_chl = NULL;
> +	int i;
> +	int j;
> +	int n;
> +
> +
> +	for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +	{
> +		sb = &sunix_sdc_board_table[i];
> +		if ((sb->board_enum > 0) && (sb->spi_amount > 0))
> +		{
> +			n = sb->spi_start_index;
> +
> +			spi_chl = &sunix_sdc_spi_table[n];
> +			for (j = 0; j < sb->spi_amount; j++, n++, spi_chl++)
> +			{
> +				if (spi_chl->incomeBuff != NULL)
> +				{
> +					kfree(spi_chl->incomeBuff);
> +					spi_chl->incomeBuff = NULL;
> +				}
> +
> +				if (spi_chl->outcomeBuff != NULL)
> +				{
> +					kfree(spi_chl->outcomeBuff);
> +					spi_chl->outcomeBuff = NULL;
> +				}
> +
> +				if (spi_chl->translateBuff != NULL)
> +				{
> +					kfree(spi_chl->translateBuff);
> +					spi_chl->translateBuff = NULL;
> +				}
> +			}
> +		}
> +	}
> +}
> +
> +
> +int sunix_register_irq(void)
> +{
> +	struct sunix_sdc_board *sb = NULL;
> +	int status = 0;
> +	int i;
> +
> +
> +	for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +	{
> +		sb = &sunix_sdc_board_table[i];
> +
> +		if (sb == NULL)
> +		{
> +			status = -ENXIO;
> +			printk("SUNIX: Board table pointer error !\n");
> +			return status;
> +		}
> +
> +		if (sb->board_enum > 0)
> +		{
> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
> +			status = request_irq(sb->irq, sunix_interrupt, IRQF_SHARED, "sunix_sdc", sb);
> +#else
> +			status = request_irq(sb->irq, sunix_interrupt, SA_SHIRQ, "sunix_sdc", sb);
> +#endif
> +			if (status)
> +			{
> +				printk("SUNIX: %s board (bus_num:%d dev_num:%d), request\n", sb->model_name, sb->bus_number, sb->dev_number);
> +				printk("       IRQ %d fail, IRQ %d may be conflit with another device.\n", sb->irq, sb->irq);
> +				return status;
> +			}
> +		}
> +	}
> +
> +	return status;
> +}
> +
> +
> +void sunix_release_irq(void)
> +{
> +	struct sunix_sdc_board *sb = NULL;
> +	int i;
> +
> +
> +	for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +	{
> +		sb = &sunix_sdc_board_table[i];
> +
> +		if (sb->board_enum > 0)
> +		{
> +			free_irq(sb->irq, sb);
> +		}
> +	}
> +}
> +
> +
> +void sunix_release_iomap(void)
> +{
> +	struct sunix_sdc_board *sb = NULL;
> +	int i;
> +
> +
> +	for (i = 0; i < SUNIX_SDC_BOARD_MAX; i++)
> +	{
> +		sb = &sunix_sdc_board_table[i];
> +
> +		if (sb->board_enum > 0)
> +		{
> +			if (sb->bar0_membase != NULL)
> +			{
> +				iounmap(sb->bar0_membase);
> +				sb->bar0_membase = NULL;
> +			}
> +
> +			if (sb->bar2_membase != NULL)
> +			{
> +				iounmap(sb->bar2_membase);
> +				sb->bar2_membase = NULL;
> +			}
> +		}
> +	}
> +}
> +
> +
> +static struct pci_driver snx_pci_driver =
> +{
> +	.name			= "sunix_sdc",
> +	.probe			= snx_pci_probe_one,
> +	.suspend		= snx_suspend_one,
> +	.resume			= snx_resume_one,
> +	.id_table		= sunix_pci_board_id,
> +};
> +
> +
> +static int __init sunix_sdc_init(void)
> +{
> +	int status = 0;
> +
> +
> +	sunix_sdc_board_amount = 0;
> +	sunix_sdc_uart_amount = 0;
> +	sunix_sdc_dio_amount = 0;
> +	sunix_sdc_spi_amount = 0;
> +
> +
> +	sunix_sdc_dio_pack_cache = kmem_cache_create("sunix_sdc_dio", sizeof(DIO_PACKAGE), 0, SLAB_HWCACHE_ALIGN, NULL);
> +	if (sunix_sdc_dio_pack_cache == NULL)
> +		goto step1_fail;
> +
> +	sunix_sdc_spi_pack_cache = kmem_cache_create("sunix_sdc_spi", sizeof(DIO_PACKAGE), 0, SLAB_HWCACHE_ALIGN, NULL);
> +	if (sunix_sdc_spi_pack_cache == NULL)
> +		goto step2_fail;
> +
> +	status = pci_register_driver(&snx_pci_driver);
> +	if (status != 0)
> +		goto step3_fail;
> +
> +	status = sunix_pci_board_probe();
> +	if (status != 0)	
> +		goto step4_fail;
> +
> +	status = sunix_get_pci_board_conf();
> +	if (status != 0)
> +		goto step5_fail;
> +
> +	status = sunix_assign_resource();
> +	if (status != 0)
> +		goto step5_fail;
> +
> +	status = sunix_uart_channel_table_init();
> +	if (status != 0)
> +		goto step5_fail;
> +
> +	status = sunix_dio_channel_table_init();
> +	if (status != 0)
> +		goto step5_fail;
> +
> +	status = sunix_spi_channel_table_init();
> +	if (status != 0)
> +		goto step6_fail;
> +
> +	status = sunix_register_irq();
> +	if (status != 0)
> +		goto step7_fail;
> +
> +	status = sunix_ser_register_driver();
> +	if (status != 0)
> +		goto step8_fail;
> +
> +	status = sunix_ser_register_ports();
> +	if (status != 0)
> +		goto step9_fail;
> +
> +	status = sunix_dio_register_channel();
> +	if (status != 0)
> +		goto step10_fail;
> +
> +	status = sunix_spi_register_channel();
> +	if (status != 0)
> +		goto step11_fail;
> +
> +
> +	return status;
> +
> +
> +step11_fail:
> +	sunix_dio_unregister_channel();
> +
> +step10_fail:
> +	sunix_ser_unregister_ports();
> +
> +step9_fail:
> +	sunix_ser_unregister_driver();
> +
> +step8_fail:
> +	sunix_release_irq();
> +
> +step7_fail:
> +	sunix_spi_channel_table_deinit();
> +
> +step6_fail:
> +	sunix_dio_channel_table_deinit();
> +
> +step5_fail:
> +	sunix_release_iomap();
> +
> +step4_fail:
> +	pci_unregister_driver(&snx_pci_driver);
> +
> +step3_fail:
> +	kmem_cache_destroy(sunix_sdc_spi_pack_cache);
> +
> +step2_fail:
> +	kmem_cache_destroy(sunix_sdc_dio_pack_cache);
> +
> +step1_fail:
> +
> +	return status;
> +}
> +
> +
> +static void __exit sunix_sdc_exit(void)
> +{
> +	sunix_spi_unregister_channel();
> +
> +	sunix_dio_unregister_channel();
> +
> +	sunix_ser_unregister_ports();
> +
> +	sunix_ser_unregister_driver();
> +
> +	sunix_release_irq();
> +
> +	sunix_spi_channel_table_deinit();
> +
> +	sunix_dio_channel_table_deinit();
> +
> +	sunix_release_iomap();
> +
> +	pci_unregister_driver(&snx_pci_driver);
> +
> +	kmem_cache_destroy(sunix_sdc_spi_pack_cache);
> +
> +	kmem_cache_destroy(sunix_sdc_dio_pack_cache);
> +}
> +
> +
> +module_init(sunix_sdc_init);
> +module_exit(sunix_sdc_exit);
> +
> +
> +MODULE_AUTHOR("SUNIX Co., Ltd.<info@...ix.com.tw>");
> +MODULE_DESCRIPTION("SUNIX PCI(e) expansion board bus driver");
> +MODULE_LICENSE("GPL");
> +
> +
> diff --git a/drivers/mfd/dio.c b/drivers/mfd/dio.c
> new file mode 100644
> index 000000000000..216280194d1b
> --- /dev/null
> +++ b/drivers/mfd/dio.c
> @@ -0,0 +1,529 @@
> +
> +
> +#include "sdc_include.h"
> +
> +
> +static int sunix_dio_open(struct inode *inode, struct file *file)
> +{
> +	int line = MINOR(file->f_path.dentry->d_inode->i_rdev);
> +	struct sunix_sdc_dio_channel *dio_chl = NULL;
> +	int status = 0;
> +
> +
> +	do
> +	{
> +		if (line > SUNIX_SDC_DIO_MAX)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		dio_chl = &sunix_sdc_dio_table[line];
> +		if (dio_chl->info.memsize == 0)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		if (dio_chl->isOpened == true)
> +		{
> +			status = -EBUSY;
> +			break;
> +		}
> +
> +
> +		dio_chl->InputInvertEnableReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 2);
> +		dio_chl->InputLatchRegPositiveEdgeR = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 3);
> +		dio_chl->InputLatchRegNegativeEdgeR = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 4);
> +		dio_chl->InputCounterIncrementCtrlRegPositiveEdge = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 6);
> +		dio_chl->InputCounterIncrementCtrlRegNegativeEdge = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 7);
> +		dio_chl->InputRisingEventCtrlReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 8);
> +		dio_chl->InputFallingEventCtrlReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 9);
> +		dio_chl->DirectionCtrlReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 12);
> +		dio_chl->OutputInitialValueReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 13);

Why a completely own, proprietary character device, instead of just
pluggin into gpio (or IIO, if its a streaming DIO) subsystem ?

> +
> +		dio_chl->readDataReady = 0;
> +		dio_chl->isOpened = true;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +		try_module_get(THIS_MODULE);
> +#else
> +		MOD_INC_USE_COUNT;
> +#endif
> +
> +	} while (false);
> +
> +	return status;
> +}
> +
> +
> +static int sunix_dio_release(struct inode *inode, struct file *file)
> +{
> +	int line = MINOR(file->f_path.dentry->d_inode->i_rdev);
> +	struct sunix_sdc_dio_channel *dio_chl = NULL;
> +	int status = 0;
> +	DLIST * pListHead = NULL;
> +	DLIST * e = NULL;
> +	unsigned long Flags;
> +	PDIO_PACKAGE pPack = NULL;
> +
> +
> +	do
> +	{
> +		if (line > SUNIX_SDC_DIO_MAX)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		dio_chl = &sunix_sdc_dio_table[line];
> +		if (dio_chl->info.memsize == 0)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		if (dio_chl->isOpened == false)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +
> +		pListHead = &dio_chl->packList;
> +		spin_lock_irqsave(&dio_chl->packLock, Flags);
> +		while (!SxxListEmpty(pListHead))
> +		{
> +			e = SxxListGetNext(pListHead);
> +			pPack = SUNIX_SDC_DIO_PACK_PTR(e);
> +			if (pPack != NULL)
> +			{
> +				printk("SUNIX: DIO FREE pack, line:%d, pack:x%p, DataPtrx%p\n", dio_chl->info.line, pPack, pPack->DataPtr);
> +				SxxListRemoveEntry(e);
> +				if (pPack->DataPtr != NULL)
> +				{
> +					kfree(pPack->DataPtr);
> +					pPack->DataPtr = NULL;
> +				}
> +				kmem_cache_free(sunix_sdc_dio_pack_cache, pPack);
> +				pPack = NULL;
> +			}
> +		}
> +		spin_unlock_irqrestore(&dio_chl->packLock, Flags);
> +
> +		dio_chl->isOpened = false;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +		module_put(THIS_MODULE);
> +#else
> +		MOD_DEC_USE_COUNT;
> +#endif
> +
> +	} while (false);
> +
> +	return status;
> +}
> +
> +
> +static long sunix_dio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> +{
> +	int line = MINOR(file->f_path.dentry->d_inode->i_rdev);
> +	struct sunix_sdc_dio_channel *dio_chl = NULL;
> +	int status = 0;
> +
> +
> +	do
> +	{
> +		if (line > SUNIX_SDC_DIO_MAX)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		dio_chl = &sunix_sdc_dio_table[line];
> +		if (dio_chl->info.memsize == 0)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		if (dio_chl->isOpened == false)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	return status;
> +}
> +
> +
> +static ssize_t sunix_dio_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
> +{
> +	int line = MINOR(file->f_path.dentry->d_inode->i_rdev);
> +	struct sunix_sdc_dio_channel *dio_chl = NULL;
> +	int status = 0;
> +	unsigned int outcomeLength = 0;
> +
> +
> +	if (line > SUNIX_SDC_DIO_MAX)
> +	{
> +		return -ENODEV;
> +	}
> +	dio_chl = &sunix_sdc_dio_table[line];
> +	if (dio_chl->info.memsize == 0)
> +	{
> +		return -ENODEV;
> +	}
> +	if (dio_chl->isOpened == false)
> +	{
> +		return -ENODEV;
> +	}
> +
> +	if (count < sizeof(DIO_HEADER))
> +	{
> +		return -ENOMEM;
> +	}
> +
> +
> +	if (down_interruptible(&dio_chl->sem))
> +	{
> +		return -ERESTARTSYS;
> +	}
> +
> +	if (dio_chl->readDataReady == 0)
> +	{
> +		up(&dio_chl->sem);
> +
> +		if ((file->f_flags & O_NONBLOCK))
> +		{
> +			return -EAGAIN;
> +		}
> +
> +		wait_event_interruptible(dio_chl->readWQ, dio_chl->readDataReady == 1);
> +
> +		if (down_interruptible(&dio_chl->sem))
> +		{
> +			return -ERESTARTSYS;
> +		}
> +	}
> +
> +
> +	do
> +	{
> +		status = sunix_dio_handle_outcome(dio_chl, count, &outcomeLength);
> +		if (status != 0)
> +		{
> +			break;
> +		}
> +		if (count < outcomeLength)
> +		{
> +			status = -ENOMEM;
> +			break;
> +		}
> +		if (outcomeLength <= 0)
> +		{
> +			status = 0;
> +			break;
> +		}
> +
> +		if (copy_to_user((void *)buf, dio_chl->outcomeBuff, outcomeLength))
> +		{
> +			status = -EFAULT;
> +			break;
> +		}
> +
> +		status = outcomeLength;
> +
> +	} while (false);
> +
> +
> +	dio_chl->readDataReady = 0;
> +	up(&dio_chl->sem);
> +
> +	return status;
> +}
> +
> +
> +static ssize_t sunix_dio_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
> +{
> +	int line = MINOR(file->f_path.dentry->d_inode->i_rdev);
> +	struct sunix_sdc_dio_channel *dio_chl = NULL;
> +	int status = 0;
> +
> +
> +	do
> +	{
> +		if (line > SUNIX_SDC_DIO_MAX)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		dio_chl = &sunix_sdc_dio_table[line];
> +		if (dio_chl->info.memsize == 0)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		if (dio_chl->isOpened == false)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +
> +		if (count < sizeof(DIO_HEADER))
> +		{
> +			status = -EFAULT;
> +			break;
> +		}
> +
> +		if (count > (sizeof(DIO_HEADER) + DIO_MAX_DATA_LENGTH))
> +		{
> +			status = -ENOMEM;
> +			break;
> +		}
> +
> +		if (copy_from_user(dio_chl->incomeBuff, (void *)buf, count))
> +		{
> +			status = -EFAULT;
> +			break;
> +		}
> +
> +		status = sunix_dio_handle_income(dio_chl, count);
> +		if (status == 0)
> +		{
> +			status = count;
> +		}
> +
> +	} while (false);
> +
> +	return status;
> +}
> +
> +
> +unsigned int sunix_dio_poll(struct file *file, poll_table *wait)
> +{
> +	int line = MINOR(file->f_path.dentry->d_inode->i_rdev);
> +	struct sunix_sdc_dio_channel *dio_chl = NULL;
> +	unsigned int mask = POLLOUT | POLLWRNORM;
> +
> +
> +	do
> +	{
> +		if (line > SUNIX_SDC_DIO_MAX)
> +		{
> +			mask = -ENODEV;
> +			break;
> +		}
> +		dio_chl = &sunix_sdc_dio_table[line];
> +		if (dio_chl->info.memsize == 0)
> +		{
> +			mask = -ENODEV;
> +			break;
> +		}
> +		if (dio_chl->isOpened == false)
> +		{
> +			mask = -ENODEV;
> +			break;
> +		}
> +
> +
> +		down(&dio_chl->sem);
> +
> +		poll_wait(file, &dio_chl->readWQ, wait);
> +
> +		if (dio_chl->readDataReady == 1)
> +		{
> +			mask |= (POLLIN | POLLRDNORM);
> +		}
> +
> +		up(&dio_chl->sem);
> +
> +	} while (false);
> +
> +	return mask;
> +}
> +
> +
> +static int sunix_dio_uevent(struct device *dev, struct kobj_uevent_env *env)
> +{
> +	add_uevent_var(env, "DEVMODE=%#o", 0666);
> +	return 0;
> +}
> +
> +
> +static const struct file_operations sunix_sdc_dio_fops =
> +{
> +	.owner				= THIS_MODULE,
> +	.open				= sunix_dio_open,
> +	.release			= sunix_dio_release,
> +	.unlocked_ioctl		= sunix_dio_ioctl,
> +	.read				= sunix_dio_read,
> +	.write 				= sunix_dio_write,
> +	.poll				= sunix_dio_poll
> +};
> +
> +
> +static int sunix_sdc_dio_dev_major = 0;
> +static struct class *sunix_sdc_dio_dev_class = NULL;
> +
> +
> +int sunix_dio_register_channel(void)
> +{
> +	int err, i;
> +	dev_t dev;
> +	struct sunix_sdc_dio_channel *dio_chl = NULL;
> +
> +
> +	err = alloc_chrdev_region(&dev, 0, sunix_sdc_dio_amount, "sunix_sdc_dio");
> +	if (err != 0)
> +	{
> +		return err;
> +	}
> +
> +	sunix_sdc_dio_dev_major = MAJOR(dev);
> +
> +	sunix_sdc_dio_dev_class = class_create(THIS_MODULE, "sunix_sdc_dio");
> +	sunix_sdc_dio_dev_class->dev_uevent = sunix_dio_uevent;
> +
> +	for (i = 0; i < sunix_sdc_dio_amount; i++)
> +	{
> +		dio_chl = &sunix_sdc_dio_table[i];
> +		if ((dio_chl != NULL) && (dio_chl->info.membase != NULL))
> +		{
> +			request_mem_region(dio_chl->info.phy2_base_start + dio_chl->info.memoffset, dio_chl->info.memsize, "sunix_sdc_dio");
> +
> +			cdev_init(&dio_chl->cdev, &sunix_sdc_dio_fops);
> +			dio_chl->cdev.owner = THIS_MODULE;
> +
> +			cdev_add(&dio_chl->cdev, MKDEV(sunix_sdc_dio_dev_major, i), 1);
> +
> +			device_create(sunix_sdc_dio_dev_class, NULL, MKDEV(sunix_sdc_dio_dev_major, i), NULL, "SDCDIO%d", i);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +
> +void sunix_dio_unregister_channel(void)
> +{
> +	int i;
> +	struct sunix_sdc_dio_channel *dio_chl = NULL;
> +
> +
> +	for (i = 0; i < sunix_sdc_dio_amount; i++)
> +	{
> +		dio_chl = &sunix_sdc_dio_table[i];
> +		if ((dio_chl != NULL) && (dio_chl->info.membase != NULL))
> +		{
> +			device_destroy(sunix_sdc_dio_dev_class, MKDEV(sunix_sdc_dio_dev_major, i));
> +
> +			release_mem_region(dio_chl->info.phy2_base_start + dio_chl->info.memoffset, dio_chl->info.memsize);
> +		}
> +	}
> +
> +	class_unregister(sunix_sdc_dio_dev_class);
> +	class_destroy(sunix_sdc_dio_dev_class);
> +
> +	unregister_chrdev_region(MKDEV(sunix_sdc_dio_dev_major, 0), MINORMASK);
> +}
> +
> +
> +int sunix_dio_interrupt(struct sunix_sdc_dio_channel *dio_chl, unsigned int event_header)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	unsigned int InputValue = 0;
> +	unsigned int BankInputValue = 0;
> +	unsigned int BankInputDelta = 0;
> +	int i = 0;
> +	unsigned char TxBuff[256];
> +	unsigned int TxLength = 0;
> +	PDIO_HEADER pTxHeader = (PDIO_HEADER)TxBuff;
> +	PDIO_PACKAGE pPack = NULL;
> +	bool bCreatePackSuccess = false;
> +	unsigned long Flags;
> +
> +
> +	InputValue = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 0);
> +
> +	for (i = 0; i < cib_info->dio_number_of_banks; i++)
> +	{
> +		if ((cib_info->dio_bank_cap[i].io_mask & event_header) && (cib_info->dio_bank_cap[i].support_inputs == 0x01))
> +		{
> +			BankInputValue = ((InputValue & cib_info->dio_bank_cap[i].io_mask) >> cib_info->dio_bank_cap[i].io_shift_bits);
> +			BankInputDelta = ((event_header & cib_info->dio_bank_cap[i].io_mask) >> cib_info->dio_bank_cap[i].io_shift_bits);
> +
> +
> +			memset(TxBuff, 0, sizeof(TxBuff));
> +			TxLength = 0;
> +
> +			pTxHeader->Version = 0x01;
> +			pTxHeader->CmdResponseEventData = SDCDIO_EVENT;
> +			pTxHeader->ResponseStatus = SDCDIO_STATUS_SUCCESS;
> +			pTxHeader->Length = 9;
> +			TxLength = sizeof(DIO_HEADER);
> +
> +			TxBuff[TxLength++] = i;
> +
> +			TxBuff[TxLength++] = (unsigned char)((BankInputDelta & 0xff000000) >> 24);
> +			TxBuff[TxLength++] = (unsigned char)((BankInputDelta & 0x00ff0000) >> 16);
> +			TxBuff[TxLength++] = (unsigned char)((BankInputDelta & 0x0000ff00) >> 8);
> +			TxBuff[TxLength++] = (unsigned char)((BankInputDelta & 0x000000ff));
> +
> +			TxBuff[TxLength++] = (unsigned char)((BankInputValue & 0xff000000) >> 24);
> +			TxBuff[TxLength++] = (unsigned char)((BankInputValue & 0x00ff0000) >> 16);
> +			TxBuff[TxLength++] = (unsigned char)((BankInputValue & 0x0000ff00) >> 8);
> +			TxBuff[TxLength++] = (unsigned char)((BankInputValue & 0x000000ff));
> +
> +
> +			do
> +			{
> +				pPack = NULL;
> +				bCreatePackSuccess = false;
> +
> +				pPack = kmem_cache_alloc(sunix_sdc_dio_pack_cache, GFP_ATOMIC);
> +				if (pPack == NULL)
> +				{
> +					break;
> +				}
> +				memset(pPack, 0, sizeof(DIO_PACKAGE));
> +
> +				pPack->DataPtr = (unsigned char *)kmalloc(DIO_MAX_DATA_LENGTH, GFP_KERNEL);
> +				if (pPack->DataPtr == NULL)
> +				{
> +					break;
> +				}
> +				memset(pPack->DataPtr, 0, DIO_MAX_DATA_LENGTH);
> +
> +				SxxListInit(&pPack->Entry);
> +				memcpy(&pPack->Header, pTxHeader, sizeof(DIO_HEADER));
> +				memcpy(pPack->DataPtr, TxBuff + sizeof(DIO_HEADER), pTxHeader->Length);
> +
> +				spin_lock_irqsave(&dio_chl->packLock, Flags);
> +				//printk("SUNIX: DIO ALOC pack, line:%d, pack:x%p, DataPtrx%p\n", dio_chl->info.line, pPack, pPack->DataPtr);
> +				SxxListInsertTail(&dio_chl->packList, &pPack->Entry);
> +
> +				dio_chl->readDataReady = 1;
> +				wake_up_interruptible(&dio_chl->readWQ);
> +				spin_unlock_irqrestore(&dio_chl->packLock, Flags);
> +
> +				bCreatePackSuccess = true;
> +
> +			} while (false);
> +
> +			if (bCreatePackSuccess == false)
> +			{
> +				if (pPack != NULL)
> +				{
> +					if (pPack->DataPtr != NULL)
> +					{
> +						kfree(pPack->DataPtr);
> +						pPack->DataPtr = NULL;
> +					}
> +
> +					kmem_cache_free(sunix_sdc_dio_pack_cache, pPack);
> +					pPack = NULL;
> +				}
> +			}
> +		}
> +	}
> +
> +    return 0;
> +}
> +
> +
> diff --git a/drivers/mfd/dio_pack.c b/drivers/mfd/dio_pack.c
> new file mode 100644
> index 000000000000..29e623918a45
> --- /dev/null
> +++ b/drivers/mfd/dio_pack.c
> @@ -0,0 +1,3126 @@
> +
> +
> +#include "sdc_include.h"
> +
> +
> +static void get_info(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int Address = 0;
> +	int i = 0;
> +	unsigned int BankDirection = 0;
> +
> +
> +	do
> +	{
> +		Address = dio_chl->info.phy2_base_start + dio_chl->info.memoffset;
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?(28 + (cib_info->dio_number_of_banks * 18)):0;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		memcpy(&TrBuff[TrLength], dio_chl->info.model_name, 16);
> +		TrLength += 16;
> +		TrBuff[TrLength++] = dio_chl->info.bus_number;
> +		TrBuff[TrLength++] = dio_chl->info.dev_number;
> +		TrBuff[TrLength++] = dio_chl->info.line;
> +		TrBuff[TrLength++] = (unsigned char)((Address & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((Address & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((Address & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((Address & 0x000000ff));
> +		TrBuff[TrLength++] = (unsigned char)(dio_chl->info.irq);
> +
> +		TrBuff[TrLength++] = cib_info->version;
> +		TrBuff[TrLength++] = cib_info->dio_number_of_banks;
> +		TrBuff[TrLength++] = cib_info->dio_shares_same_direction_ctrl_cap;
> +		TrBuff[TrLength++] = cib_info->dio_writing_setting_to_flash_cap;
> +
> +		for (i = 0; i < cib_info->dio_number_of_banks; i++)
> +		{
> +			BankDirection = (dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[i].io_mask) >>cib_info->dio_bank_cap[i].io_shift_bits;
> +
> +			TrBuff[TrLength++] = i;
> +			TrBuff[TrLength++] = cib_info->dio_bank_cap[i].number_of_io;
> +			TrBuff[TrLength++] = cib_info->dio_bank_cap[i].support_inputs;
> +			TrBuff[TrLength++] = cib_info->dio_bank_cap[i].support_outputs;
> +			TrBuff[TrLength++] = cib_info->dio_bank_cap[i].rising_edge_trigger_cap;
> +			TrBuff[TrLength++] = cib_info->dio_bank_cap[i].falling_edge_trigger_cap;
> +
> +			TrBuff[TrLength++] = (unsigned char)((cib_info->dio_bank_cap[i].io_mask & 0xff000000) >> 24);
> +			TrBuff[TrLength++] = (unsigned char)((cib_info->dio_bank_cap[i].io_mask & 0x00ff0000) >> 16);
> +			TrBuff[TrLength++] = (unsigned char)((cib_info->dio_bank_cap[i].io_mask & 0x0000ff00) >> 8);
> +			TrBuff[TrLength++] = (unsigned char)((cib_info->dio_bank_cap[i].io_mask & 0x000000ff));
> +			TrBuff[TrLength++] = (unsigned char)((cib_info->dio_bank_cap[i].io_shift_bits & 0xff000000) >> 24);
> +			TrBuff[TrLength++] = (unsigned char)((cib_info->dio_bank_cap[i].io_shift_bits & 0x00ff0000) >> 16);
> +			TrBuff[TrLength++] = (unsigned char)((cib_info->dio_bank_cap[i].io_shift_bits & 0x0000ff00) >> 8);
> +			TrBuff[TrLength++] = (unsigned char)((cib_info->dio_bank_cap[i].io_shift_bits & 0x000000ff));
> +			TrBuff[TrLength++] = (unsigned char)((BankDirection & 0xff000000) >> 24);
> +			TrBuff[TrLength++] = (unsigned char)((BankDirection & 0x00ff0000) >> 16);
> +			TrBuff[TrLength++] = (unsigned char)((BankDirection & 0x0000ff00) >> 8);
> +			TrBuff[TrLength++] = (unsigned char)((BankDirection & 0x000000ff));
> +		}
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_bank_state(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankState = 0;
> +	unsigned int InputReg = 0;
> +	unsigned int OutputReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			InputReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 0);
> +			//printk("SUNIX: DIO (%d), get bank state, INDIVIDUAL (input), 1, InputReg:x%08x\n", dio_chl->info.line, InputReg);
> +			InputReg &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank state, INDIVIDUAL (input), 2, InputReg:x%08x\n", dio_chl->info.line, InputReg);
> +			InputReg &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank state, INDIVIDUAL (input), 3, InputReg:x%08x\n", dio_chl->info.line, InputReg);
> +
> +			OutputReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 11);
> +			//printk("SUNIX: DIO (%d), get bank state, INDIVIDUAL (output), 4, OutputReg:x%08x\n", dio_chl->info.line, OutputReg);
> +			OutputReg &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank state, INDIVIDUAL (output), 5, OutputReg:x%08x\n", dio_chl->info.line, OutputReg);
> +			OutputReg &= dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank state, INDIVIDUAL (output), 6, OutputReg:x%08x\n", dio_chl->info.line, OutputReg);
> +
> +			BankState = (InputReg | OutputReg) & cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank state, INDIVIDUAL, 7, BankState:x%08x\n", dio_chl->info.line, BankState);
> +			BankState = BankState >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank state, INDIVIDUAL, 8, BankState:x%08x\n", dio_chl->info.line, BankState);
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 0);
> +			//printk("SUNIX: DIO (%d), get bank state, WHOLE (input), 1, InputReg:x%08x\n", dio_chl->info.line, InputReg);
> +			BankState = InputReg & cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank state, WHOLE (input), 2, BankState:x%08x\n", dio_chl->info.line, BankState);
> +			BankState = BankState >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank state, WHOLE (input), 3, BankState:x%08x\n", dio_chl->info.line, BankState);
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			OutputReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 11);
> +			//printk("SUNIX: DIO (%d), get bank state, WHOLE (output), 1, OutputReg:x%08x\n", dio_chl->info.line, OutputReg);
> +			BankState = OutputReg & cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank state, WHOLE (output), 2, BankState:x%08x\n", dio_chl->info.line, BankState);
> +			BankState = BankState >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank state, WHOLE (output), 3, BankState:x%08x\n", dio_chl->info.line, BankState);
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?5:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = (unsigned char)((BankState & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((BankState & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((BankState & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((BankState & 0x000000ff));
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_bank_input_delta_state(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankDeltaState = 0;
> +	unsigned int InputDeltaReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank input delta state, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputDeltaReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 1);
> +			//printk("SUNIX: DIO (%d), get bank input delta state, INDIVIDUAL, 1, InputDeltaReg:x%08x\n", dio_chl->info.line, InputDeltaReg);
> +			InputDeltaReg &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input delta state, INDIVIDUAL, 2, InputDeltaReg:x%08x\n", dio_chl->info.line, InputDeltaReg);
> +			InputDeltaReg &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank input delta state, INDIVIDUAL, 3, InputDeltaReg:x%08x\n", dio_chl->info.line, InputDeltaReg);
> +			BankDeltaState = InputDeltaReg >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input delta state, INDIVIDUAL, 4, BankDeltaState:x%08x\n", dio_chl->info.line, BankDeltaState);
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputDeltaReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 1);
> +			//printk("SUNIX: DIO (%d), get bank input delta state, WHOLE (input), 1, InputDeltaReg:x%08x\n", dio_chl->info.line, InputDeltaReg);
> +			BankDeltaState = InputDeltaReg & cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input delta state, WHOLE (input), 2, BankDeltaState:x%08x\n", dio_chl->info.line, BankDeltaState);
> +			BankDeltaState = BankDeltaState >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input delta state, WHOLE (input), 3, BankDeltaState:x%08x\n", dio_chl->info.line, BankDeltaState);
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?5:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = (unsigned char)((BankDeltaState & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((BankDeltaState & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((BankDeltaState & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((BankDeltaState & 0x000000ff));
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_bank_input_invert_enable(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputInvertEnable = 0;
> +	unsigned int InputInvertEnableReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank input inver enable, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputInvertEnableReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 2);
> +			BankInputInvertEnable = InputInvertEnableReg;
> +			//printk("SUNIX: DIO (%d), get bank input inver enable, INDIVIDUAL, 1, BankInputInvertEnable:x%08x\n", dio_chl->info.line, BankInputInvertEnable);
> +			BankInputInvertEnable &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input inver enable, INDIVIDUAL, 2, BankInputInvertEnable:x%08x\n", dio_chl->info.line, BankInputInvertEnable);
> +			BankInputInvertEnable &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank input inver enable, INDIVIDUAL, 3, BankInputInvertEnable:x%08x\n", dio_chl->info.line, BankInputInvertEnable);
> +			BankInputInvertEnable = BankInputInvertEnable >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input inver enable, INDIVIDUAL, 4, BankInputInvertEnable:x%08x\n", dio_chl->info.line, BankInputInvertEnable);
> +
> +			dio_chl->InputInvertEnableReg = InputInvertEnableReg;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputInvertEnableReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 2);
> +			BankInputInvertEnable = InputInvertEnableReg;
> +			//printk("SUNIX: DIO (%d), get bank input inver enable, WHOLE (input), 1, BankInputInvertEnable:x%08x\n", dio_chl->info.line, BankInputInvertEnable);
> +			BankInputInvertEnable &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input inver enable, WHOLE (input), 2, BankInputInvertEnable:x%08x\n", dio_chl->info.line, BankInputInvertEnable);
> +			BankInputInvertEnable = BankInputInvertEnable >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input inver enable, WHOLE (input), 3, BankInputInvertEnable:x%08x\n", dio_chl->info.line, BankInputInvertEnable);
> +
> +			dio_chl->InputInvertEnableReg = InputInvertEnableReg;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?5:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = (unsigned char)((BankInputInvertEnable & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputInvertEnable & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputInvertEnable & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputInvertEnable & 0x000000ff));
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_bank_input_invert_enable(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputInvertEnable = 0;
> +	unsigned int InputInvertEnableRegByBank = 0;
> +	unsigned int InputInvertEnableReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 5)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +		BankInputInvertEnable  =  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 1) << 24);
> +		BankInputInvertEnable |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 2) << 16);
> +		BankInputInvertEnable |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 3) << 8);
> +		BankInputInvertEnable |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 4));
> +		//printk("SUNIX: DIO (%d), set bank input inver enable, BankIndex:x%02x, BankInputInvertEnable:x%08x\n", dio_chl->info.line, BankIndex, BankInputInvertEnable);
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), set bank input inver enable, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			BankInputInvertEnable &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), set bank input inver enable, INDIVIDUAL, 1, BankInputInvertEnable:x%08x\n", dio_chl->info.line, BankInputInvertEnable);
> +			InputInvertEnableRegByBank = BankInputInvertEnable << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input inver enable, INDIVIDUAL, 2, InputInvertEnableRegByBank:x%08x\n", dio_chl->info.line, InputInvertEnableRegByBank);
> +			InputInvertEnableRegByBank &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input inver enable, INDIVIDUAL, 3, InputInvertEnableRegByBank:x%08x\n", dio_chl->info.line, InputInvertEnableRegByBank);
> +			InputInvertEnableReg = dio_chl->InputInvertEnableReg & ~cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input inver enable, INDIVIDUAL, 4, InputInvertEnableReg:x%08x\n", dio_chl->info.line, InputInvertEnableReg);
> +			InputInvertEnableReg |= InputInvertEnableRegByBank;
> +			//printk("SUNIX: DIO (%d), set bank input inver enable, INDIVIDUAL, 5, InputInvertEnableReg:x%08x\n", dio_chl->info.line, InputInvertEnableReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 2, InputInvertEnableReg);
> +			dio_chl->InputInvertEnableReg = InputInvertEnableReg;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputInvertEnableRegByBank = BankInputInvertEnable << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input inver enable, WHOLE (input), 1, InputInvertEnableRegByBank:x%08x\n", dio_chl->info.line, InputInvertEnableRegByBank);
> +			InputInvertEnableRegByBank &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input inver enable, WHOLE (input), 2, InputInvertEnableRegByBank:x%08x\n", dio_chl->info.line, InputInvertEnableRegByBank);
> +			InputInvertEnableReg = dio_chl->InputInvertEnableReg & ~cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input inver enable, WHOLE (input), 3, InputInvertEnableReg:x%08x\n", dio_chl->info.line, InputInvertEnableReg);
> +			InputInvertEnableReg |= InputInvertEnableRegByBank;
> +			//printk("SUNIX: DIO (%d), set bank input inver enable, WHOLE (input), 4, InputInvertEnableReg:x%08x\n", dio_chl->info.line, InputInvertEnableReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 2, InputInvertEnableReg);
> +			dio_chl->InputInvertEnableReg = InputInvertEnableReg;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?1:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_bank_input_latch_rising_edge(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputLatch = 0;
> +	unsigned int InputLatchRegPositiveEdgeR = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].rising_edge_trigger_cap != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_RISING_EDGE_TRIGGER_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank input latch rising edge, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputLatchRegPositiveEdgeR = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 3);
> +			BankInputLatch = InputLatchRegPositiveEdgeR;
> +			//printk("SUNIX: DIO (%d), get bank input latch rising edge, INDIVIDUAL, 1, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +			BankInputLatch &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input latch rising edge, INDIVIDUAL, 2, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +			BankInputLatch &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank input latch rising edge, INDIVIDUAL, 3, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +			BankInputLatch = BankInputLatch >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input latch rising edge, INDIVIDUAL, 4, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +
> +			dio_chl->InputLatchRegPositiveEdgeR = InputLatchRegPositiveEdgeR;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputLatchRegPositiveEdgeR = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 3);
> +			BankInputLatch = InputLatchRegPositiveEdgeR;
> +			//printk("SUNIX: DIO (%d), get bank input latch rising edge, WHOLE (input), 1, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +			BankInputLatch &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input latch rising edge, WHOLE (input), 2, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +			BankInputLatch = BankInputLatch >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input latch rising edge, WHOLE (input), 3, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +
> +			dio_chl->InputLatchRegPositiveEdgeR = InputLatchRegPositiveEdgeR;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?5:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = (unsigned char)((BankInputLatch & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputLatch & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputLatch & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputLatch & 0x000000ff));
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_bank_input_latch_rising_edge(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputLatch = 0;
> +	unsigned int InputLatchRegPositiveEdgeW = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 5)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +		BankInputLatch  =  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 1) << 24);
> +		BankInputLatch |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 2) << 16);
> +		BankInputLatch |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 3) << 8);
> +		BankInputLatch |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 4));
> +		//printk("SUNIX: DIO (%d), set bank input latch rising edge, BankIndex:x%02x, BankInputLatch:x%08x\n", dio_chl->info.line, BankIndex, BankInputLatch);
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].rising_edge_trigger_cap != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_RISING_EDGE_TRIGGER_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), set bank input latch rising edge, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputLatchRegPositiveEdgeW = BankInputLatch << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input latch rising edge, INDIVIDUAL, 1, InputLatchRegPositiveEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegPositiveEdgeW);
> +			InputLatchRegPositiveEdgeW &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input latch rising edge, INDIVIDUAL, 2, InputLatchRegPositiveEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegPositiveEdgeW);
> +			InputLatchRegPositiveEdgeW &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), set bank input latch rising edge, INDIVIDUAL, 3, InputLatchRegPositiveEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegPositiveEdgeW);
> +			InputLatchRegPositiveEdgeW |= (dio_chl->InputLatchRegPositiveEdgeW & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank input latch rising edge, INDIVIDUAL, 4, InputLatchRegPositiveEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegPositiveEdgeW);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 3, InputLatchRegPositiveEdgeW);
> +			dio_chl->InputLatchRegPositiveEdgeW = InputLatchRegPositiveEdgeW;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputLatchRegPositiveEdgeW = BankInputLatch << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input latch rising edge, WHOLE (input), 1, InputLatchRegPositiveEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegPositiveEdgeW);
> +			InputLatchRegPositiveEdgeW &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input latch rising edge, WHOLE (input), 2, InputLatchRegPositiveEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegPositiveEdgeW);
> +			InputLatchRegPositiveEdgeW |= (dio_chl->InputLatchRegPositiveEdgeW & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank input latch rising edge, WHOLE (input), 3, InputLatchRegPositiveEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegPositiveEdgeW);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 3, InputLatchRegPositiveEdgeW);
> +			dio_chl->InputLatchRegPositiveEdgeW = InputLatchRegPositiveEdgeW;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?1:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_bank_input_latch_falling_edge(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputLatch = 0;
> +	unsigned int InputLatchRegNegativeEdgeR = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].falling_edge_trigger_cap != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_FALLING_EDGE_TRIGGER_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank input latch falling edge, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputLatchRegNegativeEdgeR = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 4);
> +			BankInputLatch = InputLatchRegNegativeEdgeR;
> +			//printk("SUNIX: DIO (%d), get bank input latch falling edge, INDIVIDUAL, 1, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +			BankInputLatch &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input latch falling edge, INDIVIDUAL, 2, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +			BankInputLatch &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank input latch falling edge, INDIVIDUAL, 3, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +			BankInputLatch = BankInputLatch >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input latch falling edge, INDIVIDUAL, 4, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +
> +			dio_chl->InputLatchRegNegativeEdgeR = InputLatchRegNegativeEdgeR;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputLatchRegNegativeEdgeR = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 4);
> +			BankInputLatch = InputLatchRegNegativeEdgeR;
> +			//printk("SUNIX: DIO (%d), get bank input latch falling edge, WHOLE (input), 1, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +			BankInputLatch &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input latch falling edge, WHOLE (input), 2, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +			BankInputLatch = BankInputLatch >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input latch falling edge, WHOLE (input), 3, BankInputLatch:x%08x\n", dio_chl->info.line, BankInputLatch);
> +
> +			dio_chl->InputLatchRegNegativeEdgeR = InputLatchRegNegativeEdgeR;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?5:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = (unsigned char)((BankInputLatch & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputLatch & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputLatch & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputLatch & 0x000000ff));
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_bank_input_latch_falling_edge(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputLatch = 0;
> +	unsigned int InputLatchRegNegativeEdgeW = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 5)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +		BankInputLatch  =  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 1) << 24);
> +		BankInputLatch |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 2) << 16);
> +		BankInputLatch |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 3) << 8);
> +		BankInputLatch |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 4));
> +		//printk("SUNIX: DIO (%d), set bank input latch falling edge, BankIndex:x%02x, BankInputLatch:x%08x\n", dio_chl->info.line, BankIndex, BankInputLatch);
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].falling_edge_trigger_cap != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_FALLING_EDGE_TRIGGER_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), set bank input latch falling edge, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputLatchRegNegativeEdgeW = BankInputLatch << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input latch falling edge, INDIVIDUAL, 1, InputLatchRegNegativeEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegNegativeEdgeW);
> +			InputLatchRegNegativeEdgeW &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input latch falling edge, INDIVIDUAL, 2, InputLatchRegNegativeEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegNegativeEdgeW);
> +			InputLatchRegNegativeEdgeW &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), set bank input latch falling edge, INDIVIDUAL, 3, InputLatchRegNegativeEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegNegativeEdgeW);
> +			InputLatchRegNegativeEdgeW |= (dio_chl->InputLatchRegNegativeEdgeW & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank input latch falling edge, INDIVIDUAL, 4, InputLatchRegNegativeEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegNegativeEdgeW);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 4, InputLatchRegNegativeEdgeW);
> +			dio_chl->InputLatchRegNegativeEdgeW = InputLatchRegNegativeEdgeW;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputLatchRegNegativeEdgeW = BankInputLatch << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input latch falling edge, WHOLE (input), 1, InputLatchRegNegativeEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegNegativeEdgeW);
> +			InputLatchRegNegativeEdgeW &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input latch falling edge, WHOLE (input), 2, InputLatchRegNegativeEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegNegativeEdgeW);
> +			InputLatchRegNegativeEdgeW |= (dio_chl->InputLatchRegNegativeEdgeW & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank input latch falling edge, WHOLE (input), 3, InputLatchRegNegativeEdgeW:x%08x\n", dio_chl->info.line, InputLatchRegNegativeEdgeW);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 4, InputLatchRegNegativeEdgeW);
> +			dio_chl->InputLatchRegNegativeEdgeW = InputLatchRegNegativeEdgeW;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?1:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_bank_input_counter_reset(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputCounterReset = 0;
> +	unsigned int InputCounterResetReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 5)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +		BankInputCounterReset  =  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 1) << 24);
> +		BankInputCounterReset |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 2) << 16);
> +		BankInputCounterReset |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 3) << 8);
> +		BankInputCounterReset |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 4));
> +		//printk("SUNIX: DIO (%d), set bank input counter reset, BankIndex:x%02x, BankInputCounterReset:x%08x\n", dio_chl->info.line, BankIndex, BankInputCounterReset);
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), set bank input counter reset, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputCounterResetReg = BankInputCounterReset << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input counter reset, INDIVIDUAL, 1, InputCounterResetReg:x%08x\n", dio_chl->info.line, InputCounterResetReg);
> +			InputCounterResetReg &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input counter reset, INDIVIDUAL, 2, InputCounterResetReg:x%08x\n", dio_chl->info.line, InputCounterResetReg);
> +			InputCounterResetReg &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), set bank input counter reset, INDIVIDUAL, 3, InputCounterResetReg:x%08x\n", dio_chl->info.line, InputCounterResetReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 5, InputCounterResetReg);
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputCounterResetReg = BankInputCounterReset << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input counter reset, WHOLE (input), 1, InputCounterResetReg:x%08x\n", dio_chl->info.line, InputCounterResetReg);
> +			InputCounterResetReg &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input counter reset, WHOLE (input), 2, InputCounterResetReg:x%08x\n", dio_chl->info.line, InputCounterResetReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 5, InputCounterResetReg);
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?1:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_bank_input_counter_increment_rising_edge(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputCounterInc = 0;
> +	unsigned int InputCounterIncrementCtrlRegPositiveEdge = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].rising_edge_trigger_cap != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_RISING_EDGE_TRIGGER_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank input counter increment rising edge, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputCounterIncrementCtrlRegPositiveEdge = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 6);
> +			BankInputCounterInc = InputCounterIncrementCtrlRegPositiveEdge;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment rising edge, INDIVIDUAL, 1, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +			BankInputCounterInc &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment rising edge, INDIVIDUAL, 2, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +			BankInputCounterInc &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment rising edge, INDIVIDUAL, 3, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +			BankInputCounterInc = BankInputCounterInc >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment rising edge, INDIVIDUAL, 4, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +
> +			dio_chl->InputCounterIncrementCtrlRegPositiveEdge = InputCounterIncrementCtrlRegPositiveEdge;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputCounterIncrementCtrlRegPositiveEdge = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 6);
> +			BankInputCounterInc = InputCounterIncrementCtrlRegPositiveEdge;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment rising edge, WHOLE (input), 1, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +			BankInputCounterInc &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment rising edge, WHOLE (input), 2, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +			BankInputCounterInc = BankInputCounterInc >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment rising edge, WHOLE (input), 3, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +
> +			dio_chl->InputCounterIncrementCtrlRegPositiveEdge = InputCounterIncrementCtrlRegPositiveEdge;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?5:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = (unsigned char)((BankInputCounterInc & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputCounterInc & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputCounterInc & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputCounterInc & 0x000000ff));
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_bank_input_counter_increment_rising_edge(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputCounterInc = 0;
> +	unsigned int InputCounterIncrementCtrlRegPositiveEdge = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 5)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +		BankInputCounterInc  =  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 1) << 24);
> +		BankInputCounterInc |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 2) << 16);
> +		BankInputCounterInc |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 3) << 8);
> +		BankInputCounterInc |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 4));
> +		//printk("SUNIX: DIO (%d), set bank input counter increment rising edge, BankIndex:x%02x, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankIndex, BankInputCounterInc);
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].rising_edge_trigger_cap != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_RISING_EDGE_TRIGGER_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), set bank input counter increment rising edge, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputCounterIncrementCtrlRegPositiveEdge = BankInputCounterInc << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input counter increment rising edge, INDIVIDUAL, 1, InputCounterIncrementCtrlRegPositiveEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegPositiveEdge);
> +			InputCounterIncrementCtrlRegPositiveEdge &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input counter increment rising edge, INDIVIDUAL, 2, InputCounterIncrementCtrlRegPositiveEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegPositiveEdge);
> +			InputCounterIncrementCtrlRegPositiveEdge &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), set bank input counter increment rising edge, INDIVIDUAL, 3, InputCounterIncrementCtrlRegPositiveEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegPositiveEdge);
> +			InputCounterIncrementCtrlRegPositiveEdge |= (dio_chl->InputCounterIncrementCtrlRegPositiveEdge & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank input counter increment rising edge, INDIVIDUAL, 4, InputCounterIncrementCtrlRegPositiveEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegPositiveEdge);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 6, InputCounterIncrementCtrlRegPositiveEdge);
> +			dio_chl->InputCounterIncrementCtrlRegPositiveEdge = InputCounterIncrementCtrlRegPositiveEdge;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputCounterIncrementCtrlRegPositiveEdge = BankInputCounterInc << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input counter increment rising edge, WHOLE (input), 1, InputCounterIncrementCtrlRegPositiveEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegPositiveEdge);
> +			InputCounterIncrementCtrlRegPositiveEdge &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input counter increment rising edge, WHOLE (input), 2, InputCounterIncrementCtrlRegPositiveEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegPositiveEdge);
> +			InputCounterIncrementCtrlRegPositiveEdge |= (dio_chl->InputCounterIncrementCtrlRegPositiveEdge & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank input counter increment rising edge, WHOLE (input), 3, InputCounterIncrementCtrlRegPositiveEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegPositiveEdge);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 6, InputCounterIncrementCtrlRegPositiveEdge);
> +			dio_chl->InputCounterIncrementCtrlRegPositiveEdge = InputCounterIncrementCtrlRegPositiveEdge;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?1:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_bank_input_counter_increment_falling_edge(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputCounterInc = 0;
> +	unsigned int InputCounterIncrementCtrlRegNegativeEdge = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].falling_edge_trigger_cap != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_FALLING_EDGE_TRIGGER_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank input counter increment falling edge, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputCounterIncrementCtrlRegNegativeEdge = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 7);
> +			BankInputCounterInc = InputCounterIncrementCtrlRegNegativeEdge;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment falling edge, INDIVIDUAL, 1, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +			BankInputCounterInc &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment falling edge, INDIVIDUAL, 2, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +			BankInputCounterInc &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment falling edge, INDIVIDUAL, 3, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +			BankInputCounterInc = BankInputCounterInc >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment falling edge, INDIVIDUAL, 4, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +
> +			dio_chl->InputCounterIncrementCtrlRegNegativeEdge = InputCounterIncrementCtrlRegNegativeEdge;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputCounterIncrementCtrlRegNegativeEdge = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 7);
> +			BankInputCounterInc = InputCounterIncrementCtrlRegNegativeEdge;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment falling edge, WHOLE (input), 1, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +			BankInputCounterInc &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment falling edge, WHOLE (input), 2, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +			BankInputCounterInc = BankInputCounterInc >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input counter increment falling edge, WHOLE (input), 3, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankInputCounterInc);
> +
> +			dio_chl->InputCounterIncrementCtrlRegNegativeEdge = InputCounterIncrementCtrlRegNegativeEdge;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?5:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = (unsigned char)((BankInputCounterInc & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputCounterInc & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputCounterInc & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputCounterInc & 0x000000ff));
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_bank_input_counter_increment_falling_edge(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputCounterInc = 0;
> +	unsigned int InputCounterIncrementCtrlRegNegativeEdge = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 5)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +		BankInputCounterInc  =  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 1) << 24);
> +		BankInputCounterInc |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 2) << 16);
> +		BankInputCounterInc |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 3) << 8);
> +		BankInputCounterInc |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 4));
> +		//printk("SUNIX: DIO (%d), set bank input counter increment falling edge, BankIndex:x%02x, BankInputCounterInc:x%08x\n", dio_chl->info.line, BankIndex, BankInputCounterInc);
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].falling_edge_trigger_cap != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_FALLING_EDGE_TRIGGER_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), set bank input counter increment falling edge, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputCounterIncrementCtrlRegNegativeEdge = BankInputCounterInc << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input counter increment falling edge, INDIVIDUAL, 1, InputCounterIncrementCtrlRegNegativeEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegNegativeEdge);
> +			InputCounterIncrementCtrlRegNegativeEdge &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input counter increment falling edge, INDIVIDUAL, 2, InputCounterIncrementCtrlRegNegativeEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegNegativeEdge);
> +			InputCounterIncrementCtrlRegNegativeEdge &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), set bank input counter increment falling edge, INDIVIDUAL, 3, InputCounterIncrementCtrlRegNegativeEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegNegativeEdge);
> +			InputCounterIncrementCtrlRegNegativeEdge |= (dio_chl->InputCounterIncrementCtrlRegNegativeEdge & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank input counter increment falling edge, INDIVIDUAL, 4, InputCounterIncrementCtrlRegNegativeEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegNegativeEdge);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 7, InputCounterIncrementCtrlRegNegativeEdge);
> +			dio_chl->InputCounterIncrementCtrlRegNegativeEdge = InputCounterIncrementCtrlRegNegativeEdge;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputCounterIncrementCtrlRegNegativeEdge = BankInputCounterInc << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input counter increment falling edge, WHOLE (input), 1, InputCounterIncrementCtrlRegNegativeEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegNegativeEdge);
> +			InputCounterIncrementCtrlRegNegativeEdge &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input counter increment falling edge, WHOLE (input), 2, InputCounterIncrementCtrlRegNegativeEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegNegativeEdge);
> +			InputCounterIncrementCtrlRegNegativeEdge |= (dio_chl->InputCounterIncrementCtrlRegNegativeEdge & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank input counter increment falling edge, WHOLE (input), 3, InputCounterIncrementCtrlRegNegativeEdge:x%08x\n", dio_chl->info.line, InputCounterIncrementCtrlRegNegativeEdge);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 7, InputCounterIncrementCtrlRegNegativeEdge);
> +			dio_chl->InputCounterIncrementCtrlRegNegativeEdge = InputCounterIncrementCtrlRegNegativeEdge;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?1:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_bank_input_rising_event_ctrl(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputEventCtrl = 0;
> +	unsigned int InputRisingEventCtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].rising_edge_trigger_cap != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_RISING_EDGE_TRIGGER_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank input rising event ctrl, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputRisingEventCtrlReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 8);
> +			BankInputEventCtrl = InputRisingEventCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank input rising event ctrl, INDIVIDUAL, 1, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +			BankInputEventCtrl &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input rising event ctrl, INDIVIDUAL, 2, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +			BankInputEventCtrl &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank input rising event ctrl, INDIVIDUAL, 3, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +			BankInputEventCtrl = BankInputEventCtrl >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input rising event ctrl, INDIVIDUAL, 4, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +
> +			dio_chl->InputRisingEventCtrlReg = InputRisingEventCtrlReg;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputRisingEventCtrlReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 8);
> +			BankInputEventCtrl = InputRisingEventCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank input rising event ctrl, WHOLE (input), 1, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +			BankInputEventCtrl &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input rising event ctrl, WHOLE (input), 2, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +			BankInputEventCtrl = BankInputEventCtrl >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input rising event ctrl, WHOLE (input), 3, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +
> +			dio_chl->InputRisingEventCtrlReg = InputRisingEventCtrlReg;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?5:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = (unsigned char)((BankInputEventCtrl & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputEventCtrl & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputEventCtrl & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputEventCtrl & 0x000000ff));
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_bank_input_rising_event_ctrl(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputEventCtrl = 0;
> +	unsigned int InputRisingEventCtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 5)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +		BankInputEventCtrl  =  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 1) << 24);
> +		BankInputEventCtrl |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 2) << 16);
> +		BankInputEventCtrl |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 3) << 8);
> +		BankInputEventCtrl |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 4));
> +		//printk("SUNIX: DIO (%d), set bank input rising event ctrl, BankIndex:x%02x, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankIndex, BankInputEventCtrl);
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].rising_edge_trigger_cap != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_RISING_EDGE_TRIGGER_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), set bank input rising event ctrl, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputRisingEventCtrlReg = BankInputEventCtrl << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input rising event ctrl, INDIVIDUAL, 1, InputRisingEventCtrlReg:x%08x\n", dio_chl->info.line, InputRisingEventCtrlReg);
> +			InputRisingEventCtrlReg &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input rising event ctrl, INDIVIDUAL, 2, InputRisingEventCtrlReg:x%08x\n", dio_chl->info.line, InputRisingEventCtrlReg);
> +			InputRisingEventCtrlReg &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), set bank input rising event ctrl, INDIVIDUAL, 3, InputRisingEventCtrlReg:x%08x\n", dio_chl->info.line, InputRisingEventCtrlReg);
> +			InputRisingEventCtrlReg |= (dio_chl->InputRisingEventCtrlReg & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank input rising event ctrl, INDIVIDUAL, 4, InputRisingEventCtrlReg:x%08x\n", dio_chl->info.line, InputRisingEventCtrlReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 8, InputRisingEventCtrlReg);
> +			dio_chl->InputRisingEventCtrlReg = InputRisingEventCtrlReg;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputRisingEventCtrlReg = BankInputEventCtrl << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input rising event ctrl, WHOLE (input), 1, InputRisingEventCtrlReg:x%08x\n", dio_chl->info.line, InputRisingEventCtrlReg);
> +			InputRisingEventCtrlReg &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input rising event ctrl, WHOLE (input), 2, InputRisingEventCtrlReg:x%08x\n", dio_chl->info.line, InputRisingEventCtrlReg);
> +			InputRisingEventCtrlReg |= (dio_chl->InputRisingEventCtrlReg & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank input rising event ctrl, WHOLE (input), 3, InputRisingEventCtrlReg:x%08x\n", dio_chl->info.line, InputRisingEventCtrlReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 8, InputRisingEventCtrlReg);
> +			dio_chl->InputRisingEventCtrlReg = InputRisingEventCtrlReg;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?1:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_bank_input_falling_event_ctrl(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputEventCtrl = 0;
> +	unsigned int InputFallingEventCtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].falling_edge_trigger_cap != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_FALLING_EDGE_TRIGGER_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank input falling event ctrl, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputFallingEventCtrlReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 9);
> +			BankInputEventCtrl = InputFallingEventCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank input falling event ctrl, INDIVIDUAL, 1, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +			BankInputEventCtrl &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input falling event ctrl, INDIVIDUAL, 2, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +			BankInputEventCtrl &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank input falling event ctrl, INDIVIDUAL, 3, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +			BankInputEventCtrl = BankInputEventCtrl >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input falling event ctrl, INDIVIDUAL, 4, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +
> +			dio_chl->InputFallingEventCtrlReg = InputFallingEventCtrlReg;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputFallingEventCtrlReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 9);
> +			BankInputEventCtrl = InputFallingEventCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank input falling event ctrl, WHOLE (input), 1, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +			BankInputEventCtrl &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank input falling event ctrl, WHOLE (input), 2, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +			BankInputEventCtrl = BankInputEventCtrl >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank input falling event ctrl, WHOLE (input), 3, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankInputEventCtrl);
> +
> +			dio_chl->InputFallingEventCtrlReg = InputFallingEventCtrlReg;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?5:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = (unsigned char)((BankInputEventCtrl & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputEventCtrl & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputEventCtrl & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((BankInputEventCtrl & 0x000000ff));
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_bank_input_falling_event_ctrl(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankInputEventCtrl = 0;
> +	unsigned int InputFallingEventCtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 5)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +		BankInputEventCtrl  =  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 1) << 24);
> +		BankInputEventCtrl |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 2) << 16);
> +		BankInputEventCtrl |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 3) << 8);
> +		BankInputEventCtrl |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 4));
> +		//printk("SUNIX: DIO (%d), set bank input falling event ctrl, BankIndex:x%02x, BankInputEventCtrl:x%08x\n", dio_chl->info.line, BankIndex, BankInputEventCtrl);
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].falling_edge_trigger_cap != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_FALLING_EDGE_TRIGGER_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), set bank input falling event ctrl, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			InputFallingEventCtrlReg = BankInputEventCtrl << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input falling event ctrl, INDIVIDUAL, 1, InputFallingEventCtrlReg:x%08x\n", dio_chl->info.line, InputFallingEventCtrlReg);
> +			InputFallingEventCtrlReg &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input falling event ctrl, INDIVIDUAL, 2, InputFallingEventCtrlReg:x%08x\n", dio_chl->info.line, InputFallingEventCtrlReg);
> +			InputFallingEventCtrlReg &= ~dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), set bank input falling event ctrl, INDIVIDUAL, 3, InputFallingEventCtrlReg:x%08x\n", dio_chl->info.line, InputFallingEventCtrlReg);
> +			InputFallingEventCtrlReg |= (dio_chl->InputFallingEventCtrlReg & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank input falling event ctrl, INDIVIDUAL, 4, InputFallingEventCtrlReg:x%08x\n", dio_chl->info.line, InputFallingEventCtrlReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 9, InputFallingEventCtrlReg);
> +			dio_chl->InputFallingEventCtrlReg = InputFallingEventCtrlReg;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			InputFallingEventCtrlReg = BankInputEventCtrl << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank input falling event ctrl, WHOLE (input), 1, InputFallingEventCtrlReg:x%08x\n", dio_chl->info.line, InputFallingEventCtrlReg);
> +			InputFallingEventCtrlReg &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank input falling event ctrl, WHOLE (input), 2, InputFallingEventCtrlReg:x%08x\n", dio_chl->info.line, InputFallingEventCtrlReg);
> +			InputFallingEventCtrlReg |= (dio_chl->InputFallingEventCtrlReg & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank input falling event ctrl, WHOLE (input), 3, InputFallingEventCtrlReg:x%08x\n", dio_chl->info.line, InputFallingEventCtrlReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 9, InputFallingEventCtrlReg);
> +			dio_chl->InputFallingEventCtrlReg = InputFallingEventCtrlReg;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?1:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_bank_state(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankState = 0;
> +	unsigned int OutputWriteEnableReg = 0;
> +	unsigned int OutputReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 5)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +		BankState  =  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 1) << 24);
> +		BankState |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 2) << 16);
> +		BankState |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 3) << 8);
> +		BankState |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 4));
> +		//printk("SUNIX: DIO (%d), set bank state, BankIndex:x%02x, BankState:x%08x\n", dio_chl->info.line, BankIndex, BankState);
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_outputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_OUTPUT_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), set bank state, INDIVIDUAL, no output\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_OUTPUT_IO;
> +				break;
> +			}
> +
> +			OutputWriteEnableReg = dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), set bank state, INDIVIDUAL, 1, OutputWriteEnableReg:x%08x\n", dio_chl->info.line, OutputWriteEnableReg);
> +			OutputReg = BankState << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank state, INDIVIDUAL, 2, OutputReg:x%08x\n", dio_chl->info.line, OutputReg);
> +			OutputReg &= OutputWriteEnableReg;
> +			//printk("SUNIX: DIO (%d), set bank state, INDIVIDUAL, 3, OutputReg:x%08x\n", dio_chl->info.line, OutputReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 10, OutputWriteEnableReg);
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 11, OutputReg);
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			nStatus = SDCDIO_NO_OUTPUT_IO;
> +			break;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			OutputWriteEnableReg = cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank state, WHILE (output), 1, OutputWriteEnableReg:x%08x\n", dio_chl->info.line, OutputWriteEnableReg);
> +			OutputReg = BankState << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank state, WHILE (output), 2, OutputReg:x%08x\n", dio_chl->info.line, OutputReg);
> +			OutputReg &= OutputWriteEnableReg;
> +			//printk("SUNIX: DIO (%d), set bank state, WHILE (output), 3, OutputReg:x%08x\n", dio_chl->info.line, OutputReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 10, OutputWriteEnableReg);
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 11, OutputReg);
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?1:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_bank_direction(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankDirection = 0;
> +	unsigned int DirectionCtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank direction, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +
> +			DirectionCtrlReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 12);
> +			BankDirection = DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank direction, INDIVIDUAL, 1, BankDirection:x%08x\n", dio_chl->info.line, BankDirection);
> +			BankDirection &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank direction, INDIVIDUAL, 2, BankDirection:x%08x\n", dio_chl->info.line, BankDirection);
> +			BankDirection = BankDirection >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank direction, INDIVIDUAL, 3, BankDirection:x%08x\n", dio_chl->info.line, BankDirection);
> +
> +			dio_chl->DirectionCtrlReg = DirectionCtrlReg;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			DirectionCtrlReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 12);
> +			BankDirection = DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank direction, WHOLE (input), 1, BankDirection:x%08x\n", dio_chl->info.line, BankDirection);
> +			BankDirection &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank direction, WHOLE (input), 2, BankDirection:x%08x\n", dio_chl->info.line, BankDirection);
> +			BankDirection = BankDirection >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank direction, WHOLE (input), 3, BankDirection:x%08x\n", dio_chl->info.line, BankDirection);
> +
> +			dio_chl->DirectionCtrlReg = DirectionCtrlReg;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			DirectionCtrlReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 12);
> +			BankDirection = DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank direction, WHOLE (output), 1, BankDirection:x%08x\n", dio_chl->info.line, BankDirection);
> +			BankDirection &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank direction, WHOLE (output), 2, BankDirection:x%08x\n", dio_chl->info.line, BankDirection);
> +			BankDirection = BankDirection >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank direction, WHOLE (output), 3, BankDirection:x%08x\n", dio_chl->info.line, BankDirection);
> +
> +			dio_chl->DirectionCtrlReg = DirectionCtrlReg;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?5:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = (unsigned char)((BankDirection & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((BankDirection & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((BankDirection & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((BankDirection & 0x000000ff));
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_bank_direction(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankDirection = 0;
> +	unsigned int DirectionCtrlReg = 0;
> +	unsigned int DirectionCtrlRegByBank = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 5)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +		BankDirection  =  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 1) << 24);
> +		BankDirection |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 2) << 16);
> +		BankDirection |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 3) << 8);
> +		BankDirection |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 4));
> +		//printk("SUNIX: DIO (%d), set bank direction, BankIndex:x%02x, BankDirection:x%08x\n", dio_chl->info.line, BankIndex, BankDirection);
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			DirectionCtrlRegByBank = (BankDirection << cib_info->dio_bank_cap[BankIndex].io_shift_bits) & cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank direction, INDIVIDUAL, 1, DirectionCtrlRegByBank:x%08x\n", dio_chl->info.line, DirectionCtrlRegByBank);
> +			DirectionCtrlReg = dio_chl->DirectionCtrlReg & ~cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank direction, INDIVIDUAL, 2, DirectionCtrlReg:x%08x\n", dio_chl->info.line, DirectionCtrlReg);
> +			DirectionCtrlReg |= DirectionCtrlRegByBank;
> +			//printk("SUNIX: DIO (%d), set bank direction, INDIVIDUAL, 3, DirectionCtrlReg:x%08x\n", dio_chl->info.line, DirectionCtrlReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 12, DirectionCtrlReg);
> +			dio_chl->DirectionCtrlReg = DirectionCtrlReg;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			if ((BankDirection & (cib_info->dio_bank_cap[BankIndex].io_mask >> cib_info->dio_bank_cap[BankIndex].io_shift_bits)) != 0x00000000)
> +			{
> +				nStatus = SDCDIO_UNSUPPORT_OUTPUT_CAP;
> +				break;
> +			}
> +
> +			DirectionCtrlRegByBank = (BankDirection << cib_info->dio_bank_cap[BankIndex].io_shift_bits) & cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank direction, WHOLE (input), 1, DirectionCtrlRegByBank:x%08x\n", dio_chl->info.line, DirectionCtrlRegByBank);
> +			DirectionCtrlReg = dio_chl->DirectionCtrlReg & ~cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank direction, WHOLE (input), 2, DirectionCtrlReg:x%08x\n", dio_chl->info.line, DirectionCtrlReg);
> +			DirectionCtrlReg |= DirectionCtrlRegByBank;
> +			//printk("SUNIX: DIO (%d), set bank direction, WHOLE (input), 3, DirectionCtrlReg:x%08x\n", dio_chl->info.line, DirectionCtrlReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 12, DirectionCtrlReg);
> +			dio_chl->DirectionCtrlReg = DirectionCtrlReg;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			if ((BankDirection & (cib_info->dio_bank_cap[BankIndex].io_mask >> cib_info->dio_bank_cap[BankIndex].io_shift_bits)) !=
> +				(0xffffffff & (cib_info->dio_bank_cap[BankIndex].io_mask >> cib_info->dio_bank_cap[BankIndex].io_shift_bits)))
> +			{
> +				nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +				break;
> +			}
> +
> +			DirectionCtrlRegByBank = (BankDirection << cib_info->dio_bank_cap[BankIndex].io_shift_bits) & cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank direction, WHOLE (output), 1, DirectionCtrlRegByBank:x%08x\n", dio_chl->info.line, DirectionCtrlRegByBank);
> +			DirectionCtrlReg = dio_chl->DirectionCtrlReg & ~cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank direction, WHOLE (output), 2, DirectionCtrlReg:x%08x\n", dio_chl->info.line, DirectionCtrlReg);
> +			DirectionCtrlReg |= DirectionCtrlRegByBank;
> +			//printk("SUNIX: DIO (%d), set bank direction, WHOLE (output), 3, DirectionCtrlReg:x%08x\n", dio_chl->info.line, DirectionCtrlReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 12, DirectionCtrlReg);
> +			dio_chl->DirectionCtrlReg = DirectionCtrlReg;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?1:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_bank_output_initial_value(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankOutputInitialValue = 0;
> +	unsigned int OutputInitialValueReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_outputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_OUTPUT_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank output initial value, INDIVIDUAL, no output\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_OUTPUT_IO;
> +				break;
> +			}
> +
> +			OutputInitialValueReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 13);
> +			BankOutputInitialValue = OutputInitialValueReg;
> +			//printk("SUNIX: DIO (%d), get bank output initial value, INDIVIDUAL, 1, BankOutputInitialValue:x%08x\n", dio_chl->info.line, BankOutputInitialValue);
> +			BankOutputInitialValue &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank output initial value, INDIVIDUAL, 2, BankOutputInitialValue:x%08x\n", dio_chl->info.line, BankOutputInitialValue);
> +			BankOutputInitialValue &= dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), get bank output initial value, INDIVIDUAL, 3, BankOutputInitialValue:x%08x\n", dio_chl->info.line, BankOutputInitialValue);
> +			BankOutputInitialValue = BankOutputInitialValue >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank output initial value, INDIVIDUAL, 4, BankOutputInitialValue:x%08x\n", dio_chl->info.line, BankOutputInitialValue);
> +
> +			dio_chl->OutputInitialValueReg = OutputInitialValueReg;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			nStatus = SDCDIO_NO_OUTPUT_IO;
> +			break;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			OutputInitialValueReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 13);
> +			BankOutputInitialValue = OutputInitialValueReg;
> +			//printk("SUNIX: DIO (%d), get bank output initial value, WHOLE (output), 1, BankOutputInitialValue:x%08x\n", dio_chl->info.line, BankOutputInitialValue);
> +			BankOutputInitialValue &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), get bank output initial value, WHOLE (output), 2, BankOutputInitialValue:x%08x\n", dio_chl->info.line, BankOutputInitialValue);
> +			BankOutputInitialValue = BankOutputInitialValue >> cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), get bank output initial value, WHOLE (output), 3, BankOutputInitialValue:x%08x\n", dio_chl->info.line, BankOutputInitialValue);
> +
> +			dio_chl->OutputInitialValueReg = OutputInitialValueReg;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?5:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = (unsigned char)((BankOutputInitialValue & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((BankOutputInitialValue & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((BankOutputInitialValue & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((BankOutputInitialValue & 0x000000ff));
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_bank_output_initial_value(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankOutputInitialValue = 0;
> +	unsigned int OutputInitialValueReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 5)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +		BankOutputInitialValue  =  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 1) << 24);
> +		BankOutputInitialValue |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 2) << 16);
> +		BankOutputInitialValue |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 3) << 8);
> +		BankOutputInitialValue |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 4));
> +		//printk("SUNIX: DIO (%d), set bank output initial value, BankIndex:x%02x, BankOutputInitialValue:x%08x\n", dio_chl->info.line, BankIndex, BankOutputInitialValue);
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_outputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_OUTPUT_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), set bank output initial value, INDIVIDUAL, no output\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_OUTPUT_IO;
> +				break;
> +			}
> +
> +			OutputInitialValueReg = BankOutputInitialValue << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank output initial value, INDIVIDUAL, 1, OutputInitialValueReg:x%08x\n", dio_chl->info.line, OutputInitialValueReg);
> +			OutputInitialValueReg &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank output initial value, INDIVIDUAL, 2, OutputInitialValueReg:x%08x\n", dio_chl->info.line, OutputInitialValueReg);
> +			OutputInitialValueReg &= dio_chl->DirectionCtrlReg;
> +			//printk("SUNIX: DIO (%d), set bank output initial value, INDIVIDUAL, 3, OutputInitialValueReg:x%08x\n", dio_chl->info.line, OutputInitialValueReg);
> +			OutputInitialValueReg |= (dio_chl->OutputInitialValueReg & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank output initial value, INDIVIDUAL, 4, OutputInitialValueReg:x%08x\n", dio_chl->info.line, OutputInitialValueReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 13, OutputInitialValueReg);
> +			dio_chl->OutputInitialValueReg = OutputInitialValueReg;
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			nStatus = SDCDIO_NO_OUTPUT_IO;
> +			break;
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			OutputInitialValueReg = BankOutputInitialValue << cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			//printk("SUNIX: DIO (%d), set bank output initial value, WHOLE (output), 1, OutputInitialValueReg:x%08x\n", dio_chl->info.line, OutputInitialValueReg);
> +			OutputInitialValueReg &= cib_info->dio_bank_cap[BankIndex].io_mask;
> +			//printk("SUNIX: DIO (%d), set bank output initial value, WHOLE (output), 2, OutputInitialValueReg:x%08x\n", dio_chl->info.line, OutputInitialValueReg);
> +			OutputInitialValueReg |= (dio_chl->OutputInitialValueReg & ~cib_info->dio_bank_cap[BankIndex].io_mask);
> +			//printk("SUNIX: DIO (%d), set bank output initial value, WHOLE (output), 3, OutputInitialValueReg:x%08x\n", dio_chl->info.line, OutputInitialValueReg);
> +
> +			mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 13, OutputInitialValueReg);
> +			dio_chl->OutputInitialValueReg = OutputInitialValueReg;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?1:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_bank_ctrl_register(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankCtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +
> +		BankCtrlReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 16 + BankIndex);
> +		//printk("SUNIX: DIO (%d), get bank ctrl register, BankCtrlReg:x%08x\n", dio_chl->info.line, BankCtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?5:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = (unsigned char)((BankCtrlReg & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((BankCtrlReg & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((BankCtrlReg & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((BankCtrlReg & 0x000000ff));
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_bank_ctrl_register(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned int BankCtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 5)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +		BankCtrlReg  =  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 1) << 24);
> +		BankCtrlReg |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 2) << 16);
> +		BankCtrlReg |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 3) << 8);
> +		BankCtrlReg |=  (unsigned int)(*(RxBuff + sizeof(DIO_HEADER) + 4));
> +		//printk("SUNIX: DIO (%d), set bank ctrl register, BankIndex:x%02x, BankCtrlReg:x%08x\n", dio_chl->info.line, BankIndex, BankCtrlReg);
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +
> +		mem_tx32(dio_chl->info.membase, dio_chl->info.memoffset, 16 + BankIndex, BankCtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?1:1;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_bank_input_port_counter(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &dio_chl->info.cib_info;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	unsigned char * RxBuff = dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BankIndex = 0;
> +	unsigned char BankPortIndex = 0;
> +	unsigned int BankPortInputCounterValue = 0;
> +	unsigned char PortIndex = 0x00;
> +	unsigned int PortInputCounterValueReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 2)
> +		{
> +			nStatus = SDCDIO_LENGTH_INVALID;
> +			break;
> +		}
> +		BankIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 0);
> +		BankPortIndex = (unsigned char)*(RxBuff + sizeof(DIO_HEADER) + 1);
> +
> +		if (!(BankIndex < cib_info->dio_number_of_banks))
> +		{
> +			nStatus = SDCDIO_BANK_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (!(BankPortIndex < cib_info->dio_bank_cap[BankIndex].number_of_io))
> +		{
> +			nStatus = SDCDIO_BANK_IO_NOT_FOUND;
> +			break;
> +		}
> +
> +		if (cib_info->dio_bank_cap[BankIndex].support_inputs != 0x01)
> +		{
> +			nStatus = SDCDIO_UNSUPPORT_INPUT_CAP;
> +			break;
> +		}
> +
> +
> +		if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is individual input/output
> +			if ((~dio_chl->DirectionCtrlReg & cib_info->dio_bank_cap[BankIndex].io_mask) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank input port counter, INDIVIDUAL, no input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +			PortIndex = BankPortIndex;
> +			if (cib_info->dio_bank_cap[BankIndex].io_shift_bits > 0)
> +			{
> +				PortIndex += cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			}
> +			if (PortIndex > 32)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank input port counter, INDIVIDUAL, PortIndex:%d invalid\n", dio_chl->info.line, PortIndex);
> +				nStatus = SDCDIO_BANK_IO_NOT_FOUND;
> +				break;
> +			}
> +			if ((~dio_chl->DirectionCtrlReg & (0x00000001 << PortIndex)) == 0x00000000)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank input port counter, INDIVIDUAL, not input\n", dio_chl->info.line);
> +				nStatus = SDCDIO_NO_INPUT_IO;
> +				break;
> +			}
> +			PortInputCounterValueReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 32 + PortIndex);
> +			BankPortInputCounterValue = PortInputCounterValueReg;
> +			//printk("SUNIX: DIO (%d), get bank input port counter, INDIVIDUAL, 1, PortIndex:x%02x\n", dio_chl->info.line, PortIndex);
> +			//printk("SUNIX: DIO (%d), get bank input port counter, INDIVIDUAL, 2, BankPortInputCounterValue:x%08x\n", dio_chl->info.line, BankPortInputCounterValue);
> +		}
> +		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x01) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x00))
> +		{
> +			// bank is whole input
> +			PortIndex = BankPortIndex;
> +			if (cib_info->dio_bank_cap[BankIndex].io_shift_bits > 0)
> +			{
> +				PortIndex += cib_info->dio_bank_cap[BankIndex].io_shift_bits;
> +			}
> +			if (PortIndex > 32)
> +			{
> +				//printk("SUNIX: DIO (%d), get bank input port counter, WHOLE (input), PortIndex:%d invalid\n", dio_chl->info.line, PortIndex);
> +				nStatus = SDCDIO_BANK_IO_NOT_FOUND;
> +				break;
> +			}
> +			PortInputCounterValueReg = mem_rx32(dio_chl->info.membase, dio_chl->info.memoffset, 32 + PortIndex);
> +			BankPortInputCounterValue = PortInputCounterValueReg;
> +			//printk("SUNIX: DIO (%d), get bank input port counter, WHOLE (input), 1, PortIndex:x%02x\n", dio_chl->info.line, PortIndex);
> +			//printk("SUNIX: DIO (%d), get bank input port counter, WHOLE (input), 2, BankPortInputCounterValue:x%08x\n", dio_chl->info.line, BankPortInputCounterValue);
> +		}
> + 		else if ((cib_info->dio_bank_cap[BankIndex].support_inputs == 0x00) && (cib_info->dio_bank_cap[BankIndex].support_outputs == 0x01))
> +		{
> +			// bank is whole output
> +			nStatus = SDCDIO_NO_INPUT_IO;
> +			break;
> +		}
> +		else
> +		{
> +			nStatus = SDCDIO_UNDEFINE_ERROR;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCDIO_STATUS_SUCCESS)?6:2;
> +	TrLength = sizeof(DIO_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCDIO_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = BankPortIndex;
> +		TrBuff[TrLength++] = (unsigned char)((BankPortInputCounterValue & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((BankPortInputCounterValue & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((BankPortInputCounterValue & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((BankPortInputCounterValue & 0x000000ff));
> +	}
> +	else
> +	{
> +		TrBuff[TrLength++] = BankIndex;
> +		TrBuff[TrLength++] = BankPortIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void unsupport(struct sunix_sdc_dio_channel *dio_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	unsigned int nStatus = SDCDIO_UNSUPPORT_COMMAND;
> +	unsigned int TrLength = 0;
> +
> +
> +	memset(TrBuff, 0, SUNIX_SDC_DIO_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = 0;
> +	TrLength = sizeof(DIO_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +int sunix_dio_handle_outcome(struct sunix_sdc_dio_channel *dio_chl, size_t count, unsigned int * outcomeLength)
> +{
> +	int status = 0;
> +	PDIO_PACKAGE pPack = NULL;
> +	DLIST *	pListHead = &dio_chl->packList;
> +	DLIST * e = NULL;
> +	unsigned char * TxBuff = dio_chl->outcomeBuff;
> +	unsigned int TrLength = 0;
> +
> +
> +	do
> +	{
> +		do
> +		{
> +			if (!SxxListEmpty(pListHead))
> +			{
> +				e = pListHead->Flink;
> +			}
> +			else
> +			{
> +				break;
> +			}
> +
> +			while ((e != NULL) && (e != pListHead))
> +			{
> +				if (e != NULL)
> +				{
> +					pPack = SUNIX_SDC_DIO_PACK_PTR(e);
> +					if (pPack != NULL)
> +					{
> +						break;
> +					}
> +
> +					e = e->Flink;
> +				}
> +			}
> +
> +		} while (false);
> +
> +		if (pPack == NULL)
> +		{
> +			*outcomeLength = 0;
> +			break;
> +		}
> +
> +
> +		SxxListRemoveEntry(&pPack->Entry);
> +
> +
> +		memset(TxBuff, 0, SUNIX_SDC_DIO_BUFF);
> +		memcpy(TxBuff, &pPack->Header, sizeof(DIO_HEADER));
> +		TrLength = sizeof(DIO_HEADER);
> +		if (pPack->DataPtr != NULL)
> +		{
> +			memcpy(TxBuff + sizeof(DIO_HEADER), pPack->DataPtr, pPack->Header.Length);
> +			TrLength += pPack->Header.Length;
> +		}
> +
> +		*outcomeLength = TrLength;
> +
> +		//printk("SUNIX: DIO FREE pack, line:%d, pack:x%p, DataPtrx%p\n", dio_chl->info.line, pPack, pPack->DataPtr);
> +		if (pPack->DataPtr != NULL)
> +		{
> +			kfree(pPack->DataPtr);
> +			pPack->DataPtr = NULL;
> +		}
> +		kmem_cache_free(sunix_sdc_dio_pack_cache, pPack);
> +		pPack = NULL;
> +			
> +	} while (false);
> +
> +	return status;
> +}
> +
> +
> +int sunix_dio_handle_income(struct sunix_sdc_dio_channel *dio_chl, size_t count)
> +{
> +	int status = 0;
> +	PDIO_HEADER pRxHeader = (PDIO_HEADER)dio_chl->incomeBuff;
> +	PDIO_HEADER pTrHeader = (PDIO_HEADER)dio_chl->translateBuff;
> +	unsigned char * TrBuff = dio_chl->translateBuff;
> +	PDIO_PACKAGE pPack = NULL;
> +	unsigned int translateLength = 0;
> +	unsigned long Flags;
> +
> +
> +	do
> +	{
> +		// debug
> +		/*
> +		printk("++++++++++++++++++++++++++++++++++++++++++++++\n");
> +		printk("SUNIX: DIO_RX, Version              :x%02x\n", pRxHeader->Version);
> +		printk("SUNIX: DIO_RX, CmdResponseEventData :x%04x\n", pRxHeader->CmdResponseEventData);
> +		printk("SUNIX: DIO_RX, Length               :x%08x\n", pRxHeader->Length);
> +		printk("++++++++++++++++++++++++++++++++++++++++++++++\n");
> +		*/
> +
> +
> +		switch (pRxHeader->CmdResponseEventData)
> +		{
> +			case SDCDIO_CMD_GET_INFO :
> +				get_info(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_GET_BANK_STATE :
> +				get_bank_state(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_GET_BANK_INPUT_DELTA_STATE :
> +				get_bank_input_delta_state(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_GET_BANK_INPUT_INVERT_ENABLE :
> +				get_bank_input_invert_enable(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_SET_BANK_INPUT_INVERT_ENABLE :
> +				set_bank_input_invert_enable(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_GET_BANK_INPUT_LATCH_RISING_EDGE :
> +				get_bank_input_latch_rising_edge(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_SET_BANK_INPUT_LATCH_RISING_EDGE :
> +				set_bank_input_latch_rising_edge(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_GET_BANK_INPUT_LATCH_FALLING_EDGE :
> +				get_bank_input_latch_falling_edge(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_SET_BANK_INPUT_LATCH_FALLING_EDGE :
> +				set_bank_input_latch_falling_edge(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_SET_BANK_INPUT_COUNTER_RESET :
> +				set_bank_input_counter_reset(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_GET_BANK_INPUT_COUNTER_INCREMENT_RISING_EDGE :
> +				get_bank_input_counter_increment_rising_edge(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_SET_BANK_INPUT_COUNTER_INCREMENT_RISING_EDGE :
> +				set_bank_input_counter_increment_rising_edge(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_GET_BANK_INPUT_COUNTER_INCREMENT_FALLING_EDGE :
> +				get_bank_input_counter_increment_falling_edge(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_SET_BANK_INPUT_COUNTER_INCREMENT_FALLING_EDGE :
> +				set_bank_input_counter_increment_falling_edge(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_GET_BANK_INPUT_RISING_EVENT_CTRL :
> +				get_bank_input_rising_event_ctrl(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_SET_BANK_INPUT_RISING_EVENT_CTRL :
> +				set_bank_input_rising_event_ctrl(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_GET_BANK_INPUT_FALLING_EVENT_CTRL :
> +				get_bank_input_falling_event_ctrl(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_SET_BANK_INPUT_FALLING_EVENT_CTRL :
> +				set_bank_input_falling_event_ctrl(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_SET_BANK_STATE :
> +				set_bank_state(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_GET_BANK_DIRECTION :
> +				get_bank_direction(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_SET_BANK_DIRECTION :
> +				set_bank_direction(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_GET_BANK_OUTPUT_INITIAL_VALUE :
> +				get_bank_output_initial_value(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_SET_BANK_OUTPUT_INITIAL_VALUE :
> +				set_bank_output_initial_value(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_GET_BANK_CTRL_REGISTER :
> +				get_bank_ctrl_register(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_SET_BANK_CTRL_REGISTER :
> +				set_bank_ctrl_register(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCDIO_CMD_GET_BANK_INPUT_PORT_COUNTER :
> +				get_bank_input_port_counter(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			default :
> +				unsupport(dio_chl, (unsigned int)count, &translateLength);
> +				break;
> +		}
> +
> +
> +		// debug
> +		/*
> +		printk("----------------------------------------------\n");
> +		printk("SUNIX: DIO_TR, translateLength      :%d\n", translateLength);
> +		printk("SUNIX: DIO_TR, Version              :x%02x\n", pTrHeader->Version);
> +		printk("SUNIX: DIO_TR, CmdResponseEventData :x%04x\n", pTrHeader->CmdResponseEventData);
> +		printk("SUNIX: DIO_TR, ResponseStatus       :x%04x\n", pTrHeader->ResponseStatus);
> +		printk("SUNIX: DIO_TR, Length               :x%08x\n", pTrHeader->Length);
> +		{
> +			int i;
> +			for (i = 0; i < pTrHeader->Length; i++)
> +				printk("x%02x ", (unsigned char)*(TrBuff + sizeof(DIO_HEADER) + i));
> +		}
> +		printk("----------------------------------------------\n");
> +		*/
> +
> +
> +		if (pTrHeader->Length > DIO_MAX_DATA_LENGTH)
> +		{
> +			status = -ENOMEM;
> +			break;
> +		}
> +		if (translateLength > (DIO_MAX_DATA_LENGTH + sizeof(DIO_HEADER)))
> +		{
> +			status = -ENOMEM;
> +			break;
> +		}
> +
> +		pPack = kmem_cache_alloc(sunix_sdc_dio_pack_cache, GFP_ATOMIC);
> +		if (pPack == NULL)
> +		{
> +			status = -ENOMEM;
> +			break;
> +		}
> +		memset(pPack, 0, sizeof(DIO_PACKAGE));
> +		pPack->DataPtr = (unsigned char *)kmalloc(DIO_MAX_DATA_LENGTH, GFP_KERNEL);
> +		if (pPack->DataPtr == NULL)
> +		{
> +			status = -ENOMEM;
> +			break;
> +		}
> +		memset(pPack->DataPtr, 0, DIO_MAX_DATA_LENGTH);
> +
> +
> +		SxxListInit(&pPack->Entry);
> +		memcpy(&pPack->Header, pTrHeader, sizeof(DIO_HEADER));
> +		memcpy(pPack->DataPtr, TrBuff + sizeof(DIO_HEADER), pTrHeader->Length);
> +
> +		spin_lock_irqsave(&dio_chl->packLock, Flags);
> +		//printk("SUNIX: DIO ALOC pack, line:%d, pack:x%p, DataPtrx%p\n", dio_chl->info.line, pPack, pPack->DataPtr);
> +		SxxListInsertTail(&dio_chl->packList, &pPack->Entry);
> +
> +		dio_chl->readDataReady = 1;
> +		wake_up_interruptible(&dio_chl->readWQ);
> +		spin_unlock_irqrestore(&dio_chl->packLock, Flags);
> +
> +	} while (false);
> +
> +	if (status != 0)
> +	{
> +		if (pPack != NULL)
> +		{
> +			if (pPack->DataPtr != NULL)
> +			{
> +				kfree(pPack->DataPtr);
> +				pPack->DataPtr = NULL;
> +			}
> +
> +			kmem_cache_free(sunix_sdc_dio_pack_cache, pPack);
> +		}
> +	}
> +
> +	return status;
> +}
> +
> +
> diff --git a/drivers/mfd/list.c b/drivers/mfd/list.c
> new file mode 100644
> index 000000000000..8126eaed9671
> --- /dev/null
> +++ b/drivers/mfd/list.c
> @@ -0,0 +1,99 @@
> +
> +
> +#include "sdc_include.h"
> +
> +
> +void
> +SxxListInit(
> +	DLIST *					pListHead
> +	)
> +{
> +	pListHead->Flink = pListHead->Blink = pListHead;
> +}
> +
> +
> +bool
> +SxxListEmpty(
> +	DLIST *					pListHead
> +	)
> +{
> +	if (pListHead->Flink == pListHead)
> +	{
> +		return true;
> +	}
> +	else
> +	{
> +		return false;
> +	}
> +}
> +
> +
> +DLIST *
> +SxxListGetNext(
> +	DLIST *					pListHead
> +	)
> +{
> +	return pListHead->Flink;
> +}
> +
> +
> +DLIST *
> +SxxListGetPrev(
> +	DLIST *					pListHead
> +	)
> +{
> +	return pListHead->Blink;
> +}
> +
> +
> +void
> +SxxListRemoveEntry(
> +	DLIST *					pEntry
> +	)
> +{
> +	DLIST *					_DlistMEntry = pEntry;
> +
> +
> +	_DlistMEntry->Blink->Flink = _DlistMEntry->Flink;
> +	_DlistMEntry->Flink->Blink = _DlistMEntry->Blink;
> +	_DlistMEntry->Flink = _DlistMEntry->Blink = _DlistMEntry;
> +}
> +
> +
> +void
> +SxxListInsertEntry(
> +	DLIST *					pEntry,
> +	DLIST * 				pNewEntry
> +	)
> +{
> +	DLIST *					_DlistMEntry = pEntry;
> +	DLIST *					_DlistMNewEntry = pNewEntry;
> +
> +
> +	_DlistMNewEntry->Flink = _DlistMEntry->Flink;
> +	_DlistMNewEntry->Blink = _DlistMEntry;
> +	_DlistMEntry->Flink->Blink = _DlistMNewEntry;
> +	_DlistMEntry->Flink = _DlistMNewEntry;
> +}
> +
> +
> +void
> +SxxListInsertHead(
> +	DLIST *					pListHead,
> +	DLIST *					pEntry
> +	)
> +{
> +	SxxListInsertEntry(pListHead, pEntry);
> +}
> +
> +
> +void
> +SxxListInsertTail(
> +	DLIST *					pListHead,
> +	DLIST *					pEntry
> +	)
> +{
> +	SxxListInsertEntry(pListHead->Blink, pEntry);
> +}
> +

What is that for? We already have list functions the kernel.

> +
> diff --git a/drivers/mfd/mem.c b/drivers/mfd/mem.c
> new file mode 100644
> index 000000000000..1158439d0aef
> --- /dev/null
> +++ b/drivers/mfd/mem.c
> @@ -0,0 +1,37 @@
> +
> +
> +#include "sdc_include.h"
> +
> +
> +void __iomem * mem_get_bar_ioremap(struct pci_dev *pdev, unsigned int bar_num)
> +{
> +	void __iomem * membase;
> +	unsigned long phy_base_start;
> +	unsigned long phy_base_end;
> +	unsigned long phy_base_len;
> +
> +
> +	phy_base_start = pci_resource_start(pdev, bar_num);
> +	phy_base_end = pci_resource_end(pdev, bar_num);
> +	phy_base_len = (phy_base_end - phy_base_start) + 1;
> +	membase = ioremap(phy_base_start, phy_base_len);
> +	return membase;
> +}
> +
> +
> +unsigned int mem_rx32(void __iomem *membase, unsigned int base_offset, unsigned int reg_offset)
> +{
> +	unsigned int data;
> +
> +
> +	data = readl(membase + base_offset + (reg_offset * 4));
> +	return data;
> +}
> +
> +
> +void mem_tx32(void __iomem *membase, unsigned int base_offset, unsigned int reg_offset, unsigned int data)
> +{
> +	writel(data, membase + base_offset + (reg_offset * 4));
> +}
> +
> +
> diff --git a/drivers/mfd/sdc_define.h b/drivers/mfd/sdc_define.h
> new file mode 100644
> index 000000000000..365a52809da5
> --- /dev/null
> +++ b/drivers/mfd/sdc_define.h
> @@ -0,0 +1,668 @@
> +
> +
> +#ifndef _SDC_DRVR_DEFINE_H_
> +#define _SDC_DRVR_DEFINE_H_
> +
> +
> +/*******************************************************
> +	
> +*******************************************************/
> +
> +#define ENABLE_DEBUG_SDC_BUS					0
> +#define ENABLE_DEBUG_SDC_DIO					0
> +
> +
> +/*******************************************************
> +	bus
> +*******************************************************/
> +
> +#define SUNIX_SDC_BOARD_MAX  					4
> +
> +struct dio_bank
> +{
> +	unsigned char			number_of_io;
> +	unsigned char			support_inputs;
> +	unsigned char			support_outputs;
> +	unsigned char			rising_edge_trigger_cap;
> +	unsigned char			falling_edge_trigger_cap;
> +
> +	unsigned int			io_mask;
> +	unsigned int			io_shift_bits;
> +};
> +
> +struct spi_device
> +{
> +	unsigned char			type;
> +	unsigned char			number_of_gpio_input;
> +	unsigned char			number_of_gpio_output;
> +	unsigned char			name[32];
> +};
> +
> +struct sdc_cib
> +{
> +	// cib
> +	unsigned char			num;
> +	unsigned char			type;
> +	unsigned char			version;
> +	unsigned char			lengthInDW;
> +	unsigned char			capability;
> +	unsigned char			event_header_type;
> +	unsigned int			io_addr_offset;
> +	unsigned char			io_space_size;
> +	unsigned int			mem_addr_offset;
> +	unsigned int			mem_space_size;
> +	// configuration controller
> +	unsigned char			cfg_ic_model;
> +	// uart controller
> +	unsigned short			uart_tx_fifo_size;
> +	unsigned short			uart_rx_fifo_size;
> +	unsigned int			uart_significand_of_clock;
> +	unsigned char			uart_exponent_of_clock;
> +	unsigned char			uart_RS232_cap;
> +	unsigned char			uart_RS422_cap;
> +	unsigned char			uart_RS485_cap;
> +	unsigned char			uart_AHDC_cap;
> +	unsigned char			uart_CS_cap;
> +	unsigned char			uart_auto_RS422485_cap;
> +	unsigned char			uart_RS422_termination_cap;
> +	unsigned char			uart_RS485_termination_cap;
> +	unsigned char			uart_RI_5V_cap;
> +	unsigned char			uart_RI_12V_cap;
> +	unsigned char			uart_DCD_5V_cap;
> +	unsigned char			uart_DCD_12V_cap;
> +	// dio controller
> +	unsigned char			dio_number_of_banks;
> +	unsigned char			dio_shares_same_direction_ctrl_cap;
> +	unsigned char			dio_writing_setting_to_flash_cap;
> +	struct dio_bank			dio_bank_cap[32];
> +	// spi controller
> +	unsigned int			spi_significand_of_clock;
> +	unsigned char			spi_exponent_of_clock;
> +	unsigned char			spi_number_of_device;
> +	struct spi_device		spi_device_cap[16];
> +};
> +
> +struct sunix_sdc_uart_channel;
> +struct sunix_sdc_dio_channel;
> +struct sunix_sdc_spi_channel;
> +
> +struct sunix_sdc_board
> +{
> +	struct pci_dev			*pdev;
> +	int						board_enum;
> +	int						board_number;
> +	unsigned int			bus_number;
> +	unsigned int			dev_number;
> +	unsigned int			irq;
> +
> +	void __iomem *			bar0_membase;
> +	unsigned int			bar1_iobase;
> +	void __iomem *			bar2_membase;
> +
> +	unsigned char 			major_version;
> +	unsigned char 			minor_version;
> +	unsigned char 			aval_channels;
> +	unsigned char 			model_name[32];
> +	struct sdc_cib			channel[32];
> +
> +	unsigned int			uart_amount;
> +	unsigned int			uart_start_index;
> +	int						(*uart_isr)(struct sunix_sdc_uart_channel *);
> +
> +	unsigned int			dio_amount;
> +	unsigned int			dio_start_index;
> +	int						(*dio_isr)(struct sunix_sdc_dio_channel *, unsigned int);
> +
> +	unsigned int			spi_amount;
> +	unsigned int			spi_start_index;
> +	int						(*spi_isr)(struct sunix_sdc_spi_channel *, unsigned int);
> +};

Split that off into separate drivers for gpio, spi, serial, etc., ...


> +
> +/*******************************************************
> +
> +*******************************************************/
> +
> +typedef struct _DLIST
> +{
> +	struct _DLIST *			Flink;
> +	struct _DLIST *			Blink;
> +
> +} DLIST;
> +
> +
> +#define STRUCT_BASE_POINTER(Fieldptr, Type, Field) \
> +	((Type *)(((char *)(Fieldptr)) - ((char *)(&(((Type *)0)->Field)))))
> +
> +
> +/*******************************************************
> +	uart
> +*******************************************************/
> +
> +#define SUNIX_SDC_UART_MAX					32
> +
> +#define SNX_SDC_UART_IOCTL					0xa00
> +#define SNX_SDC_UART_GET_INFO				(SNX_SDC_UART_IOCTL + 50)
> +#define SNX_SDC_UART_GET_ADDITIONAL_REG_0E	(SNX_SDC_UART_IOCTL + 51)
> +#define SNX_SDC_UART_SET_ADDITIONAL_REG_0E	(SNX_SDC_UART_IOCTL + 52)
> +
> +struct snx_sdc_uart_info
> +{
> +	unsigned char			model_name[32];
> +	unsigned int			bus_number;
> +	unsigned int			dev_number;
> +	unsigned int			line;
> +	unsigned int			iobase;
> +	unsigned int			irq;
> +	unsigned char			version;
> +	unsigned short			tx_fifo_size;
> +	unsigned short			rx_fifo_size;
> +	unsigned int			significand_of_clock;
> +	unsigned char			exponent_of_clock;
> +	unsigned char			RS232_cap;
> +	unsigned char			RS422_cap;
> +	unsigned char			RS485_cap;
> +	unsigned char			AHDC_cap;
> +	unsigned char			CS_cap;
> +	unsigned char			auto_RS422485_cap;
> +	unsigned char			RS422_termination_cap;
> +	unsigned char			RS485_termination_cap;
> +	unsigned char			RI_5V_cap;
> +	unsigned char			RI_12V_cap;
> +	unsigned char			DCD_5V_cap;
> +	unsigned char			DCD_12V_cap;
> +};
> +
> +
> +
> +
> +#define UART_LSR_ERR_IN_RFIFO  				0x80
> +#define UART_MCR_AFE  						0x20
> +#define UART_IIR_CTO  						0x0C
> +
> +#define INTERRUPT_COUNT						128
> +#define WAKEUP_CHARS						256
> +
> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19))
> +#define SNXTERMIOS  ktermios
> +#else
> +#define SNXTERMIOS  termios
> +#endif
> +
> +#define SNX_SER_BAUD_SETSERIAL				1
> +#define SNX_SER_BAUD_NOTSETSER				0
> +
> +#define PORT_SER_UNKNOWN		0
> +#define PORT_SER_8250			1
> +#define PORT_SER_16450			2
> +#define PORT_SER_16550			3
> +#define PORT_SER_16550A			4
> +#define PORT_SER_CIRRUS         5
> +#define PORT_SER_16650			6
> +#define PORT_SER_16650V2		7
> +#define PORT_SER_16750			8
> +#define PORT_SER_MAX_UART		8	/* max serial port ID */
> +
> +#define SNX_USF_CLOSING_WAIT_INF			(0)
> +#define SNX_USF_CLOSING_WAIT_NONE			(65535)
> +#define SNX_UART_CONFIG_TYPE				(1 << 0)
> +#define SNX_UART_CONFIG_IRQ					(1 << 1)
> +
> +#define SNX_UART_XMIT_SIZE 					4096
> +
> +#define snx_ser_circ_empty(circ)		   	((circ)->head == (circ)->tail)
> +#define snx_ser_circ_clear(circ)		    ((circ)->head = (circ)->tail = 0)
> +#define snx_ser_circ_chars_pending(circ)    (CIRC_CNT((circ)->head, (circ)->tail, SNX_UART_XMIT_SIZE))
> +#define snx_ser_circ_chars_free(circ)       (CIRC_SPACE((circ)->head, (circ)->tail, SNX_UART_XMIT_SIZE))
> +#define snx_ser_tx_stopped(port)            ((port)->info->tty->stopped || (port)->info->tty->hw_stopped)
> +
> +#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
> +#define SNX_SERIAL_INLINE
> +#endif
> +
> +#ifdef SNX_SERIAL_INLINE
> +#define _INLINE_ inline
> +#else
> +#define _INLINE_
> +#endif
> +
> +#define SNX_UPIO_PORT				(0)
> +#define SNX_UPIO_MEM				(1)
> +
> +#define SNX_UPF_SAK					(1 << 2)
> +#define SNX_UPF_SPD_MASK			(0x1030)
> +#define SNX_UPF_SPD_HI				(0x0010)
> +#define SNX_UPF_SPD_VHI				(0x0020)
> +#define SNX_UPF_SPD_CUST			(0x0030)
> +#define SNX_UPF_SPD_SHI				(0x1000)
> +#define SNX_UPF_SPD_WARP			(0x1010)
> +#define SNX_UPF_SKIP_TEST			(1 << 6)
> +#define SNX_UPF_HARDPPS_CD			(1 << 11)
> +#define SNX_UPF_LOW_LATENCY			(1 << 13)
> +#define SNX_UPF_BUGGY_UART			(1 << 14)
> +#define SNX_UPF_MAGIC_MULTIPLIER	(1 << 16)
> +
> +#define SNX_UPF_CHANGE_MASK			(0x17fff)
> +#define SNX_UPF_USR_MASK			(SNX_UPF_SPD_MASK | SNX_UPF_LOW_LATENCY)
> +
> +#define SNX_UIF_CHECK_CD			(1 << 25)
> +#define SNX_UIF_CTS_FLOW			(1 << 26)
> +
> +#define SNX_UIF_NORMAL_ACTIVE		(1 << 29)
> +#define SNX_UIF_INITIALIZED			(1 << 31)
> +
> +#define SNX_ENABLE_MS(port, cflag)    ((port)->flags & SNX_UPF_HARDPPS_CD || (cflag) & CRTSCTS || !((cflag) & CLOCAL))
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +#define SNX_SER_DEVNUM(x)   ((x)->index)
> +#else
> +#define SNX_SER_DEVNUM(x)   (MINOR((x)->device) - (x)->driver.minor_start)
> +#endif
> +
> +struct snx_ser_info;
> +struct snx_ser_port;
> +
> +struct snx_ser_icount
> +{
> +	__u32	cts;
> +	__u32	dsr;
> +	__u32	rng;
> +	__u32	dcd;
> +	__u32	rx;
> +	__u32	tx;
> +	__u32	frame;
> +	__u32	overrun;
> +	__u32	parity;
> +	__u32	brk;
> +	__u32	buf_overrun;
> +};
> +
> +struct snx_ser_info
> +{
> +	struct tty_struct		*tty;
> +	struct circ_buf			xmit;
> +	unsigned int			flags;
> +	unsigned char			*tmpbuf;
> +	struct semaphore		tmpbuf_sem;
> +	int						blocked_open;
> +	struct tasklet_struct	tlet;
> +
> +	wait_queue_head_t		open_wait;
> +	wait_queue_head_t		delta_msr_wait;
> +};
> +
> +struct snx_ser_driver
> +{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	struct module			*owner;
> +	const char 				*driver_name;
> +#endif
> +
> +	const char				*dev_name;
> +	int			 			major;
> +	int			 			minor;
> +	int			 			nr;
> +	struct snx_ser_state	*state;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +	struct tty_driver		*tty_driver;
> +#else
> +	struct tty_driver  		tty_driver;
> +#endif
> +};
> +
> +struct snx_ser_port
> +{
> +	spinlock_t				lock;
> +	unsigned int			iobase;
> +	unsigned int			iosize;
> +	unsigned int			irq;
> +	unsigned int			uartclk;
> +	unsigned char			fifosize;
> +	unsigned char			x_char;
> +	unsigned char			iotype;
> +
> +	unsigned int			read_status_mask;
> +	unsigned int			ignore_status_mask;
> +	struct snx_ser_info		*info;
> +	struct snx_ser_icount	icount;
> +
> +	unsigned int			flags;
> +	unsigned int			mctrl;
> +	unsigned int			timeout;
> +
> +	unsigned int			type;
> +	unsigned int			custom_divisor;
> +	unsigned int			line;
> +
> +	int						board_enum;
> +	unsigned int			bus_number;
> +	unsigned int			dev_number;
> +	unsigned char 			model_name[32];
> +
> +	unsigned int			baud_base;
> +	int						rx_trigger;
> +	unsigned char			ldisc_stop_rx;
> +	unsigned int			setserial_flag;
> +    unsigned char			suspended;
> +	struct device			*dev;
> +
> +	struct sdc_cib			cib_info;
> +};
> +
> +struct snx_ser_state
> +{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	struct tty_port			tport;
> +#endif
> +
> +	unsigned int			close_delay;
> +	unsigned int			closing_wait;
> +	int						count;
> +	struct snx_ser_info	    *info;
> +	struct snx_ser_port		*port;
> +	struct semaphore		sem;
> +};
> +
> +static inline int snx_ser_handle_break(struct snx_ser_port *port)
> +{
> +	struct snx_ser_info *info = port->info;
> +
> +	if (info->flags & SNX_UPF_SAK)
> +	{
> +		do_SAK(info->tty);
> +	}
> +	return 0;
> +}
> +
> +static inline void snx_ser_handle_dcd_change(struct snx_ser_port *port, unsigned int status)
> +{
> +	struct snx_ser_info *info = port->info;
> +
> +	port->icount.dcd++;
> +
> +	if (info->flags & SNX_UIF_CHECK_CD)
> +	{
> +		if (status)
> +		{
> +			wake_up_interruptible(&info->open_wait);
> +		}
> +		else if (info->tty)
> +		{
> +			tty_hangup(info->tty);
> +		}
> +	}
> +}
> +
> +struct sunix_sdc_uart_channel
> +{
> +	struct snx_ser_port port;
> +	struct timer_list	timer;
> +	struct list_head	list;
> +
> +	unsigned int		capabilities;
> +	unsigned char		ier;
> +	unsigned char		lcr;
> +	unsigned char		mcr;
> +	unsigned char		mcr_mask;
> +	unsigned char		mcr_force;
> +	unsigned char		lsr_break_flag;
> +};
> +
> +
> +/*******************************************************
> +	dio
> +*******************************************************/
> +
> +#define SUNIX_SDC_DIO_MAX					32
> +#define SUNIX_SDC_DIO_BUFF					1024
> +
> +struct snx_dio_info
> +{
> + 	unsigned char			model_name[32];
> +	unsigned int			bus_number;
> +	unsigned int			dev_number;
> +	unsigned int			line;
> +	unsigned long			phy2_base_start;
> +	void __iomem *			membase;
> +	unsigned int			memoffset;
> +	unsigned int			memsize;
> +	unsigned int			irq;
> +
> +	struct sdc_cib			cib_info;
> +};
> +
> +struct sunix_sdc_dio_channel
> +{
> +	struct snx_dio_info		info;
> +	struct cdev				cdev;
> +
> +	DLIST					packList;
> +	spinlock_t				packLock;
> +	wait_queue_head_t		readWQ;
> +	unsigned int			readDataReady;
> +	struct semaphore		sem;
> +
> +	bool					isOpened;
> +
> +	unsigned char *			incomeBuff;
> +	unsigned char *			outcomeBuff;
> +	unsigned char *			translateBuff;
> +
> +	unsigned int			InputInvertEnableReg;
> +	unsigned int			InputLatchRegPositiveEdgeR;
> +	unsigned int			InputLatchRegPositiveEdgeW;
> +	unsigned int			InputLatchRegNegativeEdgeR;
> +	unsigned int			InputLatchRegNegativeEdgeW;
> +	unsigned int			InputCounterIncrementCtrlRegPositiveEdge;
> +	unsigned int			InputCounterIncrementCtrlRegNegativeEdge;
> +	unsigned int			InputRisingEventCtrlReg;
> +	unsigned int			InputFallingEventCtrlReg;
> +	unsigned int			DirectionCtrlReg;
> +	unsigned int			OutputInitialValueReg;
> +};
> +
> +#define DIO_MAX_DATA_LENGTH		128
> +
> +typedef struct _DIO_HEADER
> +{
> +	unsigned char		Version;
> +	unsigned char		Reserved;
> +	unsigned short		CmdResponseEventData;
> +	unsigned short		ResponseStatus;
> +	unsigned int		Length;
> +
> +} DIO_HEADER, *PDIO_HEADER;
> +
> +typedef struct _DIO_PACKAGE
> +{
> +	DLIST				Entry;
> +	DIO_HEADER			Header;
> +	unsigned char * 	DataPtr;
> +
> +} DIO_PACKAGE, *PDIO_PACKAGE;
> +
> +#define SDCDIO_CMD_GET_INFO											0x0001
> +#define SDCDIO_CMD_GET_BANK_STATE									0x0002
> +#define SDCDIO_CMD_GET_BANK_INPUT_DELTA_STATE						0x0003
> +#define SDCDIO_CMD_GET_BANK_INPUT_INVERT_ENABLE						0x0004
> +#define SDCDIO_CMD_SET_BANK_INPUT_INVERT_ENABLE						0x0005
> +#define SDCDIO_CMD_GET_BANK_INPUT_LATCH_RISING_EDGE					0x0006
> +#define SDCDIO_CMD_SET_BANK_INPUT_LATCH_RISING_EDGE					0x0007
> +#define SDCDIO_CMD_GET_BANK_INPUT_LATCH_FALLING_EDGE				0x0008
> +#define SDCDIO_CMD_SET_BANK_INPUT_LATCH_FALLING_EDGE				0x0009
> +#define SDCDIO_CMD_SET_BANK_INPUT_COUNTER_RESET						0x000a
> +#define SDCDIO_CMD_GET_BANK_INPUT_COUNTER_INCREMENT_RISING_EDGE		0x000b
> +#define SDCDIO_CMD_SET_BANK_INPUT_COUNTER_INCREMENT_RISING_EDGE		0x000c
> +#define SDCDIO_CMD_GET_BANK_INPUT_COUNTER_INCREMENT_FALLING_EDGE	0x000d
> +#define SDCDIO_CMD_SET_BANK_INPUT_COUNTER_INCREMENT_FALLING_EDGE	0x000e
> +#define SDCDIO_CMD_GET_BANK_INPUT_RISING_EVENT_CTRL					0x000f
> +#define SDCDIO_CMD_SET_BANK_INPUT_RISING_EVENT_CTRL					0x0010
> +#define SDCDIO_CMD_GET_BANK_INPUT_FALLING_EVENT_CTRL				0x0011
> +#define SDCDIO_CMD_SET_BANK_INPUT_FALLING_EVENT_CTRL				0x0012
> +#define SDCDIO_CMD_SET_BANK_STATE									0x0013
> +#define SDCDIO_CMD_GET_BANK_DIRECTION								0x0014
> +#define SDCDIO_CMD_SET_BANK_DIRECTION								0x0015
> +#define SDCDIO_CMD_GET_BANK_OUTPUT_INITIAL_VALUE					0x0016
> +#define SDCDIO_CMD_SET_BANK_OUTPUT_INITIAL_VALUE					0x0017
> +#define SDCDIO_CMD_GET_BANK_CTRL_REGISTER							0x0018
> +#define SDCDIO_CMD_SET_BANK_CTRL_REGISTER							0x0019
> +#define SDCDIO_CMD_GET_BANK_INPUT_PORT_COUNTER						0x001a
> +#define SDCDIO_EVENT												0x1001
> +
> +
> +
> +
> +#define SDCDIO_STATUS_SUCCESS										0x0000
> +#define SDCDIO_LENGTH_INVALID										0x0001
> +#define SDCDIO_DATA_INVALID											0x0002
> +#define SDCDIO_CONTROLLER_VERSION_UNSUPPORT							0x0003
> +#define SDCDIO_UNSUPPORT_COMMAND									0x0004
> +#define SDCDIO_ALLOC_MEMORY_FAIL									0x0005
> +
> +#define SDCDIO_BANK_NOT_FOUND										0x0010
> +#define SDCDIO_BANK_IO_NOT_FOUND									0x0011
> +#define SDCDIO_UNSUPPORT_INPUT_CAP									0x0012
> +#define SDCDIO_UNSUPPORT_OUTPUT_CAP									0x0013
> +#define SDCDIO_NO_INPUT_IO											0x0014
> +#define SDCDIO_NO_OUTPUT_IO											0x0015
> +#define SDCDIO_UNSUPPORT_RISING_EDGE_TRIGGER_CAP					0x0016
> +#define SDCDIO_UNSUPPORT_FALLING_EDGE_TRIGGER_CAP					0x0017
> +
> +#define SDCDIO_UNDEFINE_ERROR										0xffff
> +
> +#define SUNIX_SDC_DIO_PACK_PTR(ListEntry) \
> +	STRUCT_BASE_POINTER(ListEntry, DIO_PACKAGE, Entry)
> +
> +
> +/*******************************************************
> +	spi
> +*******************************************************/
> +
> +#define SUNIX_SDC_SPI_MAX					32
> +#define SUNIX_SDC_SPI_BUFF					1024
> +
> +struct snx_spi_info
> +{
> + 	unsigned char			model_name[32];
> +	unsigned int			bus_number;
> +	unsigned int			dev_number;
> +	unsigned int			line;
> +	unsigned long			phy2_base_start;
> +	void __iomem *			membase;
> +	unsigned int			memoffset;
> +	unsigned int			memsize;
> +	unsigned int			irq;
> +
> +	struct sdc_cib			cib_info;
> +};
> +
> +struct sunix_sdc_spi_channel
> +{
> +	struct snx_spi_info		info;
> +	struct cdev				cdev;
> +
> +	DLIST					packList;
> +	spinlock_t				packLock;
> +	wait_queue_head_t		readWQ;
> +	unsigned int			readDataReady;
> +	struct semaphore		sem;
> +
> +	bool					isOpened;
> +
> +	unsigned char *			incomeBuff;
> +	unsigned char *			outcomeBuff;
> +	unsigned char *			translateBuff;
> +};
> +
> +#define SPI_MAX_DATA_LENGTH		512
> +
> +typedef struct _SPI_HEADER
> +{
> +	unsigned char		Version;
> +	unsigned char		Reserved;
> +	unsigned short		CmdResponseEventData;
> +	unsigned short		ResponseStatus;
> +	unsigned int		Length;
> +
> +} SPI_HEADER, *PSPI_HEADER;
> +
> +typedef struct _SPI_PACKAGE
> +{
> +	DLIST				Entry;
> +	SPI_HEADER			Header;
> +	unsigned char * 	DataPtr;
> +
> +} SPI_PACKAGE, *PSPI_PACKAGE;
> +
> +#define SDCSPI_CMD_GET_INFO											0x0001
> +#define SDCSPI_CMD_GET_BASIC_CTRL									0x0002
> +#define SDCSPI_CMD_SET_BASIC_CTRL									0x0003
> +#define SDCSPI_CMD_GET_MODE_CTRL									0x0004
> +#define SDCSPI_CMD_SET_MODE_CTRL									0x0005
> +#define SDCSPI_CMD_GET_DIVISOR										0x0006
> +#define SDCSPI_CMD_SET_DIVISOR										0x0007
> +#define SDCSPI_CMD_GET_STATUS										0x0008
> +#define SDCSPI_CMD_GET_CS_SCLK_SETUP_DELAY_TIME_UNIT				0x0009
> +#define SDCSPI_CMD_SET_CS_SCLK_SETUP_DELAY_TIME_UNIT				0x000a
> +#define SDCSPI_CMD_GET_CS_SCLK_HOLD_DELAY_TIME_UNIT					0x000b
> +#define SDCSPI_CMD_SET_CS_SCLK_HOLD_DELAY_TIME_UNIT					0x000c
> +#define SDCSPI_CMD_GET_QUIET_DELAY_TIME_UNIT						0x000d
> +#define SDCSPI_CMD_SET_QUIET_DELAY_TIME_UNIT						0x000e
> +#define SDCSPI_CMD_GET_PORT_IRQ_ENABLE_REG							0x000f
> +#define SDCSPI_CMD_SET_PORT_IRQ_ENABLE_REG							0x0010
> +#define SDCSPI_CMD_GET_PORT_IRQ_STATUS_REG							0x0011
> +#define SDCSPI_CMD_GET_GPIO_OUTPUT_WRITE_ENABLE_REG					0x0012
> +#define SDCSPI_CMD_SET_GPIO_OUTPUT_WRITE_ENABLE_REG					0x0013
> +#define SDCSPI_CMD_GET_GPIO_OUTPUT_REG								0x0014
> +#define SDCSPI_CMD_SET_GPIO_OUTPUT_REG								0x0015
> +#define SDCSPI_CMD_GET_TRANSCATION_CTRL_REG0						0x0016
> +#define SDCSPI_CMD_SET_TRANSCATION_CTRL_REG0						0x0017
> +#define SDCSPI_CMD_GET_TRANSCATION_CTRL_REG1						0x0018
> +#define SDCSPI_CMD_SET_TRANSCATION_CTRL_REG1						0x0019
> +#define SDCSPI_CMD_GET_PORT_EXTEND_CTRL_REG0						0x001a
> +#define SDCSPI_CMD_SET_PORT_EXTEND_CTRL_REG0						0x001b
> +#define SDCSPI_CMD_GET_PORT_EXTEND_CTRL_REG1						0x001c
> +#define SDCSPI_CMD_SET_PORT_EXTEND_CTRL_REG1						0x001d
> +#define SDCSPI_CMD_GET_RAM											0x001e
> +#define SDCSPI_CMD_SET_RAM											0x001f
> +
> +
> +
> +
> +#define SDCSPI_STATUS_SUCCESS										0x0000
> +#define SDCSPI_LENGTH_INVALID										0x0001
> +#define SDCSPI_DATA_INVALID											0x0002
> +#define SDCSPI_CONTROLLER_VERSION_UNSUPPORT							0x0003
> +#define SDCSPI_UNSUPPORT_COMMAND									0x0004
> +#define SDCSPI_ALLOC_MEMORY_FAIL									0x0005
> +
> +#define SDCSPI_UNDEFINE_ERROR										0xffff
> +
> +#define SUNIX_SDC_SPI_PACK_PTR(ListEntry) \
> +	STRUCT_BASE_POINTER(ListEntry, SPI_PACKAGE, Entry)
> +
> +
> +/*******************************************************
> +
> +*******************************************************/
> +
> +
> +extern struct sunix_sdc_board			sunix_sdc_board_table[SUNIX_SDC_BOARD_MAX];
> +extern struct sunix_sdc_uart_channel	sunix_sdc_uart_table[SUNIX_SDC_UART_MAX + 1];
> +extern struct sunix_sdc_dio_channel		sunix_sdc_dio_table[SUNIX_SDC_DIO_MAX];
> +extern struct sunix_sdc_spi_channel		sunix_sdc_spi_table[SUNIX_SDC_SPI_MAX];
> +
> +extern struct kmem_cache *				sunix_sdc_dio_pack_cache;
> +extern struct kmem_cache *				sunix_sdc_spi_pack_cache;
> +
> +extern unsigned int						sunix_sdc_board_amount;
> +extern unsigned int						sunix_sdc_board_amount;
> +extern unsigned int						sunix_sdc_uart_amount;
> +extern unsigned int						sunix_sdc_dio_amount;
> +extern unsigned int						sunix_sdc_spi_amount;
> +
> +
> +#endif
> +
> +
> diff --git a/drivers/mfd/sdc_function.h b/drivers/mfd/sdc_function.h
> new file mode 100644
> index 000000000000..0a56348123d8
> --- /dev/null
> +++ b/drivers/mfd/sdc_function.h
> @@ -0,0 +1,96 @@
> +
> +
> +#ifndef _SDC_DRVR_FUNCTION_H_
> +#define _SDC_DRVR_FUNCTION_H_
> +
> +
> +// bus.c
> +
> +
> +// mem.c
> +void __iomem * mem_get_bar_ioremap(struct pci_dev *pdev, unsigned int bar_num);
> +void __iomem * mem_get_chl_ioremap(struct pci_dev *pdev, unsigned int bar_num, unsigned int offset, unsigned int size);
> +unsigned int mem_rx32(void __iomem *membase, unsigned int base_offset, unsigned int reg_offset);
> +void mem_tx32(void __iomem *membase, unsigned int base_offset, unsigned int reg_offset, unsigned int data);
> +
> +
> +// list.c
> +void
> +SxxListInit(
> +	DLIST *					pListHead
> +	);
> +
> +bool
> +SxxListEmpty(
> +	DLIST *					pListHead
> +	);
> +
> +DLIST *
> +SxxListGetNext(
> +	DLIST *					pListHead
> +	);
> +
> +DLIST *
> +SxxListGetPrev(
> +	DLIST *					pListHead
> +	);
> +
> +void
> +SxxListRemoveEntry(
> +	DLIST *					pEntry
> +	);
> +
> +void
> +SxxListInsertEntry(
> +	DLIST *					pEntry,
> +	DLIST * 				pNewEntry
> +	);
> +
> +void
> +SxxListInsertHead(
> +	DLIST *					pListHead,
> +	DLIST *					pEntry
> +	);
> +
> +void
> +SxxListInsertTail(
> +	DLIST *					pListHead,
> +	DLIST *					pEntry
> +	);
> +
> +
> +// uart.c
> +int snx_ser_startup(struct snx_ser_state *, int);
> +void snx_ser_update_termios(struct snx_ser_state *);
> +int sunix_ser_register_ports(void);
> +void sunix_ser_unregister_ports(void);
> +int sunix_ser_register_driver(void);
> +void sunix_ser_unregister_driver(void);
> +int sunix_ser_interrupt(struct sunix_sdc_uart_channel *);
> +
> +
> +// dio.c
> +int sunix_dio_register_channel(void);
> +void sunix_dio_unregister_channel(void);
> +int sunix_dio_interrupt(struct sunix_sdc_dio_channel *dio_chl, unsigned int event_header);
> +
> +
> +// dio_pack.c
> +int sunix_dio_handle_outcome(struct sunix_sdc_dio_channel *dio_chl, size_t count, unsigned int * outcomeLength);
> +int sunix_dio_handle_income(struct sunix_sdc_dio_channel *dio_chl, size_t count);
> +
> +
> +// spi.c
> +int sunix_spi_register_channel(void);
> +void sunix_spi_unregister_channel(void);
> +int sunix_spi_interrupt(struct sunix_sdc_spi_channel *spi_chl, unsigned int event_header);
> +
> +
> +// spi_pack.c
> +int sunix_spi_handle_outcome(struct sunix_sdc_spi_channel *spi_chl, size_t count, unsigned int * outcomeLength);
> +int sunix_spi_handle_income(struct sunix_sdc_spi_channel *spi_chl, size_t count);
> +
> +
> +#endif
> +
> +
> diff --git a/drivers/mfd/sdc_include.h b/drivers/mfd/sdc_include.h
> new file mode 100644
> index 000000000000..de342b8a363a
> --- /dev/null
> +++ b/drivers/mfd/sdc_include.h
> @@ -0,0 +1,108 @@
> +#ifdef	MODVERSIONS
> +#ifndef MODULE
> +#define	MODULE
> +#endif
> +#endif
> +
> +
> +#include <linux/version.h>
> +#ifndef KERNEL_VERSION
> +#define KERNEL_VERSION(ver, rel, seq)	((ver << 16) | (rel << 8) | seq)
> +#endif
> +
> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
> +#ifdef MODULE
> +#include <linux/config.h>
> +#ifdef MODVERSIONS
> +#include <linux/modversions.h>
> +#endif
> +#include <linux/module.h>
> +#else
> +#define	MOD_INC_USE_COUNT
> +#define MOD_DEC_USE_COUNT
> +#endif
> +
> +
> +#include <linux/autoconf.h>
> +#include <linux/sched.h>
> +#include <linux/timer.h>
> +#include <linux/major.h>
> +#include <linux/string.h>
> +#include <linux/fcntl.h>
> +#include <linux/ptrace.h>
> +#include <linux/delay.h>
> +#include <linux/tty_flip.h>
> +#include <asm/bitops.h>
> +
> +#ifndef PCI_ANY_ID
> +#define PCI_ANY_ID (~0)
> +#endif
> +#endif
> +
> +#include <linux/errno.h>
> +#include <linux/signal.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/serial.h>
> +#include <linux/serial_reg.h>
> +#include <linux/ioport.h>
> +#include <linux/mm.h>
> +
> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
> +#include <linux/smp_lock.h>
> +#endif
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/wait.h>
> +#include <linux/tty_driver.h>
> +#include <linux/pci.h>
> +#include <linux/circ_buf.h>
> +
> +#include <asm/uaccess.h>
> +#include <asm/io.h>
> +#include <asm/irq.h>
> +#include <asm/segment.h>
> +#include <asm/serial.h>
> +#include <linux/interrupt.h>
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +#include <linux/module.h>
> +#include <linux/workqueue.h>
> +#include <linux/moduleparam.h>
> +#include <linux/console.h>
> +#include <linux/sysrq.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#endif
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
> +#include <linux/kref.h>
> +#endif
> +
> +#include <linux/parport.h>
> +#include <linux/ctype.h>
> +#include <linux/poll.h>
> +
> +
> +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17))
> +#include <linux/devfs_fs_kernel.h>
> +#endif
> +
> +
> +#include <linux/sched.h>
> +#include <linux/serial_8250.h>
> +#include <linux/cdev.h>
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
> +#include <linux/sched/signal.h>
> +#endif
> +
> +#include <linux/fs.h>
> +
> +#include "sdc_define.h"
> +#include "sdc_function.h"
> +
> +
> diff --git a/drivers/mfd/spi.c b/drivers/mfd/spi.c
> new file mode 100644
> index 000000000000..4c7c1c494255
> --- /dev/null
> +++ b/drivers/mfd/spi.c
> @@ -0,0 +1,420 @@
> +
> +
> +#include "sdc_include.h"
> +
> +
> +static int sunix_spi_open(struct inode *inode, struct file *file)
> +{
> +	int line = MINOR(file->f_path.dentry->d_inode->i_rdev);
> +	struct sunix_sdc_spi_channel *spi_chl = NULL;
> +	int status = 0;
> +
> +
> +	do
> +	{
> +		if (line > SUNIX_SDC_SPI_MAX)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		spi_chl = &sunix_sdc_spi_table[line];
> +		if (spi_chl->info.memsize == 0)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		if (spi_chl->isOpened == true)
> +		{
> +			status = -EBUSY;
> +			break;
> +		}
> +
> +
> +		spi_chl->readDataReady = 0;
> +		spi_chl->isOpened = true;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +		try_module_get(THIS_MODULE);
> +#else
> +		MOD_INC_USE_COUNT;
> +#endif
> +
> +	} while (false);
> +
> +	return status;
> +}

completely drop that proprietary device node, use spi subsystem.

> +
> +
> +static int sunix_spi_release(struct inode *inode, struct file *file)
> +{
> +	int line = MINOR(file->f_path.dentry->d_inode->i_rdev);
> +	struct sunix_sdc_spi_channel *spi_chl = NULL;
> +	int status = 0;
> +	DLIST * pListHead = NULL;
> +	DLIST * e = NULL;
> +	unsigned long Flags;
> +	PSPI_PACKAGE pPack = NULL;
> +
> +
> +	do
> +	{
> +		if (line > SUNIX_SDC_SPI_MAX)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		spi_chl = &sunix_sdc_spi_table[line];
> +		if (spi_chl->info.memsize == 0)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		if (spi_chl->isOpened == false)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +
> +		pListHead = &spi_chl->packList;
> +		spin_lock_irqsave(&spi_chl->packLock, Flags);
> +		while (!SxxListEmpty(pListHead))
> +		{
> +			e = SxxListGetNext(pListHead);
> +			pPack = SUNIX_SDC_SPI_PACK_PTR(e);
> +			if (pPack != NULL)
> +			{
> +				printk("SUNIX: SPI FREE pack, line:%d, pack:x%p, DataPtrx%p\n", spi_chl->info.line, pPack, pPack->DataPtr);
> +				SxxListRemoveEntry(e);
> +				if (pPack->DataPtr != NULL)
> +				{
> +					kfree(pPack->DataPtr);
> +					pPack->DataPtr = NULL;
> +				}
> +				kmem_cache_free(sunix_sdc_spi_pack_cache, pPack);
> +				pPack = NULL;
> +			}
> +		}
> +		spin_unlock_irqrestore(&spi_chl->packLock, Flags);
> +
> +		spi_chl->isOpened = false;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +		module_put(THIS_MODULE);
> +#else
> +		MOD_DEC_USE_COUNT;
> +#endif
> +
> +	} while (false);
> +
> +	return status;
> +}
> +
> +
> +static long sunix_spi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> +{
> +	int line = MINOR(file->f_path.dentry->d_inode->i_rdev);
> +	struct sunix_sdc_spi_channel *spi_chl = NULL;
> +	int status = 0;
> +
> +
> +	do
> +	{
> +		if (line > SUNIX_SDC_SPI_MAX)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		spi_chl = &sunix_sdc_spi_table[line];
> +		if (spi_chl->info.memsize == 0)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		if (spi_chl->isOpened == false)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +
> +	} while (false);
> +
> +	return status;
> +}
> +
> +
> +static ssize_t sunix_spi_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
> +{
> +	int line = MINOR(file->f_path.dentry->d_inode->i_rdev);
> +	struct sunix_sdc_spi_channel *spi_chl = NULL;
> +	int status = 0;
> +	unsigned int outcomeLength = 0;
> +
> +
> +	if (line > SUNIX_SDC_SPI_MAX)
> +	{
> +		return -ENODEV;
> +	}
> +	spi_chl = &sunix_sdc_spi_table[line];
> +	if (spi_chl->info.memsize == 0)
> +	{
> +		return -ENODEV;
> +	}
> +	if (spi_chl->isOpened == false)
> +	{
> +		return -ENODEV;
> +	}
> +
> +	if (count < sizeof(SPI_HEADER))
> +	{
> +		return -ENOMEM;
> +	}
> +
> +
> +	if (down_interruptible(&spi_chl->sem))
> +	{
> +		return -ERESTARTSYS;
> +	}
> +
> +	if (spi_chl->readDataReady == 0)
> +	{
> +		up(&spi_chl->sem);
> +
> +		if ((file->f_flags & O_NONBLOCK))
> +		{
> +			return -EAGAIN;
> +		}
> +
> +		wait_event_interruptible(spi_chl->readWQ, spi_chl->readDataReady == 1);
> +
> +		if (down_interruptible(&spi_chl->sem))
> +		{
> +			return -ERESTARTSYS;
> +		}
> +	}
> +
> +
> +	do
> +	{
> +		status = sunix_spi_handle_outcome(spi_chl, count, &outcomeLength);
> +		if (status != 0)
> +		{
> +			break;
> +		}
> +		if (count < outcomeLength)
> +		{
> +			status = -ENOMEM;
> +			break;
> +		}
> +		if (outcomeLength <= 0)
> +		{
> +			status = 0;
> +			break;
> +		}
> +
> +		if (copy_to_user((void *)buf, spi_chl->outcomeBuff, outcomeLength))
> +		{
> +			status = -EFAULT;
> +			break;
> +		}
> +
> +		status = outcomeLength;
> +
> +	} while (false);
> +
> +
> +	spi_chl->readDataReady = 0;
> +	up(&spi_chl->sem);
> +
> +	return status;
> +}
> +
> +
> +static ssize_t sunix_spi_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
> +{
> +	int line = MINOR(file->f_path.dentry->d_inode->i_rdev);
> +	struct sunix_sdc_spi_channel *spi_chl = NULL;
> +	int status = 0;
> +
> +
> +	do
> +	{
> +		if (line > SUNIX_SDC_SPI_MAX)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		spi_chl = &sunix_sdc_spi_table[line];
> +		if (spi_chl->info.memsize == 0)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +		if (spi_chl->isOpened == false)
> +		{
> +			status = -ENODEV;
> +			break;
> +		}
> +
> +		if (count < sizeof(SPI_HEADER))
> +		{
> +			status = -EFAULT;
> +			break;
> +		}
> +
> +		if (count > (sizeof(SPI_HEADER) + SPI_MAX_DATA_LENGTH))
> +		{
> +			status = -ENOMEM;
> +			break;
> +		}
> +
> +		if (copy_from_user(spi_chl->incomeBuff, (void *)buf, count))
> +		{
> +			status = -EFAULT;
> +			break;
> +		}
> +
> +		status = sunix_spi_handle_income(spi_chl, count);
> +		if (status == 0)
> +		{
> +			status = count;
> +		}
> +
> +	} while (false);
> +
> +	return status;
> +}
> +
> +
> +unsigned int sunix_spi_poll(struct file *file, poll_table *wait)
> +{
> +	int line = MINOR(file->f_path.dentry->d_inode->i_rdev);
> +	struct sunix_sdc_spi_channel *spi_chl = NULL;
> +	unsigned int mask = POLLOUT | POLLWRNORM;
> +
> +
> +	do
> +	{
> +		if (line > SUNIX_SDC_SPI_MAX)
> +		{
> +			mask = -ENODEV;
> +			break;
> +		}
> +		spi_chl = &sunix_sdc_spi_table[line];
> +		if (spi_chl->info.memsize == 0)
> +		{
> +			mask = -ENODEV;
> +			break;
> +		}
> +		if (spi_chl->isOpened == false)
> +		{
> +			mask = -ENODEV;
> +			break;
> +		}
> +
> +
> +		down(&spi_chl->sem);
> +
> +		poll_wait(file, &spi_chl->readWQ, wait);
> +
> +		if (spi_chl->readDataReady == 1)
> +		{
> +			mask |= (POLLIN | POLLRDNORM);
> +		}
> +
> +		up(&spi_chl->sem);
> +
> +	} while (false);
> +
> +	return mask;
> +}
> +
> +
> +static int sunix_spi_uevent(struct device *dev, struct kobj_uevent_env *env)
> +{
> +	add_uevent_var(env, "DEVMODE=%#o", 0666);
> +	return 0;
> +}
> +
> +
> +static const struct file_operations sunix_sdc_spi_fops =
> +{
> +	.owner				= THIS_MODULE,
> +	.open				= sunix_spi_open,
> +	.release			= sunix_spi_release,
> +	.unlocked_ioctl		= sunix_spi_ioctl,
> +	.read				= sunix_spi_read,
> +	.write 				= sunix_spi_write,
> +	.poll				= sunix_spi_poll
> +};
> +
> +
> +static int sunix_sdc_spi_dev_major = 0;
> +static struct class *sunix_sdc_spi_dev_class = NULL;
> +
> +
> +int sunix_spi_register_channel(void)
> +{
> +	int err, i;
> +	dev_t dev;
> +	struct sunix_sdc_spi_channel *spi_chl = NULL;
> +
> +
> +	err = alloc_chrdev_region(&dev, 0, sunix_sdc_spi_amount, "sunix_sdc_spi");
> +	if (err != 0)
> +	{
> +		return err;
> +	}
> +
> +	sunix_sdc_spi_dev_major = MAJOR(dev);
> +
> +	sunix_sdc_spi_dev_class = class_create(THIS_MODULE, "sunix_sdc_spi");
> +	sunix_sdc_spi_dev_class->dev_uevent = sunix_spi_uevent;
> +
> +	for (i = 0; i < sunix_sdc_spi_amount; i++)
> +	{
> +		spi_chl = &sunix_sdc_spi_table[i];
> +		if ((spi_chl != NULL) && (spi_chl->info.membase != NULL))
> +		{
> +			request_mem_region(spi_chl->info.phy2_base_start + spi_chl->info.memoffset, spi_chl->info.memsize, "sunix_sdc_spi");
> +
> +			cdev_init(&spi_chl->cdev, &sunix_sdc_spi_fops);
> +			spi_chl->cdev.owner = THIS_MODULE;
> +
> +			cdev_add(&spi_chl->cdev, MKDEV(sunix_sdc_spi_dev_major, i), 1);
> +
> +			device_create(sunix_sdc_spi_dev_class, NULL, MKDEV(sunix_sdc_spi_dev_major, i), NULL, "SDCSPI%d", i);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +
> +void sunix_spi_unregister_channel(void)
> +{
> +	int i;
> +	struct sunix_sdc_spi_channel *spi_chl = NULL;
> +
> +
> +	for (i = 0; i < sunix_sdc_spi_amount; i++)
> +	{
> +		spi_chl = &sunix_sdc_spi_table[i];
> +		if ((spi_chl != NULL) && (spi_chl->info.membase != NULL))
> +		{
> +			device_destroy(sunix_sdc_spi_dev_class, MKDEV(sunix_sdc_spi_dev_major, i));
> +
> +			release_mem_region(spi_chl->info.phy2_base_start + spi_chl->info.memoffset, spi_chl->info.memsize);
> +		}
> +	}
> +
> +	class_unregister(sunix_sdc_spi_dev_class);
> +	class_destroy(sunix_sdc_spi_dev_class);
> +
> +	unregister_chrdev_region(MKDEV(sunix_sdc_spi_dev_major, 0), MINORMASK);
> +}
> +
> +
> +int sunix_spi_interrupt(struct sunix_sdc_spi_channel *spi_chl, unsigned int event_header)
> +{
> +    return 0;
> +}
> diff --git a/drivers/mfd/spi_pack.c b/drivers/mfd/spi_pack.c
> new file mode 100644
> index 000000000000..ff49e0ae94ac
> --- /dev/null
> +++ b/drivers/mfd/spi_pack.c
> @@ -0,0 +1,1506 @@
> +
> +
> +#include "sdc_include.h"
> +
> +
> +static void get_info(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	struct sdc_cib * cib_info = &spi_chl->info.cib_info;
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int Address = 0;
> +	int i = 0;
> +
> +
> +	do
> +	{
> +		Address = spi_chl->info.phy2_base_start + spi_chl->info.memoffset;
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?(31 + (cib_info->spi_number_of_device * 12)):0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		memcpy(&TrBuff[TrLength], spi_chl->info.model_name, 16);
> +		TrLength += 16;
> +		TrBuff[TrLength++] = spi_chl->info.bus_number;
> +		TrBuff[TrLength++] = spi_chl->info.dev_number;
> +		TrBuff[TrLength++] = spi_chl->info.line;
> +		TrBuff[TrLength++] = (unsigned char)((Address & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((Address & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((Address & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((Address & 0x000000ff));
> +		TrBuff[TrLength++] = (unsigned char)(spi_chl->info.irq);
> +
> +		TrBuff[TrLength++] = cib_info->version;
> +		TrBuff[TrLength++] = (unsigned char)((cib_info->spi_significand_of_clock & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((cib_info->spi_significand_of_clock & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((cib_info->spi_significand_of_clock & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((cib_info->spi_significand_of_clock & 0x000000ff));
> +		TrBuff[TrLength++] = cib_info->spi_exponent_of_clock;
> +		TrBuff[TrLength++] = cib_info->spi_number_of_device;
> +
> +		for (i = 0; i < cib_info->spi_number_of_device; i++)
> +		{
> +			TrBuff[TrLength++] = i;
> +			TrBuff[TrLength++] = cib_info->spi_device_cap[i].type;
> +			TrBuff[TrLength++] = cib_info->spi_device_cap[i].number_of_gpio_input;
> +			TrBuff[TrLength++] = cib_info->spi_device_cap[i].number_of_gpio_output;
> +			memcpy(&TrBuff[TrLength], cib_info->spi_device_cap[i].name, 8);
> +			TrLength += 8;
> +		}
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_basic_ctrl(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BasicCtrl = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 0);
> +		//printk("SUNIX: SPI (%d), get basic ctrl, 1, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		BasicCtrl = (CtrlReg & 0x000000ff);
> +		//printk("SUNIX: SPI (%d), get basic ctrl, 2, BasicCtrl:x%02x\n", spi_chl->info.line, BasicCtrl);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?1:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = BasicCtrl;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_basic_ctrl(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	unsigned char * RxBuff = spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char BasicCtrl = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +		BasicCtrl = (unsigned char)*(RxBuff + sizeof(SPI_HEADER) + 0);
> +		//printk("SUNIX: SPI (%d), set basic ctrl, BasicCtrl:x%02x\n", spi_chl->info.line, BasicCtrl);
> +
> +
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 0);
> +		//printk("SUNIX: SPI (%d), set basic ctrl, 1, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		CtrlReg &= 0xffffff00;
> +		//printk("SUNIX: SPI (%d), set basic ctrl, 2, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		CtrlReg |= BasicCtrl;
> +		//printk("SUNIX: SPI (%d), set basic ctrl, 3, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +
> +		mem_tx32(spi_chl->info.membase, spi_chl->info.memoffset, 0, CtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?0:0;
> +	TrLength = sizeof(SPI_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_mode_ctrl(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char ModeCtrl = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 0);
> +		//printk("SUNIX: SPI (%d), get mode ctrl, 1, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		ModeCtrl = ((CtrlReg & 0x0000ff00) >> 8);
> +		//printk("SUNIX: SPI (%d), get mode ctrl, 2, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?1:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = ModeCtrl;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_mode_ctrl(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	unsigned char * RxBuff = spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char ModeCtrl = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +		ModeCtrl = (unsigned char)*(RxBuff + sizeof(SPI_HEADER) + 0);
> +		//printk("SUNIX: SPI (%d), set mode ctrl, ModeCtrl:x%02x\n", spi_chl->info.line, ModeCtrl);
> +
> +
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 0);
> +		//printk("SUNIX: SPI (%d), set mode ctrl, 1, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		CtrlReg &= 0xffff00ff;
> +		//printk("SUNIX: SPI (%d), set mode ctrl, 2, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		CtrlReg |= (ModeCtrl << 8);
> +		//printk("SUNIX: SPI (%d), set mode ctrl, 3, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +
> +		mem_tx32(spi_chl->info.membase, spi_chl->info.memoffset, 0, CtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?0:0;
> +	TrLength = sizeof(SPI_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_divisor(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned short Divisor = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 0);
> +		//printk("SUNIX: SPI (%d), get divisor, 1, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		Divisor = ((CtrlReg & 0xffff0000) >> 16);
> +		//printk("SUNIX: SPI (%d), get divisor, 2, Divisor:x%04x\n", spi_chl->info.line, Divisor);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?2:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = (unsigned char)((Divisor & 0xff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((Divisor & 0x00ff));
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_divisor(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	unsigned char * RxBuff = spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned short Divisor = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 2)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +		Divisor  = (unsigned short)(*(RxBuff + sizeof(SPI_HEADER) + 0) << 8);
> +		Divisor |= (unsigned short)(*(RxBuff + sizeof(SPI_HEADER) + 1));
> +		//printk("SUNIX: SPI (%d), set divisor, Divisor:x%04x\n", spi_chl->info.line, Divisor);
> +
> +
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 0);
> +		//printk("SUNIX: SPI (%d), set divisor, 1, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		CtrlReg &= 0x0000ffff;
> +		//printk("SUNIX: SPI (%d), set divisor, 2, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		CtrlReg |= (Divisor << 16);
> +		//printk("SUNIX: SPI (%d), set divisor, 3, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +
> +		mem_tx32(spi_chl->info.membase, spi_chl->info.memoffset, 0, CtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?0:0;
> +	TrLength = sizeof(SPI_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_status(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char Status = 0;
> +	unsigned int StatusReg = 0;
> +
> +
> +	do
> +	{
> +		StatusReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 1);
> +		//printk("SUNIX: SPI (%d), get status, 1, StatusReg:x%08x\n", spi_chl->info.line, StatusReg);
> +		Status = (StatusReg & 0x000000ff);
> +		//printk("SUNIX: SPI (%d), get status, 2, Status:x%02x\n", spi_chl->info.line, Status);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?1:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = Status;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_CS_SCLK_setup_delay_time_unit(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char TimeUnit = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 2);
> +		//printk("SUNIX: SPI (%d), get CS/SCLK setup delay time unit, 1, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		TimeUnit = (CtrlReg & 0x000000ff);
> +		//printk("SUNIX: SPI (%d), get CS/SCLK setup delay time unit, 2, TimeUnit:x%02x\n", spi_chl->info.line, TimeUnit);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?1:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = TimeUnit;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_CS_SCLK_setup_delay_time_unit(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	unsigned char * RxBuff = spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char TimeUnit = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +		TimeUnit = (unsigned char)*(RxBuff + sizeof(SPI_HEADER) + 0);
> +		//printk("SUNIX: SPI (%d), set CS/SCLK setup delay time unit, TimeUnit:x%02x\n", spi_chl->info.line, TimeUnit);
> +
> +
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 2);
> +		//printk("SUNIX: SPI (%d), set CS/SCLK setup delay time unit, 1, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		CtrlReg &= 0xffffff00;
> +		//printk("SUNIX: SPI (%d), set CS/SCLK setup delay time unit, 2, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		CtrlReg |= TimeUnit;
> +		//printk("SUNIX: SPI (%d), set CS/SCLK setup delay time unit, 3, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +
> +		mem_tx32(spi_chl->info.membase, spi_chl->info.memoffset, 2, CtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?0:0;
> +	TrLength = sizeof(SPI_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_CS_SCLK_hold_delay_time_unit(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char TimeUnit = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 2);
> +		//printk("SUNIX: SPI (%d), get CS/SCLK hold delay time unit, 1, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		TimeUnit = ((CtrlReg & 0x0000ff00) >> 8);
> +		//printk("SUNIX: SPI (%d), get CS/SCLK hold delay time unit, 2, TimeUnit:x%02x\n", spi_chl->info.line, TimeUnit);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?1:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = TimeUnit;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_CS_SCLK_hold_delay_time_unit(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	unsigned char * RxBuff = spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char TimeUnit = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +		TimeUnit = (unsigned char)*(RxBuff + sizeof(SPI_HEADER) + 0);
> +		//printk("SUNIX: SPI (%d), set CS/SCLK hold delay time unit, TimeUnit:x%02x\n", spi_chl->info.line, TimeUnit);
> +
> +
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 2);
> +		//printk("SUNIX: SPI (%d), set CS/SCLK hold delay time unit, 1, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		CtrlReg &= 0xffff00ff;
> +		//printk("SUNIX: SPI (%d), set CS/SCLK hold delay time unit, 2, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		CtrlReg |= (TimeUnit << 8);
> +		//printk("SUNIX: SPI (%d), set CS/SCLK hold delay time unit, 3, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +
> +		mem_tx32(spi_chl->info.membase, spi_chl->info.memoffset, 2, CtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?0:0;
> +	TrLength = sizeof(SPI_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_quiet_delay_time_unit(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char TimeUnit = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 2);
> +		//printk("SUNIX: SPI (%d), get quiet delay time unit, 1, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		TimeUnit = ((CtrlReg & 0x00ff0000) >> 16);
> +		//printk("SUNIX: SPI (%d), get quiet delay time unit, 2, TimeUnit:x%02x\n", spi_chl->info.line, TimeUnit);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?1:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = TimeUnit;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_quiet_delay_time_unit(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	unsigned char * RxBuff = spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned char TimeUnit = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 1)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +		TimeUnit = (unsigned char)*(RxBuff + sizeof(SPI_HEADER) + 0);
> +		//printk("SUNIX: SPI (%d), set quiet delay time unit, TimeUnit:x%02x\n", spi_chl->info.line, TimeUnit);
> +
> +
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 2);
> +		//printk("SUNIX: SPI (%d), set quiet delay time unit, 1, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		CtrlReg &= 0xff00ffff;
> +		//printk("SUNIX: SPI (%d), set quiet delay time unit, 2, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +		CtrlReg |= (TimeUnit << 16);
> +		//printk("SUNIX: SPI (%d), set quiet delay time unit, 3, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +
> +		mem_tx32(spi_chl->info.membase, spi_chl->info.memoffset, 2, CtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?0:0;
> +	TrLength = sizeof(SPI_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_port_irq_enable_reg(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 3);
> +		//printk("SUNIX: SPI (%d), get port irq enable reg, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?4:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = (unsigned char)((CtrlReg & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((CtrlReg & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((CtrlReg & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((CtrlReg & 0x000000ff));
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_port_irq_enable_reg(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	unsigned char * RxBuff = spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 4)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +		CtrlReg  =  (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 0) << 24);
> +		CtrlReg |=  (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 1) << 16);
> +		CtrlReg |=  (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 2) << 8);
> +		CtrlReg |=  (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 3));
> +		//printk("SUNIX: SPI (%d), set port irq enable reg, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +
> +		mem_tx32(spi_chl->info.membase, spi_chl->info.memoffset, 3, CtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?0:0;
> +	TrLength = sizeof(SPI_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_port_irq_status_reg(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int StatusReg = 0;
> +
> +
> +	do
> +	{
> +		StatusReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 4);
> +		//printk("SUNIX: SPI (%d), get port irq status reg, StatusReg:x%08x\n", spi_chl->info.line, StatusReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?4:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = (unsigned char)((StatusReg & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((StatusReg & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((StatusReg & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((StatusReg & 0x000000ff));
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_gpio_output_write_enable_reg(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 5);
> +		//printk("SUNIX: SPI (%d), get gpio output write enable reg, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?4:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = (unsigned char)((CtrlReg & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((CtrlReg & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((CtrlReg & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((CtrlReg & 0x000000ff));
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_gpio_output_write_enable_reg(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	unsigned char * RxBuff = spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 4)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +		CtrlReg  = (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 0) << 24);
> +		CtrlReg |= (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 1) << 16);
> +		CtrlReg |= (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 2) << 8);
> +		CtrlReg |= (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 3));
> +		//printk("SUNIX: SPI (%d), set gpio output write enable reg, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +
> +		mem_tx32(spi_chl->info.membase, spi_chl->info.memoffset, 5, CtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?0:0;
> +	TrLength = sizeof(SPI_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_gpio_output_reg(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		CtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 6);
> +		//printk("SUNIX: SPI (%d), get gpio output reg, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?4:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = (unsigned char)((CtrlReg & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((CtrlReg & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((CtrlReg & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((CtrlReg & 0x000000ff));
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_gpio_output_reg(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	unsigned char * RxBuff = spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int CtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 4)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +		CtrlReg  = (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 0) << 24);
> +		CtrlReg |= (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 1) << 16);
> +		CtrlReg |= (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 2) << 8);
> +		CtrlReg |= (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 3));
> +		//printk("SUNIX: SPI (%d), set gpio output reg, CtrlReg:x%08x\n", spi_chl->info.line, CtrlReg);
> +
> +		mem_tx32(spi_chl->info.membase, spi_chl->info.memoffset, 6, CtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?0:0;
> +	TrLength = sizeof(SPI_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_transcation_ctrl_reg0(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int TransCtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 0)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +
> +
> +		TransCtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 7);
> +		//printk("SUNIX: SPI (%d), get transcation ctrl reg0, TransCtrlReg:x%08x\n", spi_chl->info.line, TransCtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?4:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = (unsigned char)((TransCtrlReg & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((TransCtrlReg & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((TransCtrlReg & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((TransCtrlReg & 0x000000ff));
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_transcation_ctrl_reg0(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	unsigned char * RxBuff = spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int TransCtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 4)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +		TransCtrlReg  = (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 0) << 24);
> +		TransCtrlReg |= (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 1) << 16);
> +		TransCtrlReg |= (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 2) << 8);
> +		TransCtrlReg |= (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 3));
> +		//printk("SUNIX: SPI (%d), set transcation ctrl reg0, TransCtrlReg:x%08x\n", spi_chl->info.line, TransCtrlReg);
> +
> +		mem_tx32(spi_chl->info.membase, spi_chl->info.memoffset, 7, TransCtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?0:0;
> +	TrLength = sizeof(SPI_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_transcation_ctrl_reg1(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int TransCtrlReg = 0;
> +
> +
> +	do
> +	{
> +		TransCtrlReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, 8);
> +		//printk("SUNIX: SPI (%d), get transcation ctrl reg1, TransCtrlReg:x%08x\n", spi_chl->info.line, TransCtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?4:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		TrBuff[TrLength++] = (unsigned char)((TransCtrlReg & 0xff000000) >> 24);
> +		TrBuff[TrLength++] = (unsigned char)((TransCtrlReg & 0x00ff0000) >> 16);
> +		TrBuff[TrLength++] = (unsigned char)((TransCtrlReg & 0x0000ff00) >> 8);
> +		TrBuff[TrLength++] = (unsigned char)((TransCtrlReg & 0x000000ff));
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_transcation_ctrl_reg1(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	unsigned char * RxBuff = spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int TransCtrlReg = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length != 4)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +		TransCtrlReg  = (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 0) << 24);
> +		TransCtrlReg |= (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 1) << 16);
> +		TransCtrlReg |= (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 2) << 8);
> +		TransCtrlReg |= (unsigned int)(*(RxBuff + sizeof(SPI_HEADER) + 3));
> +		//printk("SUNIX: SPI (%d), set transcation ctrl reg1, TransCtrlReg:x%08x\n", spi_chl->info.line, TransCtrlReg);
> +
> +		mem_tx32(spi_chl->info.membase, spi_chl->info.memoffset, 8, TransCtrlReg);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?0:0;
> +	TrLength = sizeof(SPI_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void get_ram(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int RamReg = 0;
> +	unsigned int RamRegIndex = 0;
> +	unsigned char Data[SPI_MAX_DATA_LENGTH] = {0};
> +	int DataIndex = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length > SPI_MAX_DATA_LENGTH)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +
> +
> +		for (RamRegIndex = 128; RamRegIndex <= 255; RamRegIndex++)
> +		{
> +			RamReg = mem_rx32(spi_chl->info.membase, spi_chl->info.memoffset, RamRegIndex);
> +			//printk("SUNIX: SPI (%d), get ram, RamRegIndex:%d, RamReg:x%08x\n", spi_chl->info.line, RamRegIndex, RamReg);
> +			Data[DataIndex++] = (RamReg & 0x000000ff);
> +			if (DataIndex >= pRxHeader->Length)
> +			{
> +				break;
> +			}
> +			Data[DataIndex++] = ((RamReg & 0x0000ff00) >> 8);
> +			if (DataIndex >= pRxHeader->Length)
> +			{
> +				break;
> +			}
> +			Data[DataIndex++] = ((RamReg & 0x00ff0000) >> 16);
> +			if (DataIndex >= pRxHeader->Length)
> +			{
> +				break;
> +			}
> +			Data[DataIndex++] = ((RamReg & 0xff000000) >> 24);
> +			if (DataIndex >= pRxHeader->Length)
> +			{
> +				break;
> +			}
> +		}
> +		//printk("SUNIX: SPI (%d), get ram, DataIndex:%d\n", spi_chl->info.line, DataIndex);
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?DataIndex:0;
> +	TrLength = sizeof(SPI_HEADER);
> +	if (pTrHeader->ResponseStatus == SDCSPI_STATUS_SUCCESS)
> +	{
> +		memcpy(&TrBuff[TrLength], Data, DataIndex);
> +		TrLength += DataIndex;
> +	}
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void set_ram(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	unsigned char * RxBuff = spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_STATUS_SUCCESS;
> +	unsigned int TrLength = 0;
> +	unsigned int RamReg = 0;
> +	unsigned int RamRegIndex = 0;
> +	unsigned char Data[SPI_MAX_DATA_LENGTH] = {0};
> +	int DataIndex = 0, i = 0;
> +	unsigned int LengthInDw = 0;
> +
> +
> +	do
> +	{
> +		if (pRxHeader->Length > SPI_MAX_DATA_LENGTH)
> +		{
> +			nStatus = SDCSPI_LENGTH_INVALID;
> +			break;
> +		}
> +
> +
> +		memcpy(Data, RxBuff + sizeof(SPI_HEADER), pRxHeader->Length);
> +
> +		if ((pRxHeader->Length % 4) != 0)
> +		{
> +			LengthInDw = (pRxHeader->Length / 4) + 1;
> +		}
> +		else
> +		{
> +			LengthInDw = (pRxHeader->Length / 4);
> +		}
> +		//printk("SUNIX: SPI (%d), set ram, Length:%d, LengthInDw:%d\n", spi_chl->info.line, pRxHeader->Length, LengthInDw);
> +
> +		DataIndex = 0;
> +		RamRegIndex = 128;
> +		for (i = 0; i < LengthInDw; i++)
> +		{
> +			RamReg  = Data[DataIndex++];
> +			RamReg |= (Data[DataIndex++] << 8);
> +			RamReg |= (Data[DataIndex++] << 16);
> +			RamReg |= (Data[DataIndex++] << 24);
> +
> +			//printk("SUNIX: SPI (%d), set ram, RamRegIndex:%d, RamReg:x%08x\n", spi_chl->info.line, RamRegIndex, RamReg);
> +			mem_tx32(spi_chl->info.membase, spi_chl->info.memoffset, RamRegIndex, RamReg);
> +			RamRegIndex++;
> +		}
> +
> +	} while (false);
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = (nStatus == SDCSPI_STATUS_SUCCESS)?0:0;
> +	TrLength = sizeof(SPI_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +static void unsupport(struct sunix_sdc_spi_channel *spi_chl, unsigned int incomeLength, unsigned int * translateLength)
> +{
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	unsigned int nStatus = SDCSPI_UNSUPPORT_COMMAND;
> +	unsigned int TrLength = 0;
> +
> +
> +	memset(TrBuff, 0, SUNIX_SDC_SPI_BUFF);
> +	TrLength = 0;
> +
> +	pTrHeader->Version = 0x01;
> +	pTrHeader->CmdResponseEventData = pRxHeader->CmdResponseEventData | 0x8000;
> +	pTrHeader->ResponseStatus = nStatus;
> +	pTrHeader->Length = 0;
> +	TrLength = sizeof(PSPI_HEADER);
> +
> +	*translateLength = TrLength;
> +}
> +
> +
> +int sunix_spi_handle_outcome(struct sunix_sdc_spi_channel *spi_chl, size_t count, unsigned int * outcomeLength)
> +{
> +	int status = 0;
> +	PSPI_PACKAGE pPack = NULL;
> +	DLIST *	pListHead = &spi_chl->packList;
> +	DLIST * e = NULL;
> +	unsigned char * TxBuff = spi_chl->outcomeBuff;
> +	unsigned int TrLength = 0;
> +
> +
> +	do
> +	{
> +		do
> +		{
> +			if (!SxxListEmpty(pListHead))
> +			{
> +				e = pListHead->Flink;
> +			}
> +			else
> +			{
> +				break;
> +			}
> +
> +			while ((e != NULL) && (e != pListHead))
> +			{
> +				if (e != NULL)
> +				{
> +					pPack = SUNIX_SDC_SPI_PACK_PTR(e);
> +					if (pPack != NULL)
> +					{
> +						break;
> +					}
> +
> +					e = e->Flink;
> +				}
> +			}
> +
> +		} while (false);
> +
> +		if (pPack == NULL)
> +		{
> +			*outcomeLength = 0;
> +			break;
> +		}
> +
> +
> +		SxxListRemoveEntry(&pPack->Entry);
> +
> +
> +		memset(TxBuff, 0, SUNIX_SDC_SPI_BUFF);
> +		memcpy(TxBuff, &pPack->Header, sizeof(SPI_HEADER));
> +		TrLength = sizeof(SPI_HEADER);
> +		if (pPack->DataPtr != NULL)
> +		{
> +			memcpy(TxBuff + sizeof(SPI_HEADER), pPack->DataPtr, pPack->Header.Length);
> +			TrLength += pPack->Header.Length;
> +		}
> +
> +		*outcomeLength = TrLength;
> +
> +		//printk("SUNIX: SPI FREE pack, line:%d, pack:x%p, DataPtrx%p\n", spi_chl->info.line, pPack, pPack->DataPtr);
> +		if (pPack->DataPtr != NULL)
> +		{
> +			kfree(pPack->DataPtr);
> +			pPack->DataPtr = NULL;
> +		}
> +		kmem_cache_free(sunix_sdc_spi_pack_cache, pPack);
> +		pPack = NULL;
> +			
> +	} while (false);
> +
> +	return status;
> +}
> +
> +
> +int sunix_spi_handle_income(struct sunix_sdc_spi_channel *spi_chl, size_t count)
> +{
> +	int status = 0;
> +	PSPI_HEADER pRxHeader = (PSPI_HEADER)spi_chl->incomeBuff;
> +	PSPI_HEADER pTrHeader = (PSPI_HEADER)spi_chl->translateBuff;
> +	unsigned char * TrBuff = spi_chl->translateBuff;
> +	PSPI_PACKAGE pPack = NULL;
> +	unsigned int translateLength = 0;
> +	unsigned long Flags;
> +
> +
> +	do
> +	{
> +		// debug
> +		/*
> +		printk("++++++++++++++++++++++++++++++++++++++++++++++\n");
> +		printk("SUNIX: SPI_RX, Version              :x%02x\n", pRxHeader->Version);
> +		printk("SUNIX: SPI_RX, CmdResponseEventData :x%04x\n", pRxHeader->CmdResponseEventData);
> +		printk("SUNIX: SPI_RX, Length               :x%08x\n", pRxHeader->Length);
> +		printk("++++++++++++++++++++++++++++++++++++++++++++++\n");
> +		*/
> +
> +
> +		switch (pRxHeader->CmdResponseEventData)
> +		{
> +			case SDCSPI_CMD_GET_INFO :
> +				get_info(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_BASIC_CTRL :
> +				get_basic_ctrl(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_BASIC_CTRL :
> +				set_basic_ctrl(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_MODE_CTRL :
> +				get_mode_ctrl(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_MODE_CTRL :
> +				set_mode_ctrl(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_DIVISOR :
> +				get_divisor(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_DIVISOR :
> +				set_divisor(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_STATUS :
> +				get_status(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_CS_SCLK_SETUP_DELAY_TIME_UNIT :
> +				get_CS_SCLK_setup_delay_time_unit(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_CS_SCLK_SETUP_DELAY_TIME_UNIT :
> +				set_CS_SCLK_setup_delay_time_unit(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_CS_SCLK_HOLD_DELAY_TIME_UNIT :
> +				get_CS_SCLK_hold_delay_time_unit(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_CS_SCLK_HOLD_DELAY_TIME_UNIT :
> +				set_CS_SCLK_hold_delay_time_unit(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_QUIET_DELAY_TIME_UNIT :
> +				get_quiet_delay_time_unit(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_QUIET_DELAY_TIME_UNIT :
> +				set_quiet_delay_time_unit(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_PORT_IRQ_ENABLE_REG :
> +				get_port_irq_enable_reg(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_PORT_IRQ_ENABLE_REG :
> +				set_port_irq_enable_reg(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_PORT_IRQ_STATUS_REG :
> +				get_port_irq_status_reg(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_GPIO_OUTPUT_WRITE_ENABLE_REG :
> +				get_gpio_output_write_enable_reg(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_GPIO_OUTPUT_WRITE_ENABLE_REG :
> +				set_gpio_output_write_enable_reg(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_GPIO_OUTPUT_REG :
> +				get_gpio_output_reg(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_GPIO_OUTPUT_REG :
> +				set_gpio_output_reg(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_TRANSCATION_CTRL_REG0 :
> +				get_transcation_ctrl_reg0(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_TRANSCATION_CTRL_REG0 :
> +				set_transcation_ctrl_reg0(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_TRANSCATION_CTRL_REG1 :
> +				get_transcation_ctrl_reg1(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_TRANSCATION_CTRL_REG1 :
> +				set_transcation_ctrl_reg1(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_PORT_EXTEND_CTRL_REG0 :
> +				unsupport(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_PORT_EXTEND_CTRL_REG0 :
> +				unsupport(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_PORT_EXTEND_CTRL_REG1 :
> +				unsupport(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_PORT_EXTEND_CTRL_REG1 :
> +				unsupport(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_GET_RAM :
> +				get_ram(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			case SDCSPI_CMD_SET_RAM :
> +				set_ram(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +
> +			default :
> +				unsupport(spi_chl, (unsigned int)count, &translateLength);
> +				break;
> +		}
> +
> +
> +		// debug
> +		/*
> +		printk("----------------------------------------------\n");
> +		printk("SUNIX: SPI_TR, translateLength      :%d\n", translateLength);
> +		printk("SUNIX: SPI_TR, Version              :x%02x\n", pTrHeader->Version);
> +		printk("SUNIX: SPI_TR, CmdResponseEventData :x%04x\n", pTrHeader->CmdResponseEventData);
> +		printk("SUNIX: SPI_TR, ResponseStatus       :x%04x\n", pTrHeader->ResponseStatus);
> +		printk("SUNIX: SPI_TR, Length               :x%08x\n", pTrHeader->Length);
> +		{
> +			int i;
> +			for (i = 0; i < pTrHeader->Length; i++)
> +				printk("x%02x ", (unsigned char)*(TrBuff + sizeof(SPI_HEADER) + i));
> +		}
> +		printk("----------------------------------------------\n");
> +		*/
> +
> +
> +		if (pTrHeader->Length > SPI_MAX_DATA_LENGTH)
> +		{
> +			status = -ENOMEM;
> +			break;
> +		}
> +		if (translateLength > (SPI_MAX_DATA_LENGTH + sizeof(SPI_HEADER)))
> +		{
> +			status = -ENOMEM;
> +			break;
> +		}
> +
> +		pPack = kmem_cache_alloc(sunix_sdc_spi_pack_cache, GFP_ATOMIC);
> +		if (pPack == NULL)
> +		{
> +			status = -ENOMEM;
> +			break;
> +		}
> +		memset(pPack, 0, sizeof(SPI_PACKAGE));
> +		pPack->DataPtr = (unsigned char *)kmalloc(SPI_MAX_DATA_LENGTH, GFP_KERNEL);
> +		if (pPack->DataPtr == NULL)
> +		{
> +			status = -ENOMEM;
> +			break;
> +		}
> +		memset(pPack->DataPtr, 0, SPI_MAX_DATA_LENGTH);
> +
> +
> +		SxxListInit(&pPack->Entry);
> +		memcpy(&pPack->Header, pTrHeader, sizeof(SPI_HEADER));
> +		memcpy(pPack->DataPtr, TrBuff + sizeof(SPI_HEADER), pTrHeader->Length);
> +
> +		spin_lock_irqsave(&spi_chl->packLock, Flags);
> +		//printk("SUNIX: SPI ALOC pack, line:%d, pack:x%p, DataPtrx%p\n", spi_chl->info.line, pPack, pPack->DataPtr);
> +		SxxListInsertTail(&spi_chl->packList, &pPack->Entry);
> +
> +		spi_chl->readDataReady = 1;
> +		wake_up_interruptible(&spi_chl->readWQ);
> +		spin_unlock_irqrestore(&spi_chl->packLock, Flags);
> +
> +	} while (false);
> +
> +	if (status != 0)
> +	{
> +		if (pPack != NULL)
> +		{
> +			if (pPack->DataPtr != NULL)
> +			{
> +				kfree(pPack->DataPtr);
> +				pPack->DataPtr = NULL;
> +			}
> +
> +			kmem_cache_free(sunix_sdc_spi_pack_cache, pPack);
> +		}
> +	}
> +
> +	return status;
> +}
> +
> +
> diff --git a/drivers/mfd/uart.c b/drivers/mfd/uart.c
> new file mode 100644
> index 000000000000..bb88630fdca1
> --- /dev/null
> +++ b/drivers/mfd/uart.c
> @@ -0,0 +1,3796 @@
> +
> +
> +#include "sdc_include.h"
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
> +static DEFINE_SEMAPHORE(ser_port_sem);
> +#else
> +static DECLARE_MUTEX(ser_port_sem);
> +#endif
> +
> +
> +#define SNX_HIGH_BITS_OFFSET	((sizeof(long)-sizeof(int))*8)
> +#define sunix_ser_users(state)	((state)->count + ((state)->info ? (state)->info->blocked_open : 0))
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +static struct tty_port snx_service_port;
> +#endif
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +struct serial_uart_config
> +{
> +	char	*name;
> +	int		dfl_xmit_fifo_size;
> +	int		flags;
> +};
> +#endif
> +
> +
> +static const struct serial_uart_config snx_uart_config[PORT_SER_MAX_UART + 1] =
> +{
> +	{ "unknown",    1,      0 },
> +	{ "8250",       1,      0 },
> +	{ "16450",      1,      0 },
> +	{ "16550",      1,      0 },
> +	{ "16550A",     16,     UART_CLEAR_FIFO | UART_USE_FIFO },
> +	{ "Cirrus",     1,    	0 },
> +	{ "ST16650",    1,    	0 },
> +	{ "ST16650V2",  32,    	UART_CLEAR_FIFO | UART_USE_FIFO },
> +	{ "TI16750",    64,    	UART_CLEAR_FIFO | UART_USE_FIFO },
> +};
> +
> +
> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
> +static int		sunix_ser_refcount;
> +static struct tty_struct			*sunix_ser_tty[SUNIX_SDC_UART_MAX + 1];
> +static struct termios				*sunix_ser_termios[SUNIX_SDC_UART_MAX + 1];
> +static struct termios				*sunix_ser_termios_locked[SUNIX_SDC_UART_MAX + 1];
> +#endif
> +
> +
> +static _INLINE_ void snx_ser_handle_cts_change(struct snx_ser_port *, unsigned int);
> +static _INLINE_ void snx_ser_update_mctrl(struct snx_ser_port *, unsigned int, unsigned int);
> +static void     snx_ser_write_wakeup(struct snx_ser_port *);
> +static void     snx_ser_stop(struct tty_struct *);
> +static void     __snx_ser_start(struct tty_struct *);
> +static void     snx_ser_start(struct tty_struct *);
> +static void     snx_ser_tasklet_action(unsigned long);
> +
> +
> +static void     snx_ser_shutdown(struct snx_ser_state *);
> +static _INLINE_ void __snx_ser_put_char(struct snx_ser_port *, struct circ_buf *, unsigned char);
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26))
> +static int      snx_ser_put_char(struct tty_struct *, unsigned char);
> +#else
> +static void     snx_ser_put_char(struct tty_struct *, unsigned char);
> +#endif
> +static void     snx_ser_flush_chars(struct tty_struct *);
> +static int      snx_ser_chars_in_buffer(struct tty_struct *);
> +static void     snx_ser_flush_buffer(struct tty_struct *);
> +static void     snx_ser_send_xchar(struct tty_struct *, char);
> +static void     snx_ser_throttle(struct tty_struct *);
> +static void     snx_ser_unthrottle(struct tty_struct *);
> +static int      snx_ser_get_info(struct snx_ser_state *, struct serial_struct *);
> +static int      snx_ser_set_info(struct snx_ser_state *, struct serial_struct *);
> +static int      snx_ser_write_room(struct tty_struct *);
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
> +static int      snx_ser_write(struct tty_struct *, const unsigned char *, int);
> +#else
> +static int      snx_ser_write(struct tty_struct *, int, const unsigned char *, int);
> +#endif
> +static int      snx_ser_get_lsr_info(struct snx_ser_state *, unsigned int *);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
> +static int      snx_ser_tiocmget(struct tty_struct *);
> +static int      snx_ser_tiocmset(struct tty_struct *, unsigned int, unsigned int);
> +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +static int      snx_ser_tiocmget(struct tty_struct *, struct file *);
> +static int      snx_ser_tiocmset(struct tty_struct *, struct file *, unsigned int, unsigned int);
> +#else
> +static int      snx_ser_get_modem_info(struct snx_ser_state *, unsigned int *);
> +static int      snx_ser_set_modem_info(struct snx_ser_state *, unsigned int, unsigned int *);
> +#endif
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
> +static int      snx_ser_break_ctl(struct tty_struct *, int);
> +#else
> +static void     snx_ser_break_ctl(struct tty_struct *, int);
> +#endif
> +static int      snx_ser_wait_modem_status(struct snx_ser_state *, unsigned long);
> +static int      snx_ser_get_count(struct snx_ser_state *, struct serial_icounter_struct *);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
> +static int      snx_ser_ioctl(struct tty_struct *, unsigned int, unsigned long);
> +#else
> +static int      snx_ser_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
> +#endif
> +
> +static void     snx_ser_hangup(struct tty_struct *);
> +unsigned int    snx_ser_get_divisor(struct snx_ser_port *, unsigned int);
> +extern void     snx_ser_change_speed(struct snx_ser_state *, struct SNXTERMIOS *);
> +static void     snx_ser_set_termios(struct tty_struct *, struct SNXTERMIOS *);
> +
> +static void     snx_ser_update_timeout(struct snx_ser_port *, unsigned int, unsigned int);
> +static struct   snx_ser_state *snx_ser_get(struct snx_ser_driver *, int);
> +static int      snx_ser_block_til_ready(struct file *, struct snx_ser_state *);
> +static void     snx_ser_wait_until_sent(struct tty_struct *, int);
> +static int      snx_ser_open(struct tty_struct *, struct file *);
> +static void     snx_ser_close(struct tty_struct *, struct file *);
> +
> +
> +static void         sunix_ser_set_mctrl(struct snx_ser_port *, unsigned int);
> +static unsigned int sunix_ser_tx_empty(struct snx_ser_port *);
> +static unsigned int sunix_ser_get_mctrl(struct snx_ser_port *);
> +static void         sunix_ser_stop_tx(struct snx_ser_port *, unsigned int);
> +static void         sunix_ser_start_tx(struct snx_ser_port *, unsigned int);
> +static void         sunix_ser_stop_rx(struct snx_ser_port *);
> +static void         sunix_ser_enable_ms(struct snx_ser_port *);
> +static void         sunix_ser_break_ctl(struct snx_ser_port *, int);
> +static int          sunix_ser_startup(struct snx_ser_port *);
> +static void         sunix_ser_shutdown(struct snx_ser_port *);
> +static unsigned int sunix_ser_get_divisor(struct snx_ser_port *, unsigned int);
> +static void         sunix_ser_set_termios(struct snx_ser_port *, struct SNXTERMIOS *, struct SNXTERMIOS *);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
> +	static void sunix_ser_timeout(struct timer_list *t);
> +#else
> +	static void sunix_ser_timeout(unsigned long data);
> +#endif
> +
> +
> +static _INLINE_ void sunix_ser_receive_chars(struct sunix_sdc_uart_channel *, unsigned char *);
> +static _INLINE_ void sunix_ser_transmit_chars(struct sunix_sdc_uart_channel *);
> +static _INLINE_ void sunix_ser_check_modem_status(struct sunix_sdc_uart_channel *, unsigned char);
> +static _INLINE_ void sunix_ser_handle_port(struct sunix_sdc_uart_channel *, unsigned char);
> +
> +
> +static void     sunix_ser_release_io(struct snx_ser_port *);
> +static void     sunix_ser_request_io(struct snx_ser_port *);
> +static void     sunix_ser_configure_port(struct snx_ser_driver *, struct snx_ser_state *, struct snx_ser_port *);
> +static void     sunix_ser_unconfigure_port(struct snx_ser_driver *, struct snx_ser_state *);
> +static int      sunix_ser_add_one_port(struct snx_ser_driver *, struct snx_ser_port *);
> +static int      sunix_ser_remove_one_port(struct snx_ser_driver *, struct snx_ser_port *);
> +
> +
> +static unsigned char READ_UART_RX(struct sunix_sdc_uart_channel *);
> +static unsigned char READ_UART_IIR(struct sunix_sdc_uart_channel *);
> +static unsigned char READ_UART_LCR(struct sunix_sdc_uart_channel *);
> +static unsigned char READ_UART_LSR(struct sunix_sdc_uart_channel *);
> +static unsigned char READ_UART_MSR(struct sunix_sdc_uart_channel *);
> +static void WRITE_UART_TX(struct sunix_sdc_uart_channel *, unsigned char);
> +static void WRITE_UART_IER(struct sunix_sdc_uart_channel *, unsigned char);
> +static void WRITE_UART_FCR(struct sunix_sdc_uart_channel *, unsigned char);
> +static void WRITE_UART_LCR(struct sunix_sdc_uart_channel *, unsigned char);
> +static void WRITE_UART_MCR(struct sunix_sdc_uart_channel *, unsigned char);
> +static void WRITE_UART_DLL(struct sunix_sdc_uart_channel *, int);
> +static void WRITE_UART_DLM(struct sunix_sdc_uart_channel *, int);
> +
> +
> +static void snx_ser_insert_char(struct snx_ser_port *port, unsigned int status, unsigned int overrun, unsigned int ch, unsigned int flag)
> +{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
> +	struct snx_ser_info *info = port->info;
> +    struct tty_struct *tty = info->tty;
> +    struct snx_ser_state *state = NULL;
> +    struct tty_port *tport = NULL;
> +
> +
> +	state = tty->driver_data;
> +	tport = &state->tport;
> +#else
> +	struct tty_struct *tty = port->info->tty;
> +#endif
> +
> +	if ((status & port->ignore_status_mask & ~overrun) == 0)
> +	{
> +#if	(LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
> +		if (tty_insert_flip_char(tport, ch, flag) == 0)
> +		{
> +				++port->icount.buf_overrun;			
> +		}		
> +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
> +		if (tty_insert_flip_char(tty, ch, flag) == 0)
> +			++port->icount.buf_overrun;
> +#else
> +		tty_insert_flip_char(tty, ch, flag);	
> +#endif
> +    }
> +
> +
> +	if (status & ~port->ignore_status_mask & overrun)
> +	{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
> +		if (tty_insert_flip_char(tport, 0, TTY_OVERRUN) == 0)
> +		{
> +			++port->icount.buf_overrun;
> +		}		
> +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
> +		if (tty_insert_flip_char(tty, 0, TTY_OVERRUN) == 0)
> +			++port->icount.buf_overrun;
> +#else
> +		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
> +#endif
> +    }
> +}
> +
> +
> +static unsigned char READ_UART_RX(struct sunix_sdc_uart_channel *sp)
> +{
> +	unsigned char data;
> +
> +
> +	if (sp->port.iobase)
> +	{
> +		data = inb(sp->port.iobase + UART_RX);
> +		return data;
> +	}
> +	return 0;
> +}
> +
> +
> +static void WRITE_UART_TX(struct sunix_sdc_uart_channel *sp, unsigned char data)
> +{
> +	if (sp->port.iobase)
> +	{
> +		outb(data, sp->port.iobase + UART_TX);
> +	}
> +}
> +
> +
> +static void WRITE_UART_IER(struct sunix_sdc_uart_channel *sp, unsigned char data)
> +{
> +	if (sp->port.iobase)
> +	{
> +		outb(data, sp->port.iobase + UART_IER);
> +	}
> +}
> +
> +
> +static unsigned char READ_UART_IIR(struct sunix_sdc_uart_channel *sp)
> +{
> +	unsigned char data;
> +
> +
> +	if (sp->port.iobase)
> +	{
> +		data = inb(sp->port.iobase + UART_IIR);
> +		return data;
> +	}
> +	return 0;
> +}
> +
> +
> +static void WRITE_UART_FCR(struct sunix_sdc_uart_channel *sp, unsigned char data)
> +{
> +	if (sp->port.iobase)
> +	{
> +		outb(data, sp->port.iobase + UART_FCR);
> +	}
> +}
> +
> +
> +static unsigned char READ_UART_LCR(struct sunix_sdc_uart_channel *sp)
> +{
> +	unsigned char data;
> +
> +
> +	if (sp->port.iobase)
> +	{
> +		data = inb(sp->port.iobase + UART_LCR);
> +		return data;
> +	}
> +	return 0;
> +}
> +
> +
> +static void WRITE_UART_LCR(struct sunix_sdc_uart_channel *sp, unsigned char data)
> +{
> +	if (sp->port.iobase)
> +	{
> +		outb(data, sp->port.iobase + UART_LCR);
> +	}
> +}
> +
> +
> +static void WRITE_UART_MCR(struct sunix_sdc_uart_channel *sp, unsigned char data)
> +{
> +	if (sp->port.iobase)
> +	{
> +		outb(data, sp->port.iobase + UART_MCR);
> +	}
> +}
> +
> +
> +static unsigned char READ_UART_LSR(struct sunix_sdc_uart_channel *sp)
> +{
> +	unsigned char data;
> +
> +
> +	if (sp->port.iobase)
> +	{
> +		data = inb(sp->port.iobase + UART_LSR);
> +		return data;
> +	}
> +	return 0;
> +}
> +
> +
> +static unsigned char READ_UART_MSR(struct sunix_sdc_uart_channel *sp)
> +{
> +	unsigned char data;
> +
> +
> +	if (sp->port.iobase)
> +	{
> +		data = inb(sp->port.iobase + UART_MSR);
> +		return data;
> +	}
> +	return 0;
> +}
> +
> +
> +static void WRITE_UART_DLL(struct sunix_sdc_uart_channel *sp, int data)
> +{
> +    if (sp->port.iobase)
> +	{
> +		outb(data, sp->port.iobase + UART_DLL);
> +    }
> +}
> +
> +
> +static void WRITE_UART_DLM(struct sunix_sdc_uart_channel *sp, int data)
> +{
> +	if (sp->port.iobase)
> +	{
> +		outb(data, sp->port.iobase + UART_DLM);
> +	}
> +}
> +
> +
> +static _INLINE_ void snx_ser_handle_cts_change(struct snx_ser_port *port, unsigned int status)
> +{
> +	struct snx_ser_info *info = port->info;
> +	struct tty_struct *tty = info->tty;
> +
> +
> +	port->icount.cts++;
> +
> +	if (info->flags & SNX_UIF_CTS_FLOW)
> +	{
> +		if (tty->hw_stopped)
> +		{
> +			if (status)
> +			{
> +				tty->hw_stopped = 0;
> +				sunix_ser_start_tx(port, 0);
> +				snx_ser_write_wakeup(port);
> +			}
> +		}
> +		else
> +		{
> +			if (!status)
> +			{
> +				tty->hw_stopped = 1;
> +				sunix_ser_stop_tx(port, 0);
> +			}
> +		}
> +	}
> +}
> +
> +
> +static _INLINE_ void snx_ser_update_mctrl(struct snx_ser_port *port, unsigned int set, unsigned int clear)
> +{
> +	unsigned long flags;
> +	unsigned int old;
> +
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +
> +	old = port->mctrl;
> +	port->mctrl = (old & ~clear) | set;
> +
> +	if (old != port->mctrl)
> +	{
> +		sunix_ser_set_mctrl(port, port->mctrl);
> +	}
> +	spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +
> +#define snx_set_mctrl(port, set)		snx_ser_update_mctrl(port, set, 0)
> +#define snx_clear_mctrl(port, clear)	snx_ser_update_mctrl(port, 0, clear)
> +
> +
> +static void snx_ser_write_wakeup(struct snx_ser_port *port)
> +{
> +	struct snx_ser_info *info = port->info;
> +	tasklet_schedule(&info->tlet);
> +}
> +
> +
> +static void snx_ser_stop(struct tty_struct *tty)
> +{
> +	struct snx_ser_state *state = NULL;
> +	struct snx_ser_port *port = NULL;
> +	unsigned long flags;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return;
> +	}
> +
> +	state = tty->driver_data;
> +	port = state->port;
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +	sunix_ser_stop_tx(port, 1);
> +	spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +
> +static void __snx_ser_start(struct tty_struct *tty)
> +{
> +	struct snx_ser_state *state = tty->driver_data;
> +	struct snx_ser_port *port = state->port;
> +
> +
> +	if (!snx_ser_circ_empty(&state->info->xmit) && state->info->xmit.buf && !tty->stopped && !tty->hw_stopped)
> +	{
> +		sunix_ser_start_tx(port, 1);
> +	}
> +}
> +
> +
> +static void snx_ser_start(struct tty_struct *tty)
> +{
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return;
> +	}
> +
> +	__snx_ser_start(tty);
> +}
> +
> +
> +static void snx_ser_tasklet_action(unsigned long data)
> +{
> +	struct snx_ser_state *state = (struct snx_ser_state *)data;
> +	struct tty_struct *tty = NULL;
> +
> +
> +	tty = state->info->tty;
> +	if (tty)
> +	{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
> +		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc->ops->write_wakeup)
> +		{
> +			tty->ldisc->ops->write_wakeup(tty);
> +		}
> +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30))
> +		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.ops->write_wakeup)
> +		{
> +			tty->ldisc.ops->write_wakeup(tty);
> +		}
> +#else
> +		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
> +		{
> +			tty->ldisc.write_wakeup(tty);
> +		}
> +#endif
> +		wake_up_interruptible(&tty->write_wait);
> +    }
> +}
> +
> +
> +int snx_ser_startup(struct snx_ser_state *state, int init_hw)
> +{
> +	struct snx_ser_info *info = state->info;
> +	struct snx_ser_port *port = state->port;
> +	unsigned long page;
> +	int retval = 0;
> +
> +
> +	if (info->flags & SNX_UIF_INITIALIZED)
> +	{
> +		return 0;
> +	}
> +
> +
> +	if (info->tty)
> +	{
> +		set_bit(TTY_IO_ERROR, &info->tty->flags);
> +    }
> +
> +
> +	if (port->type == PORT_UNKNOWN)
> +	{
> +		return 0;
> +	}
> +
> +
> +	if (!info->xmit.buf)
> +	{
> +		page = get_zeroed_page(GFP_KERNEL);
> +
> +		if (!page)
> +		{
> +			return -ENOMEM;
> +		}
> +
> +		info->xmit.buf = (unsigned char *) page;
> +
> +		info->tmpbuf = info->xmit.buf + SNX_UART_XMIT_SIZE;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
> +		sema_init(&info->tmpbuf_sem, 1);
> +#else
> +		init_MUTEX(&info->tmpbuf_sem);
> +#endif
> +		snx_ser_circ_clear(&info->xmit);
> +    }
> +
> +	retval = sunix_ser_startup(port);
> +
> +	if (retval == 0)
> +	{
> +		if (init_hw)
> +		{
> +			snx_ser_change_speed(state, NULL);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +			if (info->tty->termios.c_cflag & CBAUD)
> +			{
> +				snx_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
> +			}
> +#else
> +			if (info->tty->termios->c_cflag & CBAUD)
> +			{
> +				snx_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
> +			}
> +#endif
> +		}
> +
> +
> +		info->flags |= SNX_UIF_INITIALIZED;
> +
> +		clear_bit(TTY_IO_ERROR, &info->tty->flags);
> +	}
> +
> +
> +    if (retval && capable(CAP_SYS_ADMIN))
> +	{
> +		retval = 0;
> +	}
> +
> +	return retval;
> +}
> +
> +
> +static void snx_ser_shutdown(struct snx_ser_state *state)
> +{
> +	struct snx_ser_info *info = state->info;
> +	struct snx_ser_port *port = state->port;
> +
> +
> +	if (!(info->flags & SNX_UIF_INITIALIZED))
> +	{
> +		return;
> +	}
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +    if (!info->tty || (info->tty->termios.c_cflag & HUPCL))
> +	{
> +		snx_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
> +	}
> +#else
> +	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
> +	{
> +		snx_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
> +	}
> +#endif
> +
> +	wake_up_interruptible(&info->delta_msr_wait);
> +
> +	sunix_ser_shutdown(port);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +	synchronize_irq(port->irq);
> +#endif
> +	if (info->xmit.buf)
> +	{
> +		free_page((unsigned long)info->xmit.buf);
> +		info->xmit.buf = NULL;
> +		info->tmpbuf = NULL;
> +	}
> +
> +	tasklet_kill(&info->tlet);
> +
> +	if (info->tty)
> +	{
> +		set_bit(TTY_IO_ERROR, &info->tty->flags);
> +	}
> +
> +	info->flags &= ~SNX_UIF_INITIALIZED;
> +}
> +
> +
> +static _INLINE_ void __snx_ser_put_char(struct snx_ser_port *port, struct circ_buf *circ, unsigned char c)
> +{
> +	unsigned long flags;
> +
> +
> +	if (!circ->buf)
> +	{
> +		return;
> +	}
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +
> +	if (snx_ser_circ_chars_free(circ) != 0)
> +	{
> +		circ->buf[circ->head] = c;
> +		circ->head = (circ->head + 1) & (SNX_UART_XMIT_SIZE - 1);
> +	}
> +	spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26))
> +static int  snx_ser_put_char(struct tty_struct *tty, unsigned char ch)
> +#else
> +static void snx_ser_put_char(struct tty_struct *tty, unsigned char ch)
> +#endif
> +{
> +	struct snx_ser_state *state = NULL;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26))
> +		return 0;
> +#else
> +		return;
> +#endif
> +	}
> +
> +	state = tty->driver_data;
> +	__snx_ser_put_char(state->port, &state->info->xmit, ch);
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26))
> +	return 0;
> +#endif
> +}
> +
> +
> +static void snx_ser_flush_chars(struct tty_struct *tty)
> +{
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return;
> +	}
> +
> +	snx_ser_start(tty);
> +}
> +
> +
> +static int snx_ser_chars_in_buffer(struct tty_struct *tty)
> +{
> +	struct snx_ser_state *state = NULL;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return 0;
> +	}
> +
> +	state = tty->driver_data;
> +
> +	return snx_ser_circ_chars_pending(&state->info->xmit);
> +}
> +
> +
> +static void snx_ser_flush_buffer(struct tty_struct *tty)
> +{
> +	struct snx_ser_state *state = NULL;
> +	struct snx_ser_port *port = NULL;
> +	unsigned long flags;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return;
> +	}
> +
> +	state = tty->driver_data;
> +	port = state->port;
> +
> +	if (!state || !state->info)
> +	{
> +		return;
> +	}
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +	snx_ser_circ_clear(&state->info->xmit);
> +	spin_unlock_irqrestore(&port->lock, flags);
> +
> +	wake_up_interruptible(&tty->write_wait);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
> +	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc->ops->write_wakeup)
> +	{
> +		(tty->ldisc->ops->write_wakeup)(tty);
> +	}
> +
> +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30))
> +
> +	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.ops->write_wakeup)
> +	{
> +		(tty->ldisc.ops->write_wakeup)(tty);
> +	}
> +
> +#else
> +	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
> +	{
> +		(tty->ldisc.write_wakeup)(tty);
> +	}
> +#endif
> +}
> +
> +
> +static void snx_ser_send_xchar(struct tty_struct *tty, char ch)
> +{
> +	struct snx_ser_state *state = NULL;
> +	struct snx_ser_port *port = NULL;
> +	unsigned long flags;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return;
> +	}
> +
> +	state = tty->driver_data;
> +	port = state->port;
> +	port->x_char = ch;
> +
> +	if (ch)
> +	{
> +		spin_lock_irqsave(&port->lock, flags);
> +		sunix_ser_start_tx(port, 0);
> +		spin_unlock_irqrestore(&port->lock, flags);
> +	}
> +}
> +
> +
> +static void snx_ser_throttle(struct tty_struct *tty)
> +{
> +	struct snx_ser_state *state = NULL;
> +	struct snx_ser_port *port = NULL;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return;
> +	}
> +
> +	state = tty->driver_data;
> +	port = state->port;
> +
> +	port->ldisc_stop_rx = 1;
> +
> +	if (I_IXOFF(tty))
> +	{
> +		snx_ser_send_xchar(tty, STOP_CHAR(tty));
> +	}
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	if (tty->termios.c_cflag & CRTSCTS)
> +	{
> +		snx_clear_mctrl(state->port, TIOCM_RTS);
> +	}
> +#else
> +	if (tty->termios->c_cflag & CRTSCTS)
> +	{
> +		snx_clear_mctrl(state->port, TIOCM_RTS);
> +	}
> +#endif
> +}
> +
> +
> +static void snx_ser_unthrottle(struct tty_struct *tty)
> +{
> +	struct snx_ser_state *state = NULL;
> +	struct snx_ser_port *port = NULL;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return;
> +	}
> +
> +	state = tty->driver_data;
> +	port = state->port;
> +
> +	port->ldisc_stop_rx = 0;
> +
> +	if (I_IXOFF(tty))
> +	{
> +		if (port->x_char)
> +		{
> +			port->x_char = 0;
> +		}
> +		else
> +		{
> +			snx_ser_send_xchar(tty, START_CHAR(tty));
> +		}
> +	}
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	if (tty->termios.c_cflag & CRTSCTS)
> +	{
> +		snx_set_mctrl(port, TIOCM_RTS);
> +	}
> +#else
> +	if (tty->termios->c_cflag & CRTSCTS)
> +	{
> +		snx_set_mctrl(port, TIOCM_RTS);
> +	}
> +#endif
> +}
> +
> +
> +static int snx_ser_get_info(struct snx_ser_state *state, struct serial_struct *retinfo)
> +{
> +	struct snx_ser_port *port = state->port;
> +	struct serial_struct tmp;
> +
> +
> +	memset(&tmp, 0, sizeof(tmp));
> +	tmp.type            = port->type;
> +	tmp.line            = port->line;
> +	tmp.port            = port->iobase;
> +
> +    if (SNX_HIGH_BITS_OFFSET)
> +	{
> +		tmp.port_high = (long) port->iobase >> SNX_HIGH_BITS_OFFSET;
> +	}
> +
> +	tmp.irq             = port->irq;
> +	tmp.flags           = port->flags;
> +	tmp.xmit_fifo_size  = port->fifosize;
> +	tmp.baud_base       = port->uartclk / 16;
> +	tmp.close_delay     = state->close_delay;
> +	tmp.closing_wait    = state->closing_wait;
> +
> +	tmp.custom_divisor  = port->custom_divisor;
> +	tmp.io_type         = port->iotype;
> +
> +	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
> +	{
> +		return -EFAULT;
> +	}
> +	return 0;
> +}
> +
> +
> +static int snx_ser_set_info(struct snx_ser_state *state, struct serial_struct *newinfo)
> +{
> +	struct serial_struct new_serial;
> +	struct snx_ser_port *port = state->port;
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
> +	struct tty_port		*tport = &state->tport;
> +#endif
> +	unsigned long new_port;
> +	unsigned int change_irq;
> +	unsigned int change_port;
> +	unsigned int old_custom_divisor;
> +	unsigned int closing_wait;
> +	unsigned int close_delay;
> +	unsigned int old_flags;
> +	unsigned int new_flags;
> +	int retval = 0;
> +
> +
> +	if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
> +	{
> +		return -EFAULT;
> +	}
> +
> +	new_port = new_serial.port;
> +
> +	if (SNX_HIGH_BITS_OFFSET)
> +	{
> +		new_port += (unsigned long) new_serial.port_high << SNX_HIGH_BITS_OFFSET;
> +    }
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +	new_serial.irq = irq_canonicalize(new_serial.irq);
> +#endif
> +
> +	close_delay = new_serial.close_delay;
> +	closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?	SNX_USF_CLOSING_WAIT_NONE : new_serial.closing_wait;
> +
> +	down(&state->sem);
> +
> +	change_irq  = new_serial.irq != port->irq;
> +
> +	change_port =   new_port != port->iobase ||
> +					new_serial.io_type != port->iotype ||
> +					new_serial.type != port->type;
> +
> +	old_flags = port->flags;
> +	new_flags = new_serial.flags;
> +	old_custom_divisor = port->custom_divisor;
> +
> +	if (!capable(CAP_SYS_ADMIN))
> +	{
> +		retval = -EPERM;
> +		if (change_irq ||
> +			change_port ||
> +			(new_serial.baud_base != port->uartclk / 16) ||
> +			(close_delay != state->close_delay) ||
> +			(closing_wait != state->closing_wait) ||
> +			(new_serial.xmit_fifo_size != port->fifosize) ||
> +			(((new_flags ^ old_flags) & ~SNX_UPF_USR_MASK) != 0))
> +		{
> +			goto exit;
> +		}
> +
> +		port->flags = ((port->flags & ~SNX_UPF_USR_MASK) | (new_flags & SNX_UPF_USR_MASK));
> +		port->custom_divisor = new_serial.custom_divisor;
> +		goto check_and_exit;
> +	}
> +
> +	if (change_port || change_irq)
> +	{
> +		retval = -EBUSY;
> +
> +		if (sunix_ser_users(state) > 1)
> +		{
> +			goto exit;
> +		}
> +
> +		snx_ser_shutdown(state);
> +	}
> +
> +	if (change_port)
> +	{
> +		unsigned int old_type;
> +		old_type = port->type;
> +
> +		if (old_type != PORT_UNKNOWN)
> +		{
> +			sunix_ser_release_io(port);
> +		}
> +
> +		port->iobase = new_port;
> +		port->type = new_serial.type;
> +		port->iotype = new_serial.io_type;
> +
> +		retval = 0;
> +	}
> +
> +	port->irq              = new_serial.irq;
> +	port->uartclk          = new_serial.baud_base * 16;
> +	port->flags            = ((port->flags & ~SNX_UPF_CHANGE_MASK) | (new_flags & SNX_UPF_CHANGE_MASK));
> +	port->custom_divisor   = new_serial.custom_divisor;
> +	state->close_delay     = close_delay;
> +	state->closing_wait    = closing_wait;
> +	port->fifosize         = new_serial.xmit_fifo_size;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
> +	tport->low_latency = (port->flags & SNX_UPF_LOW_LATENCY) ? 1 : 0;
> +#else
> +	if (state->info->tty)
> +	{
> +		state->info->tty->low_latency = (port->flags & SNX_UPF_LOW_LATENCY) ? 1 : 0;
> +	}
> +#endif
> +
> +
> +check_and_exit:
> +	retval = 0;
> +	if (port->type == PORT_UNKNOWN)
> +	{
> +		goto exit;
> +	}
> +
> +	if (state->info->flags & SNX_UIF_INITIALIZED)
> +	{
> +		if (((old_flags ^ port->flags) & SNX_UPF_SPD_MASK) || old_custom_divisor != port->custom_divisor)
> +		{
> +			if (port->flags & SNX_UPF_SPD_MASK)
> +			{
> +				printk("SUNIX: %s sets custom speed on ttySDC%d. This is deprecated.\n", current->comm, port->line);
> +			}
> +			snx_ser_change_speed(state, NULL);
> +		}
> +	}
> +	else
> +	{
> +		retval = snx_ser_startup(state, 1);
> +	}
> +exit:
> +
> +	up(&state->sem);
> +
> +	return retval;
> +}
> +
> +
> +static int snx_ser_write_room(struct tty_struct *tty)
> +{
> +	struct snx_ser_state *state = NULL;
> +	int line = SNX_SER_DEVNUM(tty);
> +	int status = 0;
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return 0;
> +	}
> +
> +    state = tty->driver_data;
> +
> +    status = snx_ser_circ_chars_free(&state->info->xmit);
> +
> +    return status;
> +}
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
> +static int snx_ser_write(struct tty_struct *tty, const unsigned char *buf, int count)
> +#else
> +static int snx_ser_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
> +#endif
> +{
> +	struct snx_ser_state *state = tty->driver_data;
> +	struct circ_buf *circ = NULL;
> +	struct snx_ser_port *port = state->port;
> +	unsigned long flags;
> +	int c;
> +	int ret = 0;
> +
> +
> +	if (!state || !state->info)
> +	{
> +		return -EL3HLT;
> +	}
> +
> +	circ = &state->info->xmit;
> +
> +	if (!circ->buf)
> +	{
> +		return 0;
> +	}
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +
> +	while (1)
> +	{
> +		c = CIRC_SPACE_TO_END(circ->head, circ->tail, SNX_UART_XMIT_SIZE);
> +		if (count < c)
> +		{
> +			c = count;
> +		}
> +
> +		if (c <= 0)
> +		{
> +			break;
> +		}
> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9))
> +	memcpy(circ->buf + circ->head, buf, c);
> +#else
> +		if (from_user)
> +		{
> +			if (copy_from_user((circ->buf + circ->head), buf, c) == c)
> +			{
> +				ret = -EFAULT;
> +				break;
> +			}
> +		}
> +		else
> +		{
> +			memcpy(circ->buf + circ->head, buf, c);
> +		}
> +#endif
> +
> +
> +		circ->head = (circ->head + c) & (SNX_UART_XMIT_SIZE - 1);
> +		buf += c;
> +		count -= c;
> +		ret += c;
> +    }
> +
> +	spin_unlock_irqrestore(&port->lock, flags);
> +
> +	snx_ser_start(tty);
> +
> +	return ret;
> +}
> +
> +
> +static int snx_ser_get_lsr_info(struct snx_ser_state *state, unsigned int *value)
> +{
> +	struct snx_ser_port *port = state->port;
> +	unsigned int result = 0;
> +
> +
> +	result = sunix_ser_tx_empty(port);
> +
> +	if ((port->x_char) ||
> +		((snx_ser_circ_chars_pending(&state->info->xmit) > 0) &&
> +		!state->info->tty->stopped && !state->info->tty->hw_stopped))
> +	{
> +		result &= ~TIOCSER_TEMT;
> +	}
> +
> +
> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 18))
> +	if (copy_to_user(value, &result, sizeof(int)))
> +	{
> +		return -EFAULT;
> +	}
> +
> +	return 0;
> +#else
> +	return put_user(result, value);
> +#endif
> +}
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
> +static int snx_ser_tiocmget(struct tty_struct *tty)
> +{
> +	struct snx_ser_state *state = NULL;
> +	struct snx_ser_port *port = NULL;
> +	int result = -EIO;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return 0;
> +	}
> +
> +	state = tty->driver_data;
> +	port = state->port;
> +
> +	down(&state->sem);
> +
> +	if (!(tty->flags & (1 << TTY_IO_ERROR)))
> +	{
> +		result = port->mctrl;
> +		result |= sunix_ser_get_mctrl(port);
> +	}
> +
> +	up(&state->sem);
> +
> +	return result;
> +}
> +
> +
> +static int snx_ser_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
> +{
> +	struct snx_ser_state *state = NULL;
> +	struct snx_ser_port *port = NULL;
> +	int ret = -EIO;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return 0;
> +	}
> +
> +	state = tty->driver_data;
> +	port = state->port;
> +
> +	down(&state->sem);
> +
> +	if (!(tty->flags & (1 << TTY_IO_ERROR)))
> +	{
> +		snx_ser_update_mctrl(port, set, clear);
> +		ret = 0;
> +	}
> +
> +	up(&state->sem);
> +
> +	return ret;
> +}
> +
> +
> +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +static int snx_ser_tiocmget(struct tty_struct *tty, struct file *file)
> +{
> +	struct snx_ser_state *state = NULL;
> +	struct snx_ser_port *port = NULL;
> +	int result = -EIO;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return 0;
> +	}
> +
> +	state = tty->driver_data;
> +	port = state->port;
> +
> +	down(&state->sem);
> +
> +	if ((!file || !tty_hung_up_p(file)) && !(tty->flags & (1 << TTY_IO_ERROR)))
> +	{
> +		result = port->mctrl;
> +		result |= sunix_ser_get_mctrl(port);
> +	}
> +
> +	up(&state->sem);
> +
> +	return result;
> +}
> +
> +
> +static int snx_ser_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear)
> +{
> +	struct snx_ser_state *state = NULL;
> +	struct snx_ser_port *port = NULL;
> +	int ret = -EIO;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return 0;
> +	}
> +
> +	state = tty->driver_data;
> +	port = state->port;
> +
> +	down(&state->sem);
> +
> +	if ((!file || !tty_hung_up_p(file)) && !(tty->flags & (1 << TTY_IO_ERROR)))
> +	{
> +		snx_ser_update_mctrl(port, set, clear);
> +		ret = 0;
> +	}
> +
> +	up(&state->sem);
> +
> +	return ret;
> +}
> +
> +
> +#else
> +static int snx_ser_get_modem_info(struct snx_ser_state *state, unsigned int *value)
> +{
> +	struct snx_ser_port *port = NULL;
> +	int line;
> +	unsigned int result;
> +
> +
> +	if (!state)
> +	{
> +		return -EIO;
> +	}
> +
> +	port = state->port;
> +
> +	if (!port)
> +	{
> +		return -EIO;
> +	}
> +
> +	line = port->line;
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return -EIO;
> +	}
> +
> +	result = port->mctrl;
> +	result |= sunix_ser_get_mctrl(port);
> +
> +	put_user(result, (unsigned long *)value);
> +
> +	return 0;
> +}
> +
> +
> +static int snx_ser_set_modem_info(struct snx_ser_state *state, unsigned int cmd, unsigned int *value)
> +{
> +	struct snx_ser_port *port = NULL;
> +	int line;
> +	unsigned int set = 0;
> +	unsigned int clr = 0;
> +	unsigned int arg;
> +
> +
> +	if (!state)
> +	{
> +		return -EIO;
> +	}
> +
> +	port = state->port;
> +
> +	if (!port)
> +	{
> +		return -EIO;
> +	}
> +
> +	line = port->line;
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return -EIO;
> +	}
> +
> +	get_user(arg, (unsigned long *)value);
> +
> +	switch (cmd)
> +	{
> +		case TIOCMBIS:
> +		{
> +			if (arg & TIOCM_RTS)
> +			{
> +				set |= TIOCM_RTS;
> +			}
> +
> +			if (arg & TIOCM_DTR)
> +			{
> +				set |= TIOCM_DTR;
> +			}
> +
> +			if (arg & TIOCM_LOOP)
> +			{
> +				set |= TIOCM_LOOP;
> +			}
> +			break;
> +		}
> +
> +		case TIOCMBIC:
> +		{
> +			if (arg & TIOCM_RTS)
> +			{
> +				clr |= TIOCM_RTS;
> +			}
> +
> +			if (arg & TIOCM_DTR)
> +			{
> +				clr |= TIOCM_DTR;
> +			}
> +
> +			if (arg & TIOCM_LOOP)
> +			{
> +				clr |= TIOCM_LOOP;
> +			}
> +			break;
> +		}
> +
> +		case TIOCMSET:
> +		{
> +			if (arg & TIOCM_RTS)
> +			{
> +				set |= TIOCM_RTS;
> +			}
> +			else
> +			{
> +				clr |= TIOCM_RTS;
> +			}
> +
> +			if (arg & TIOCM_DTR)
> +			{
> +				set |= TIOCM_DTR;
> +			}
> +			else
> +			{
> +				clr |= TIOCM_DTR;
> +			}
> +
> +			if (arg & TIOCM_LOOP)
> +			{
> +				set |= TIOCM_LOOP;
> +			}
> +			else
> +			{
> +				clr |= TIOCM_LOOP;
> +			}
> +			break;
> +		}
> +
> +		default:
> +		{
> +			return -EINVAL;
> +		}
> +	}
> +
> +	snx_ser_update_mctrl(port, set, clr);
> +
> +	return 0;
> +}
> +#endif
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
> +static int  snx_ser_break_ctl(struct tty_struct *tty, int break_state)
> +#else
> +static void snx_ser_break_ctl(struct tty_struct *tty, int break_state)
> +#endif
> +{
> +	struct snx_ser_state *state = NULL;
> +	struct snx_ser_port *port = NULL;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
> +		return 0;
> +#else
> +		return;
> +#endif
> +	}
> +
> +	state = tty->driver_data;
> +	port = state->port;
> +
> +	down(&state->sem);
> +
> +	if (port->type != PORT_UNKNOWN)
> +	{
> +		sunix_ser_break_ctl(port, break_state);
> +	}
> +
> +	up(&state->sem);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
> +	return 0;
> +#endif
> +}
> +
> +
> +static int snx_ser_wait_modem_status(struct snx_ser_state *state, unsigned long arg)
> +{
> +	struct snx_ser_port *port = state->port;
> +	DECLARE_WAITQUEUE(wait, current);
> +	struct snx_ser_icount cprev;
> +	struct snx_ser_icount cnow;
> +	int ret = 0;
> +
> +
> +	spin_lock_irq(&port->lock);
> +	memcpy(&cprev, &port->icount, sizeof(struct snx_ser_icount));
> +
> +	sunix_ser_enable_ms(port);
> +
> +	spin_unlock_irq(&port->lock);
> +
> +	add_wait_queue(&state->info->delta_msr_wait, &wait);
> +
> +	for (;;)
> +	{
> +		spin_lock_irq(&port->lock);
> +		memcpy(&cnow, &port->icount, sizeof(struct snx_ser_icount));
> +		spin_unlock_irq(&port->lock);
> +
> +		set_current_state(TASK_INTERRUPTIBLE);
> +
> +		if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
> +			((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
> +			((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
> +			((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)))
> +		{
> +			ret = 0;
> +			break;
> +		}
> +
> +		schedule();
> +
> +		if (signal_pending(current))
> +		{
> +			ret = -ERESTARTSYS;
> +			break;
> +		}
> +
> +		cprev = cnow;
> +	}
> +
> +	current->state = TASK_RUNNING;
> +	remove_wait_queue(&state->info->delta_msr_wait, &wait);
> +
> +	return ret;
> +}
> +
> +
> +static int snx_ser_get_count(struct snx_ser_state *state, struct serial_icounter_struct *icnt)
> +{
> +    struct serial_icounter_struct icount;
> +    struct snx_ser_icount cnow;
> +    struct snx_ser_port *port = state->port;
> +
> +
> +    spin_lock_irq(&port->lock);
> +    memcpy(&cnow, &port->icount, sizeof(struct snx_ser_icount));
> +    spin_unlock_irq(&port->lock);
> +
> +    icount.cts         = cnow.cts;
> +    icount.dsr         = cnow.dsr;
> +    icount.rng         = cnow.rng;
> +    icount.dcd         = cnow.dcd;
> +    icount.rx          = cnow.rx;
> +    icount.tx          = cnow.tx;
> +    icount.frame       = cnow.frame;
> +    icount.overrun     = cnow.overrun;
> +    icount.parity      = cnow.parity;
> +    icount.brk         = cnow.brk;
> +    icount.buf_overrun = cnow.buf_overrun;
> +
> +    return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
> +}
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
> +static int snx_ser_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
> +#else
> +static int snx_ser_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg)
> +#endif
> +{
> +	struct snx_ser_state *state = NULL;
> +	int ret = -ENOIOCTLCMD;
> +	int line = SNX_SER_DEVNUM(tty);
> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
> +	int status = 0;
> +#endif
> +
> +
> +	if (line < SUNIX_SDC_UART_MAX)
> +	{
> +		state = tty->driver_data;
> +	}
> +
> +
> +	switch (cmd)
> +	{
> +		case TIOCGSERIAL:
> +		{
> +			if (line < SUNIX_SDC_UART_MAX)
> +			{
> +				ret = snx_ser_get_info(state, (struct serial_struct *)arg);
> +			}
> +			break;
> +		}
> +
> +
> +		case TIOCSSERIAL:
> +		{
> +			if (line < SUNIX_SDC_UART_MAX)
> +			{
> +				state->port->setserial_flag = SNX_SER_BAUD_SETSERIAL;
> +				ret = snx_ser_set_info(state, (struct serial_struct *)arg);
> +			}
> +			break;
> +		}
> +
> +
> +		case TCSETS:
> +		{
> +			if (line < SUNIX_SDC_UART_MAX)
> +			{
> +				state->port->flags &= ~(SNX_UPF_SPD_HI | SNX_UPF_SPD_VHI | SNX_UPF_SPD_SHI | SNX_UPF_SPD_WARP);
> +				state->port->setserial_flag = SNX_SER_BAUD_NOTSETSER;
> +				snx_ser_update_termios(state);
> +			}
> +			break;
> +		}
> +
> +
> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
> +		case TIOCMGET:
> +		{
> +			if (line < SUNIX_SDC_UART_MAX)
> +			{
> +				ret = verify_area(VERIFY_WRITE, (void *)arg,	sizeof(unsigned int));
> +
> +				if (ret)
> +				{
> +					return ret;
> +				}
> +
> +				status = snx_ser_get_modem_info(state, (unsigned int *)arg);
> +				return status;
> +			}
> +			break;
> +		}
> +
> +
> +		case TIOCMBIS:
> +		case TIOCMBIC:
> +		case TIOCMSET:
> +		{
> +			if (line < SUNIX_SDC_UART_MAX)
> +			{
> +				status = snx_ser_set_modem_info(state, cmd, (unsigned int *)arg);
> +				return status;
> +			}
> +			break;
> +		}
> +#endif
> +
> +
> +		case TIOCSERGWILD:
> +		case TIOCSERSWILD:
> +		{
> +			if (line < SUNIX_SDC_UART_MAX)
> +			{
> +				ret = 0;
> +			}
> +			break;
> +		}
> +
> +		case SNX_SDC_UART_GET_INFO:
> +		{
> +			if (line < SUNIX_SDC_UART_MAX)
> +			{
> +				struct snx_ser_port *port = NULL;
> +				struct snx_sdc_uart_info info;
> +
> +				port = state->port;
> +				if (port != NULL)
> +				{
> +					memset(&info, 0, sizeof(struct snx_sdc_uart_info));
> +
> +					memcpy(info.model_name, port->model_name, sizeof(port->model_name));
> +					info.bus_number = port->bus_number;
> +					info.dev_number = port->dev_number;
> +					info.line = port->line;
> +					info.iobase = port->iobase;
> +					info.irq = port->irq;
> +
> +					info.version = port->cib_info.version;
> +					info.tx_fifo_size = port->cib_info.uart_tx_fifo_size;
> +					info.rx_fifo_size = port->cib_info.uart_rx_fifo_size;
> +					info.significand_of_clock = port->cib_info.uart_significand_of_clock;
> +					info.exponent_of_clock = port->cib_info.uart_exponent_of_clock;
> +					info.RS232_cap = port->cib_info.uart_RS232_cap;
> +					info.RS422_cap = port->cib_info.uart_RS422_cap;
> +					info.RS485_cap = port->cib_info.uart_RS485_cap;
> +					info.AHDC_cap = port->cib_info.uart_AHDC_cap;
> +					info.CS_cap = port->cib_info.uart_CS_cap;
> +					info.auto_RS422485_cap = port->cib_info.uart_auto_RS422485_cap;
> +					info.RS422_termination_cap = port->cib_info.uart_RS422_termination_cap;
> +					info.RS485_termination_cap = port->cib_info.uart_RS485_termination_cap;
> +					info.RI_5V_cap = port->cib_info.uart_RI_5V_cap;
> +					info.RI_12V_cap = port->cib_info.uart_RI_12V_cap;
> +					info.DCD_5V_cap = port->cib_info.uart_DCD_5V_cap;
> +					info.DCD_12V_cap = port->cib_info.uart_DCD_12V_cap;
> +
> +					if (copy_to_user((void *)arg, &info, sizeof(struct snx_sdc_uart_info)))
> +					{
> +						ret = -EFAULT;
> +					}
> +					else
> +					{
> +						ret = 0;
> +					}
> +				}
> +			}
> +			break;
> +		}
> +
> +		case SNX_SDC_UART_GET_ADDITIONAL_REG_0E:
> +		{
> +			if (line < SUNIX_SDC_UART_MAX)
> +			{
> +				struct snx_ser_port *port = NULL;
> +				unsigned char data;
> +
> +				port = state->port;
> +				if (port != NULL)
> +				{
> +					data = 	inb(port->iobase + 0x0e);
> +					if (copy_to_user((void *)arg, &data, sizeof(unsigned char)))
> +					{
> +						ret = -EFAULT;
> +					}
> +					else
> +					{
> +						ret = 0;
> +					}
> +				}
> +			}
> +
> +			break;
> +		}
> +
> +		case SNX_SDC_UART_SET_ADDITIONAL_REG_0E:
> +		{
> +			if (line < SUNIX_SDC_UART_MAX)
> +			{
> +				struct snx_ser_port *port = NULL;
> +				unsigned char data = 0x00;
> +
> +				port = state->port;
> +				if (port != NULL)
> +				{
> +					if (copy_from_user(&data, (void *)arg, sizeof(unsigned char)))
> +					{
> +						ret = -EFAULT;
> +					}
> +					else
> +					{
> +						outb(data, port->iobase + 0x0e);
> +						ret = 0;
> +					}
> +				}
> +			}
> +
> +			break;
> +		}
> +
> +    }
> +
> +    if (ret != -ENOIOCTLCMD)
> +	{
> +		goto out;
> +    }
> +
> +    if (tty->flags & (1 << TTY_IO_ERROR))
> +	{
> +		ret = -EIO;
> +		goto out;
> +	}
> +
> +	switch (cmd)
> +	{
> +		case TIOCMIWAIT:
> +			if (line < SUNIX_SDC_UART_MAX)
> +			{
> +				ret = snx_ser_wait_modem_status(state, arg);
> +			}
> +			break;
> +
> +		case TIOCGICOUNT:
> +			if (line < SUNIX_SDC_UART_MAX)
> +			{
> +				ret = snx_ser_get_count(state, (struct serial_icounter_struct *)arg);
> +			}
> +			break;
> +	}
> +
> +
> +	if (ret != -ENOIOCTLCMD)
> +	{
> +		goto out;
> +	}
> +
> +
> +    if (line < SUNIX_SDC_UART_MAX)
> +	{
> +		down(&state->sem);
> +
> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
> +		if (tty_hung_up_p(filp))
> +		{
> +			ret = -EIO;
> +			goto out_up;
> +		}
> +#endif
> +
> +		switch (cmd)
> +		{
> +			case TIOCSERGETLSR:
> +				ret = snx_ser_get_lsr_info(state, (unsigned int *)arg);
> +				break;
> +
> +
> +			default:
> +				break;
> +		}
> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
> +out_up:
> +#endif
> +		up(&state->sem);
> +	}
> +
> +out:
> +	return ret;
> +}
> +
> +
> +static void snx_ser_hangup(struct tty_struct *tty)
> +{
> +	struct snx_ser_state *state = NULL;
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	struct tty_port *tport = &state->tport;
> +#endif
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return;
> +	}
> +
> +	state = tty->driver_data;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	tport = &state->tport;
> +#endif
> +
> +	down(&state->sem);
> +
> +	if (state->info && state->info->flags & SNX_UIF_NORMAL_ACTIVE)
> +	{
> +		snx_ser_flush_buffer(tty);
> +		snx_ser_shutdown(state);
> +		state->count = 0;
> +		state->info->flags &= ~SNX_UIF_NORMAL_ACTIVE;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +		tty_port_tty_set(tport, NULL);
> +#endif
> +
> +		state->info->tty = NULL;
> +		wake_up_interruptible(&state->info->open_wait);
> +		wake_up_interruptible(&state->info->delta_msr_wait);
> +	}
> +
> +	up(&state->sem);
> +}
> +
> +
> +unsigned int snx_ser_get_divisor(struct snx_ser_port *port, unsigned int baud)
> +{
> +	unsigned int quot;
> +
> +
> +	if (baud == 38400 && (port->flags & SNX_UPF_SPD_MASK) == SNX_UPF_SPD_CUST)
> +	{
> +		quot = port->custom_divisor;
> +	}
> +	else
> +	{
> +		quot = port->uartclk / (16 * baud);
> +	}
> +
> +	return quot;
> +}
> +
> +
> +unsigned int snx_ser_get_baud_rate(struct snx_ser_port *port, struct SNXTERMIOS *termios, struct SNXTERMIOS *old, unsigned int min, unsigned int max)
> +{
> +	unsigned int try;
> +	unsigned int baud;
> +	unsigned int altbaud = 0;
> +	unsigned int flags = port->flags & SNX_UPF_SPD_MASK;
> +
> +
> +	for (try = 0; try < 2; try++)
> +	{
> +		if ((port->setserial_flag == SNX_SER_BAUD_SETSERIAL) || (port->flags & SNX_UPF_SPD_MASK))
> +		{
> +			altbaud = 38400;
> +
> +			if (flags == SNX_UPF_SPD_HI)
> +			{
> +				altbaud = 57600;
> +			}
> +
> +			if (flags == SNX_UPF_SPD_VHI)
> +			{
> +				altbaud = 115200;
> +			}
> +
> +			if (flags == SNX_UPF_SPD_SHI)
> +			{
> +				altbaud = 230400;
> +			}
> +
> +			if (flags == SNX_UPF_SPD_WARP)
> +			{
> +				altbaud = 460800;
> +			}
> +
> +			baud = altbaud;
> +		}
> +		else
> +		{
> +			switch (termios->c_cflag & (CBAUD | CBAUDEX))
> +			{
> +				case B921600:
> +					baud = 921600;
> +					break;
> +
> +				case B460800:
> +					baud = 460800;
> +					break;
> +
> +				case B230400:
> +					baud = 230400;
> +					break;
> +
> +				case B115200:
> +					baud = 115200;
> +					break;
> +
> +				case B57600:
> +					baud = 57600;
> +					break;
> +
> +				case B38400:
> +					baud = 38400;
> +					break;
> +
> +				case B19200:
> +					baud = 19200;
> +					break;
> +
> +				case B9600:
> +					baud = 9600;
> +					break;
> +
> +				case B4800:
> +					baud = 4800;
> +					break;
> +
> +				case B2400:
> +					baud = 2400;
> +					break;
> +
> +				case B1800:
> +					baud = 1800;
> +					break;
> +
> +				case B1200:
> +					baud = 1200;
> +					break;
> +
> +				case B600:
> +					baud = 600;
> +					break;
> +
> +				case B300:
> +					baud = 300;
> +					break;
> +
> +				case B200:
> +					baud = 200;
> +					break;
> +
> +				case B150:
> +					baud = 150;
> +					break;
> +
> +				case B134:
> +					baud = 134;
> +					break;
> +
> +				case B110:
> +					baud = 110;
> +					break;
> +
> +				case B75:
> +					baud = 75;
> +					break;
> +
> +				case B50:
> +					baud = 50;
> +					break;
> +
> +				default:
> +					baud = 9600;
> +					break;
> +			}
> +		}
> +
> +		if (baud == 0)
> +		{
> +			baud = 9600;
> +		}
> +
> +		if (baud >= min && baud <= max)
> +		{
> +			return baud;
> +		}
> +
> +		termios->c_cflag &= ~CBAUD;
> +
> +		if (old)
> +		{
> +			termios->c_cflag |= old->c_cflag & CBAUD;
> +			old = NULL;
> +			continue;
> +		}
> +
> +		termios->c_cflag |= B9600;
> +	}
> +
> +	return 0;
> +}
> +
> +
> +extern void snx_ser_change_speed(struct snx_ser_state *state, struct SNXTERMIOS *old_termios)
> +{
> +	struct tty_struct *tty = state->info->tty;
> +	struct snx_ser_port *port = state->port;
> +	struct SNXTERMIOS *termios;
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	if (!tty || port->type == PORT_UNKNOWN)
> +	{
> +		return;
> +	}
> +#else
> +	if (!tty || !tty->termios || port->type == PORT_UNKNOWN)
> +	{
> +		return;
> +	}
> +#endif
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	termios = &tty->termios;
> +#else
> +	termios = tty->termios;
> +#endif
> +
> +	if (termios->c_cflag & CRTSCTS)
> +	{
> +		state->info->flags |= SNX_UIF_CTS_FLOW;
> +    }
> +	else
> +	{
> +		state->info->flags &= ~SNX_UIF_CTS_FLOW;
> +    }
> +
> +	if (termios->c_cflag & CLOCAL)
> +	{
> +		state->info->flags &= ~SNX_UIF_CHECK_CD;
> +	}
> +	else
> +	{
> +		state->info->flags |= SNX_UIF_CHECK_CD;
> +	}
> +
> +	sunix_ser_set_termios(port, termios, old_termios);
> +}
> +
> +
> +static void snx_ser_set_termios(struct tty_struct *tty, struct SNXTERMIOS *old_termios)
> +{
> +	struct snx_ser_state *state = NULL;
> +	unsigned long flags;
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	unsigned int cflag = tty->termios.c_cflag;
> +#else
> +	unsigned int cflag = tty->termios->c_cflag;
> +#endif
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return;
> +	}
> +
> +	state = tty->driver_data;
> +
> +#define RELEVANT_IFLAG(iflag)	((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	if ((cflag ^ old_termios->c_cflag) == 0 && RELEVANT_IFLAG(tty->termios.c_iflag ^ old_termios->c_iflag) == 0)
> +	{
> +		return;
> +	}
> +#else
> +	if ((cflag ^ old_termios->c_cflag) == 0 && RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
> +	{
> +		return;
> +	}
> +#endif
> +
> +	snx_ser_change_speed(state, old_termios);
> +
> +	if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
> +	{
> +		snx_clear_mctrl(state->port, TIOCM_RTS | TIOCM_DTR);
> +	}
> +
> +	if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD))
> +	{
> +		unsigned int mask = TIOCM_DTR;
> +		if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags))
> +		{
> +			mask |= TIOCM_RTS;
> +		}
> +
> +		snx_set_mctrl(state->port, mask);
> +	}
> +
> +	if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS))
> +	{
> +		spin_lock_irqsave(&state->port->lock, flags);
> +		tty->hw_stopped = 0;
> +		__snx_ser_start(tty);
> +		spin_unlock_irqrestore(&state->port->lock, flags);
> +	}
> +}
> +
> +
> +void snx_ser_update_termios(struct snx_ser_state *state)
> +{
> +	struct tty_struct *tty = state->info->tty;
> +	struct snx_ser_port *port = state->port;
> +
> +
> +	if (!(tty->flags & (1 << TTY_IO_ERROR)))
> +	{
> +		snx_ser_change_speed(state, NULL);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +		if (tty->termios.c_cflag & CBAUD)
> +		{
> +			snx_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
> +		}
> +#else
> +		if (tty->termios->c_cflag & CBAUD)
> +		{
> +			snx_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
> +		}
> +#endif
> +	}
> +}
> +
> +
> +static void snx_ser_update_timeout(struct snx_ser_port *port, unsigned int cflag, unsigned int baud)
> +{
> +	unsigned int bits;
> +
> +
> +	switch (cflag & CSIZE)
> +	{
> +		case CS5:
> +			bits = 7;
> +			break;
> +
> +		case CS6:
> +			bits = 8;
> +			break;
> +
> +		case CS7:
> +			bits = 9;
> +			break;
> +
> +		default:
> +			bits = 10;
> +			break;
> +	}
> +
> +	if (cflag & CSTOPB)
> +	{
> +		bits++;
> +	}
> +
> +	if (cflag & PARENB)
> +	{
> +		bits++;
> +	}
> +
> +	bits = bits * port->fifosize;
> +
> +	port->timeout = (HZ * bits) / baud + HZ/50;
> +}
> +
> +
> +static struct snx_ser_state *snx_ser_get(struct snx_ser_driver *drv, int line)
> +{
> +	struct snx_ser_state *state = NULL;
> +
> +
> +	down(&ser_port_sem);
> +
> +	state = drv->state + line;
> +
> +	if (down_interruptible(&state->sem))
> +	{
> +		state = ERR_PTR(-ERESTARTSYS);
> +		goto out;
> +    }
> +
> +	state->count++;
> +
> +	if (!state->port)
> +	{
> +		state->count--;
> +		up(&state->sem);
> +		state = ERR_PTR(-ENXIO);
> +		goto out;
> +	}
> +
> +	if (!state->port->iobase)
> +	{
> +		state->count--;
> +		up(&state->sem);
> +		state = ERR_PTR(-ENXIO);
> +		goto out;
> +	}
> +
> +	if (!state->info)
> +	{
> +		state->info = kmalloc(sizeof(struct snx_ser_info), GFP_KERNEL);
> +
> +		if (state->info)
> +		{
> +			memset(state->info, 0, sizeof(struct snx_ser_info));
> +			init_waitqueue_head(&state->info->open_wait);
> +			init_waitqueue_head(&state->info->delta_msr_wait);
> +
> +			state->port->info = state->info;
> +
> +			tasklet_init(&state->info->tlet, snx_ser_tasklet_action, (unsigned long)state);
> +		}
> +		else
> +		{
> +			state->count--;
> +			up(&state->sem);
> +			state = ERR_PTR(-ENOMEM);
> +		}
> +	}
> +
> +out:
> +	up(&ser_port_sem);
> +
> +	return state;
> +}
> +
> +
> +static int snx_ser_block_til_ready(struct file *filp, struct snx_ser_state *state)
> +{
> +	DECLARE_WAITQUEUE(wait, current);
> +	struct snx_ser_info *info = state->info;
> +	struct snx_ser_port *port = state->port;
> +
> +
> +	info->blocked_open++;
> +	state->count--;
> +
> +	add_wait_queue(&info->open_wait, &wait);
> +
> +	while (1)
> +	{
> +		set_current_state(TASK_INTERRUPTIBLE);
> +
> +		if (tty_hung_up_p(filp) || info->tty == NULL)
> +		{
> +			break;
> +		}
> +
> +		if (!(info->flags & SNX_UIF_INITIALIZED))
> +		{
> +			break;
> +		}
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +		if ((filp->f_flags & O_NONBLOCK) ||
> +			(info->tty->termios.c_cflag & CLOCAL) ||
> +			(info->tty->flags & (1 << TTY_IO_ERROR)))
> +		{
> +			break;
> +		}
> +
> +		if (info->tty->termios.c_cflag & CBAUD)
> +		{
> +			snx_set_mctrl(port, TIOCM_DTR);
> +		}
> +#else
> +		if ((filp->f_flags & O_NONBLOCK) ||
> +			(info->tty->termios->c_cflag & CLOCAL) ||
> +			(info->tty->flags & (1 << TTY_IO_ERROR)))
> +		{
> +			break;
> +		}
> +
> +		if (info->tty->termios->c_cflag & CBAUD)
> +		{
> +			snx_set_mctrl(port, TIOCM_DTR);
> +		}
> +#endif
> +
> +		if (sunix_ser_get_mctrl(port) & TIOCM_CAR)
> +		{
> +			break;
> +		}
> +
> +		up(&state->sem);
> +		schedule();
> +		down(&state->sem);
> +
> +		if (signal_pending(current))
> +		{
> +			break;
> +		}
> +	}
> +
> +	set_current_state(TASK_RUNNING);
> +	remove_wait_queue(&info->open_wait, &wait);
> +
> +	state->count++;
> +	info->blocked_open--;
> +
> +	if (signal_pending(current))
> +	{
> +		return -ERESTARTSYS;
> +	}
> +
> +	if (!info->tty || tty_hung_up_p(filp))
> +	{
> +		return -EAGAIN;
> +	}
> +
> +	return 0;
> +}
> +
> +
> +static void snx_ser_wait_until_sent(struct tty_struct *tty, int timeout)
> +{
> +	struct snx_ser_state *state = NULL;
> +	struct snx_ser_port *port = NULL;
> +	unsigned long char_time;
> +	unsigned long expire;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line >= SUNIX_SDC_UART_MAX)
> +	{
> +		return;
> +	}
> +
> +	state = tty->driver_data;
> +	port = state->port;
> +
> +	if (port->type == PORT_UNKNOWN || port->fifosize == 0)
> +	{
> +		return;
> +	}
> +
> +	char_time = (port->timeout - HZ/50) / port->fifosize;
> +
> +    char_time = char_time / 5;
> +
> +    if (char_time == 0)
> +	{
> +		char_time = 1;
> +	}
> +
> +	if (timeout && timeout < char_time)
> +	{
> +		char_time = timeout;
> +	}
> +
> +	if (timeout == 0 || timeout > 2 * port->timeout)
> +	{
> +		timeout = 2 * port->timeout;
> +	}
> +
> +	expire = jiffies + timeout;
> +
> +	while (!sunix_ser_tx_empty(port))
> +	{
> +		set_current_state(TASK_INTERRUPTIBLE);
> +		schedule_timeout(char_time);
> +
> +		if (signal_pending(current))
> +		{
> +			break;
> +		}
> +
> +		if (time_after(jiffies, expire))
> +		{
> +			break;
> +		}
> +	}
> +	set_current_state(TASK_RUNNING);
> +}
> +
> +
> +static int snx_ser_open(struct tty_struct *tty, struct file *filp)
> +{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +	struct snx_ser_driver *drv = (struct snx_ser_driver *)tty->driver->driver_state;
> +#else
> +	struct snx_ser_driver *drv = (struct snx_ser_driver *)tty->driver.driver_state;
> +#endif
> +	struct snx_ser_state *state = NULL;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	struct tty_port *tport = NULL;
> +#endif
> +	int retval = 0;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line < SUNIX_SDC_UART_MAX)
> +	{
> +		retval = -ENODEV;
> +
> +		if (line >= SUNIX_SDC_UART_MAX)
> +		{
> +			goto fail;
> +		}
> +
> +		state = snx_ser_get(drv, line);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +		tport = &state->tport;
> +#endif
> +
> +		if (IS_ERR(state))
> +		{
> +			retval = PTR_ERR(state);
> +			goto fail;
> +		}
> +
> +		if (!state)
> +		{
> +			goto fail;
> +		}
> +
> +		state->port->suspended = 1;
> +		tty->driver_data = state;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
> +		tport->low_latency = (state->port->flags & SNX_UPF_LOW_LATENCY) ? 1 : 0;
> +#else
> +		tty->low_latency = (state->port->flags & SNX_UPF_LOW_LATENCY) ? 1 : 0;
> +#endif
> +
> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
> +		tty->alt_speed = 0;
> +#endif
> +		state->info->tty = tty;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +		tty_port_tty_set(tport, tty);
> +#endif
> +
> +		if (tty_hung_up_p(filp))
> +		{
> +			retval = -EAGAIN;
> +			state->count--;
> +			up(&state->sem);
> +			goto fail;
> +		}
> +
> +		retval = snx_ser_startup(state, 0);
> +
> +		if (retval == 0)
> +		{
> +			retval = snx_ser_block_til_ready(filp, state);
> +		}
> +
> +		up(&state->sem);
> +
> +		if (retval == 0 && !(state->info->flags & SNX_UIF_NORMAL_ACTIVE))
> +		{
> +			state->info->flags |= SNX_UIF_NORMAL_ACTIVE;
> +
> +			snx_ser_update_termios(state);
> +		}
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +		try_module_get(THIS_MODULE);
> +#else
> +		MOD_INC_USE_COUNT;
> +#endif
> +
> +	}
> +	else
> +	{
> +	}
> +
> +fail:
> +
> +	return retval;
> +}
> +
> +
> +static void snx_ser_close(struct tty_struct *tty, struct file *filp)
> +{
> +	struct snx_ser_state *state = tty->driver_data;
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	struct tty_port *tport;
> +#endif
> +	struct snx_ser_port *port = NULL;
> +	int line = SNX_SER_DEVNUM(tty);
> +
> +
> +	if (line < SUNIX_SDC_UART_MAX)
> +	{
> +		if (!state || !state->port)
> +		{
> +			return;
> +		}
> +
> +		port = state->port;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +		tport = &state->tport;
> +#endif
> +
> +		down(&state->sem);
> +
> +		if (tty_hung_up_p(filp))
> +		{
> +			goto done;
> +		}
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +		if ((tty->count == 1) && (state->count != 1))
> +		{
> +			printk("SUNIX: Bad serial port count; tty->count is 1, state->count is %d\n", state->count);
> +			state->count = 1;
> +		}
> +#endif
> +
> +		if (--state->count < 0)
> +		{
> +			printk("SUNIX: Bad serial port count for ttySDC%d: %d\n", port->line, state->count);
> +			state->count = 0;
> +		}
> +
> +		if (state->count)
> +		{
> +			goto done;
> +		}
> +
> +		tty->closing = 1;
> +
> +		port->suspended = 0;
> +		if (state->closing_wait != SNX_USF_CLOSING_WAIT_NONE)
> +		{
> +			tty_wait_until_sent(tty, state->closing_wait);
> +		}
> +
> +		if (state->info->flags & SNX_UIF_INITIALIZED)
> +		{
> +			unsigned long flags;
> +
> +			spin_lock_irqsave(&port->lock, flags);
> +			sunix_ser_stop_rx(port);
> +			spin_unlock_irqrestore(&port->lock, flags);
> +
> +			snx_ser_wait_until_sent(tty, port->timeout);
> +		}
> +
> +		snx_ser_shutdown(state);
> +		snx_ser_flush_buffer(tty);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
> +		if (tty->ldisc->ops->flush_buffer)
> +		{
> +			tty->ldisc->ops->flush_buffer(tty);
> +		}
> +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30))
> +		if (tty->ldisc.ops->flush_buffer)
> +		{
> +			tty->ldisc.ops->flush_buffer(tty);
> +		}
> +#else
> +		if (tty->ldisc.flush_buffer)
> +		{
> +			tty->ldisc.flush_buffer(tty);
> +		}
> +#endif
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +		tty_port_tty_set(tport, NULL);
> +#endif
> +
> +		tty->closing = 0;
> +		state->info->tty = NULL;
> +
> +		if (state->info->blocked_open)
> +		{
> +			if (state->close_delay)
> +			{
> +				set_current_state(TASK_INTERRUPTIBLE);
> +				schedule_timeout(state->close_delay);
> +			}
> +		}
> +
> +		state->info->flags &= ~SNX_UIF_NORMAL_ACTIVE;
> +		wake_up_interruptible(&state->info->open_wait);
> +
> +done:
> +		up(&state->sem);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +		module_put(THIS_MODULE);
> +#else
> +		MOD_DEC_USE_COUNT;
> +#endif
> +	}
> +	else
> +	{
> +	}
> +}
> +
> +
> +static void sunix_ser_set_mctrl(struct snx_ser_port *port, unsigned int mctrl)
> +{
> +	struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)port;
> +	unsigned char mcr = 0;
> +
> +
> +	if (mctrl & TIOCM_RTS)
> +	{
> +		mcr |= UART_MCR_RTS;
> +	}
> +
> +	if (mctrl & TIOCM_DTR)
> +	{
> +		mcr |= UART_MCR_DTR;
> +	}
> +
> +	if (mctrl & TIOCM_OUT1)
> +	{
> +		mcr |= UART_MCR_OUT1;
> +	}
> +
> +	if (mctrl & TIOCM_OUT2)
> +	{
> +		mcr |= UART_MCR_OUT2;
> +	}
> +
> +	if (mctrl & TIOCM_LOOP)
> +	{
> +		mcr |= UART_MCR_LOOP;
> +	}
> +
> +	mcr = (mcr & sp->mcr_mask) | sp->mcr_force | sp->mcr;
> +
> +	WRITE_UART_MCR(sp, mcr);
> +}
> +
> +
> +static unsigned int sunix_ser_tx_empty(struct snx_ser_port *port)
> +{
> +	struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)port;
> +	unsigned long flags;
> +	unsigned int ret;
> +
> +
> +	spin_lock_irqsave(&sp->port.lock, flags);
> +	ret = READ_UART_LSR(sp) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
> +	spin_unlock_irqrestore(&sp->port.lock, flags);
> +
> +	return ret;
> +}
> +
> +
> +static unsigned int sunix_ser_get_mctrl(struct snx_ser_port *port)
> +{
> +    struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)port;
> +    unsigned long flags;
> +    unsigned char status;
> +    unsigned int ret;
> +
> +
> +	ret = 0;
> +
> +	spin_lock_irqsave(&sp->port.lock, flags);
> +	status = READ_UART_MSR(sp);
> +	spin_unlock_irqrestore(&sp->port.lock, flags);
> +
> +	if (status & UART_MSR_DCD)
> +	{
> +		ret |= TIOCM_CAR;
> +	}
> +
> +	if (status & UART_MSR_RI)
> +	{
> +		ret |= TIOCM_RNG;
> +	}
> +
> +	if (status & UART_MSR_DSR)
> +	{
> +		ret |= TIOCM_DSR;
> +	}
> +
> +	if (status & UART_MSR_CTS)
> +	{
> +		ret |= TIOCM_CTS;
> +	}
> +	return ret;
> +}
> +
> +
> +static void sunix_ser_stop_tx(struct snx_ser_port *port, unsigned int tty_stop)
> +{
> +	struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)port;
> +
> +
> +	if (sp->ier & UART_IER_THRI)
> +	{
> +		sp->ier &= ~UART_IER_THRI;
> +		WRITE_UART_IER(sp, sp->ier);
> +	}
> +}
> +
> +
> +static void sunix_ser_start_tx(struct snx_ser_port *port, unsigned int tty_start)
> +{
> +	struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)port;
> +
> +
> +	if (!(sp->ier & UART_IER_THRI))
> +	{
> +		sp->ier |= UART_IER_THRI;
> +		WRITE_UART_IER(sp, sp->ier);
> +	}
> +}
> +
> +
> +static void sunix_ser_stop_rx(struct snx_ser_port *port)
> +{
> +	struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)port;
> +
> +
> +	sp->ier &= ~UART_IER_RLSI;
> +	sp->port.read_status_mask &= ~UART_LSR_DR;
> +	WRITE_UART_IER(sp, sp->ier);
> +}
> +
> +
> +static void sunix_ser_enable_ms(struct snx_ser_port *port)
> +{
> +	struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)port;
> +
> +
> +	sp->ier |= UART_IER_MSI;
> +	WRITE_UART_IER(sp, sp->ier);
> +}
> +
> +
> +static void sunix_ser_break_ctl(struct snx_ser_port *port, int break_state)
> +{
> +	struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)port;
> +	unsigned long flags;
> +
> +
> +	spin_lock_irqsave(&sp->port.lock, flags);
> +
> +	if (break_state == -1)
> +	{
> +		sp->lcr |= UART_LCR_SBC;
> +	}
> +	else
> +	{
> +		sp->lcr &= ~UART_LCR_SBC;
> +	}
> +
> +	WRITE_UART_LCR(sp, sp->lcr);
> +	spin_unlock_irqrestore(&sp->port.lock, flags);
> +}
> +
> +
> +static int sunix_ser_startup(struct snx_ser_port *port)
> +{
> +	struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)port;
> +
> +
> +	sp->capabilities = snx_uart_config[sp->port.type].flags;
> +	sp->mcr = 0;
> +
> +	if (sp->capabilities & UART_CLEAR_FIFO)
> +	{
> +		WRITE_UART_FCR(sp, UART_FCR_ENABLE_FIFO);
> +		WRITE_UART_FCR(sp, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
> +		WRITE_UART_FCR(sp, 0);
> +	}
> +
> +	(void) READ_UART_LSR(sp);
> +	(void) READ_UART_RX(sp);
> +	(void) READ_UART_IIR(sp);
> +	(void) READ_UART_MSR(sp);
> +
> +	if (!(sp->port.flags & SNX_UPF_BUGGY_UART) && (READ_UART_LSR(sp) == 0xff))
> +	{
> +		printk("SUNIX: ttySDC%d: LSR safety check engaged!\n", sp->port.line);
> +		return -ENODEV;
> +	}
> +
> +	WRITE_UART_LCR(sp, UART_LCR_WLEN8);
> +
> +	sp->ier = UART_IER_RLSI | UART_IER_RDI;
> +	WRITE_UART_IER(sp, sp->ier);
> +
> +	(void) READ_UART_LSR(sp);
> +	(void) READ_UART_RX(sp);
> +	(void) READ_UART_IIR(sp);
> +	(void) READ_UART_MSR(sp);
> +
> +	return 0;
> +}
> +
> +
> +static void sunix_ser_shutdown(struct snx_ser_port *port)
> +{
> +    struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)port;
> +
> +
> +    sp->ier = 0;
> +    WRITE_UART_IER(sp, 0);
> +
> +    WRITE_UART_LCR(sp, READ_UART_LCR(sp) & ~UART_LCR_SBC);
> +
> +    WRITE_UART_FCR(sp, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
> +    WRITE_UART_FCR(sp, 0);
> +
> +    (void) READ_UART_RX(sp);
> +}
> +
> +
> +static unsigned int sunix_ser_get_divisor(struct snx_ser_port *port, unsigned int baud)
> +{
> +	unsigned int quot;
> +
> +
> +	if ((port->flags & SNX_UPF_MAGIC_MULTIPLIER) && baud == (port->uartclk/4))
> +	{
> +		quot = 0x8001;
> +	}
> +	else if ((port->flags & SNX_UPF_MAGIC_MULTIPLIER) && baud == (port->uartclk/8))
> +	{
> +		quot = 0x8002;
> +	}
> +	else
> +	{
> +		quot = snx_ser_get_divisor(port, baud);
> +	}
> +
> +    return quot;
> +}
> +
> +
> +static void sunix_ser_set_termios(struct snx_ser_port *port, struct SNXTERMIOS *termios, struct SNXTERMIOS *old)
> +{
> +	struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)port;
> +	unsigned char cval;
> +	unsigned char fcr = 0;
> +	unsigned long flags;
> +	unsigned int baud;
> +	unsigned int quot;
> +
> +
> +	switch (termios->c_cflag & CSIZE)
> +	{
> +		case CS5:
> +			cval = 0x00;
> +			break;
> +
> +		case CS6:
> +			cval = 0x01;
> +			break;
> +
> +		case CS7:
> +			cval = 0x02;
> +			break;
> +
> +		default:
> +		case CS8:
> +			cval = 0x03;
> +			break;
> +	}
> +
> +	if (termios->c_cflag & CSTOPB)
> +	{
> +		cval |= 0x04;
> +	}
> +
> +	if (termios->c_cflag & PARENB)
> +	{
> +		cval |= UART_LCR_PARITY;
> +	}
> +
> +	if (!(termios->c_cflag & PARODD))
> +	{
> +		cval |= UART_LCR_EPAR;
> +	}
> +
> +#ifdef CMSPAR
> +	if (termios->c_cflag & CMSPAR)
> +	{
> +		cval |= UART_LCR_SPAR;
> +	}
> +#endif
> +
> +	baud = snx_ser_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
> +	quot = sunix_ser_get_divisor(port, baud);
> +
> +	if (sp->capabilities & UART_USE_FIFO)
> +	{
> +		if (baud < 2400)
> +		{
> +			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
> +		}
> +		else
> +		{
> +			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
> +		}
> +	}
> +
> +	sp->mcr &= ~UART_MCR_AFE;
> +
> +	if (termios->c_cflag & CRTSCTS)
> +	{
> +		sp->mcr |= UART_MCR_AFE;
> +	}
> +
> +	fcr |= 0x01;
> +
> +	spin_lock_irqsave(&sp->port.lock, flags);
> +
> +
> +	snx_ser_update_timeout(port, termios->c_cflag, baud);
> +
> +
> +	sp->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
> +
> +	if (termios->c_iflag & INPCK)
> +	{
> +		sp->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
> +	}
> +
> +	if (termios->c_iflag & (BRKINT | PARMRK))
> +	{
> +		sp->port.read_status_mask |= UART_LSR_BI;
> +	}
> +
> +	sp->port.ignore_status_mask = 0;
> +
> +	if (termios->c_iflag & IGNPAR)
> +	{
> +		sp->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
> +	}
> +
> +
> +	if (termios->c_iflag & IGNBRK)
> +	{
> +		sp->port.ignore_status_mask |= UART_LSR_BI;
> +
> +		if (termios->c_iflag & IGNPAR)
> +		{
> +			sp->port.ignore_status_mask |= UART_LSR_OE;
> +		}
> +	}
> +
> +	if ((termios->c_cflag & CREAD) == 0)
> +	{
> +		sp->port.ignore_status_mask |= UART_LSR_DR;
> +	}
> +
> +	sp->ier &= ~UART_IER_MSI;
> +	if (SNX_ENABLE_MS(&sp->port, termios->c_cflag))
> +	{
> +		sp->ier |= UART_IER_MSI;
> +	}
> +
> +	WRITE_UART_LCR(sp, cval | UART_LCR_DLAB);
> +
> +	WRITE_UART_DLL(sp, quot & 0xff);
> +	WRITE_UART_DLM(sp, quot >> 8);
> +
> +	WRITE_UART_FCR(sp, fcr);
> +
> +	WRITE_UART_LCR(sp, cval);
> +
> +	sp->lcr = cval;
> +
> +	sunix_ser_set_mctrl(&sp->port, sp->port.mctrl);
> +
> +	WRITE_UART_IER(sp, sp->ier);
> +
> +	spin_unlock_irqrestore(&sp->port.lock, flags);
> +}
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
> +static void sunix_ser_timeout(struct timer_list *t)
> +#else
> +static void sunix_ser_timeout(unsigned long data)
> +#endif
> +{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
> +	struct sunix_sdc_uart_channel *sp = from_timer(sp, t, timer);
> +#else
> +	struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)data;
> +#endif
> +	unsigned int timeout;
> +	unsigned int iir;
> +
> +
> +	iir = READ_UART_IIR(sp);
> +
> +	if (!(iir & UART_IIR_NO_INT))
> +	{
> +		spin_lock(&sp->port.lock);
> +		sunix_ser_handle_port(sp, iir);
> +		spin_unlock(&sp->port.lock);
> +    }
> +
> +	timeout = sp->port.timeout;
> +	timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
> +
> +	mod_timer(&sp->timer, jiffies + timeout);
> +}
> +
> +
> +static _INLINE_ void sunix_ser_receive_chars(struct sunix_sdc_uart_channel *sp, unsigned char *status)
> +{
> +	struct tty_struct *tty = sp->port.info->tty;
> +	unsigned char ch;
> +	int max_count = 256;
> +	unsigned char lsr = *status;
> +	char flag;
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
> +	struct snx_ser_state *state = NULL;
> +	struct tty_port *tport = NULL;
> +
> +
> +	state = tty->driver_data;
> +	tport = &state->tport;
> +#endif
> +
> +
> +	do
> +	{
> +		ch = READ_UART_RX(sp);
> +		flag = TTY_NORMAL;
> +		sp->port.icount.rx++;
> +
> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 18))
> +		if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE | UART_LSR_FE | UART_LSR_OE)))
> +#else
> +		if (lsr & (UART_LSR_BI | UART_LSR_PE | UART_LSR_FE | UART_LSR_OE))
> +#endif
> +		{				
> +			if (lsr & UART_LSR_BI)
> +			{
> +				lsr &= ~(UART_LSR_FE | UART_LSR_PE);
> +				sp->port.icount.brk++;
> +
> +				if (snx_ser_handle_break(&sp->port))
> +				{					
> +					goto ignore_char;
> +				}
> +			}
> +			else if (lsr & UART_LSR_PE)
> +			{
> +				sp->port.icount.parity++;
> +			}
> +			else if (lsr & UART_LSR_FE)
> +			{
> +				sp->port.icount.frame++;
> +			}
> +
> +			if (lsr & UART_LSR_OE)
> +			{
> +				sp->port.icount.overrun++;
> +			}
> +
> +			lsr &= sp->port.read_status_mask;
> +
> +			if (lsr & UART_LSR_BI)
> +			{
> +				flag = TTY_BREAK;
> +			}
> +			else if (lsr & UART_LSR_PE)
> +			{
> +				flag = TTY_PARITY;
> +			}
> +			else if (lsr & UART_LSR_FE)
> +			{
> +				flag = TTY_FRAME;
> +			}
> +		}
> +
> +
> +		if ((I_IXOFF(tty)) || I_IXON(tty))
> +		{			
> +			if (ch == START_CHAR(tty))
> +			{
> +				tty->stopped = 0;
> +				sunix_ser_start_tx(&sp->port, 1);
> +				goto ignore_char;
> +			}
> +			else if (ch == STOP_CHAR(tty))
> +			{
> +				tty->stopped = 1;
> +				sunix_ser_stop_tx(&sp->port, 1);
> +				goto ignore_char;
> +			}
> +		}
> +
> +		snx_ser_insert_char(&sp->port, lsr, UART_LSR_OE, ch, flag);
> +
> +ignore_char:
> +		lsr = READ_UART_LSR(sp);
> +	
> +		if (lsr == 0xff)
> +		{
> +			lsr = 0x01;
> +		}
> +
> +	} while ((lsr & UART_LSR_DR) && (max_count-- > 0));
> +
> +	spin_unlock(&sp->port.lock);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
> +	tty_flip_buffer_push(tport);
> +#else
> +	tty_flip_buffer_push(tty);
> +#endif
> +
> +	spin_lock(&sp->port.lock);
> +	*status = lsr;
> +}
> +
> +
> +static _INLINE_ void sunix_ser_transmit_chars(struct sunix_sdc_uart_channel *sp)
> +{
> +	struct circ_buf *xmit = &sp->port.info->xmit;
> +	int count;
> +
> +
> +	if ((!sp) || (!sp->port.iobase))
> +	{
> +		return;
> +	}
> +
> +	if (!sp->port.info)
> +	{
> +		return;
> +	}
> +
> +	if (!xmit)
> +	{
> +		return;
> +	}
> +
> +	if (sp->port.x_char)
> +	{
> +		WRITE_UART_TX(sp, sp->port.x_char);
> +		sp->port.icount.tx++;
> +		sp->port.x_char = 0;
> +		return;
> +	}
> +
> +	if (snx_ser_circ_empty(xmit))
> +	{
> +		sunix_ser_stop_tx(&sp->port, 0);
> +		return;
> +	}
> +	
> +	if (snx_ser_tx_stopped(&sp->port))
> +	{
> +		sunix_ser_stop_tx(&sp->port, 0);
> +		return;
> +	}
> +
> +	count = sp->port.fifosize;
> +
> +	do
> +	{
> +		WRITE_UART_TX(sp, xmit->buf[xmit->tail]);
> +		xmit->tail = (xmit->tail + 1) & (SNX_UART_XMIT_SIZE - 1);
> +		sp->port.icount.tx++;
> +
> +		if (snx_ser_circ_empty(xmit))
> +		{
> +			break;
> +		}
> +
> +	} while (--count > 0);
> +
> +	if (snx_ser_circ_chars_pending(xmit) < WAKEUP_CHARS)
> +	{
> +		snx_ser_write_wakeup(&sp->port);
> +	}
> +}
> +
> +
> +static _INLINE_ void sunix_ser_check_modem_status(struct sunix_sdc_uart_channel *sp, unsigned char status)
> +{		
> +	if ((status & UART_MSR_ANY_DELTA) == 0)
> +	{
> +		return;
> +	}
> +
> +	if (!sp->port.info)
> +	{
> +		return;
> +	}
> +
> +	if (status & UART_MSR_TERI)
> +	{
> +		sp->port.icount.rng++;
> +	}
> +
> +	if (status & UART_MSR_DDSR)
> +	{
> +		sp->port.icount.dsr++;
> +	}
> +
> +	if (status & UART_MSR_DDCD)
> +	{
> +		snx_ser_handle_dcd_change(&sp->port, status & UART_MSR_DCD);
> +	}
> +
> +	if (status & UART_MSR_DCTS)
> +	{
> +		snx_ser_handle_cts_change(&sp->port, status & UART_MSR_CTS);
> +	}
> +
> +	wake_up_interruptible(&sp->port.info->delta_msr_wait);
> +}
> +
> +
> +static _INLINE_ void sunix_ser_handle_port(struct sunix_sdc_uart_channel *sp, unsigned char iir)
> +{
> +	unsigned char lsr = READ_UART_LSR(sp);
> +	unsigned char msr = 0;
> +
> +
> +	if (lsr == 0xff)
> +	{
> +		lsr = 0x01;		
> +	}
> +
> +	if ((iir == UART_IIR_RLSI) || (iir == UART_IIR_CTO) || (iir == UART_IIR_RDI))
> +	{
> +		sunix_ser_receive_chars(sp, &lsr);
> +	}
> +	
> +	if ((iir == UART_IIR_THRI) && (lsr & UART_LSR_THRE))
> +	{
> +		sunix_ser_transmit_chars(sp);
> +	}
> +
> +	msr = READ_UART_MSR(sp);
> +
> +	if (msr & UART_MSR_ANY_DELTA)
> +	{
> +		sunix_ser_check_modem_status(sp, msr);
> +	}
> +}
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +static struct tty_operations sunix_tty_ops =
> +{
> +	.open               = snx_ser_open,
> +	.close              = snx_ser_close,
> +	.write              = snx_ser_write,
> +	.put_char           = snx_ser_put_char,
> +	.flush_chars        = snx_ser_flush_chars,
> +	.write_room         = snx_ser_write_room,
> +	.chars_in_buffer    = snx_ser_chars_in_buffer,
> +	.flush_buffer       = snx_ser_flush_buffer,
> +	.ioctl              = snx_ser_ioctl,
> +	.throttle           = snx_ser_throttle,
> +	.unthrottle         = snx_ser_unthrottle,
> +	.send_xchar         = snx_ser_send_xchar,
> +	.set_termios        = snx_ser_set_termios,
> +	.stop               = snx_ser_stop,
> +	.start              = snx_ser_start,
> +	.hangup             = snx_ser_hangup,
> +	.break_ctl          = snx_ser_break_ctl,
> +	.wait_until_sent    = snx_ser_wait_until_sent,
> +	.tiocmget           = snx_ser_tiocmget,
> +	.tiocmset           = snx_ser_tiocmset,
> +};
> +#endif

NO! Don't write your own tty driver - use serial subsystem.
And if the device is 8250 compatible, use that one.

> +static struct snx_ser_driver sunix_ser_reg =
> +{
> +	.dev_name = "ttySDC",
> +	.major = 0,
> +	.minor = 0,
> +	.nr = (SUNIX_SDC_UART_MAX + 1),
> +};
> +
> +
> +int sunix_ser_register_driver(void)
> +{
> +	struct snx_ser_driver *drv = &sunix_ser_reg;
> +	struct tty_driver *normal = NULL;
> +	int i;
> +	int ret = 0;
> +
> +
> +	drv->state = kmalloc(sizeof(struct snx_ser_state) * drv->nr, GFP_KERNEL);
> +
> +	ret = -ENOMEM;
> +
> +	if (!drv->state)
> +	{
> +		printk("SUNIX: Allocate memory fail !\n");
> +		goto out;
> +	}
> +
> +	memset(drv->state, 0, sizeof(struct snx_ser_state) * drv->nr);
> +
> +	for (i = 0; i < drv->nr; i++)
> +	{
> +		struct snx_ser_state *state = drv->state + i;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +		struct tty_port *tport = &state->tport;
> +		tty_port_init(tport);
> +#endif
> +
> +		if (!state)
> +		{
> +			ret = -1;
> +			printk("SUNIX: Memory error !\n");
> +			goto out;
> +		}
> +
> +		state->close_delay     = 5 * HZ / 100;
> +		state->closing_wait    = 3 * HZ;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
> +		sema_init(&state->sem, 1);
> +#else
> +		init_MUTEX(&state->sem);
> +#endif
> +    }
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	normal = tty_alloc_driver(SUNIX_SDC_UART_MAX + 1, TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
> +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +	normal = alloc_tty_driver(drv->nr);
> +#else
> +	normal = &drv->tty_driver;
> +#endif
> +
> +
> +	if (!normal)
> +	{
> +		printk("SUNIX: Allocate tty driver fail !\n");
> +		goto out;
> +	}
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +
> +#else
> +	memset(normal, 0, sizeof(struct tty_driver));
> +#endif
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +    drv->tty_driver = normal;
> +#endif
> +
> +	normal->magic                   = TTY_DRIVER_MAGIC;
> +	normal->name                    = drv->dev_name;
> +	normal->major                   = drv->major;
> +	normal->minor_start             = drv->minor;
> +	normal->num                     = (SUNIX_SDC_UART_MAX + 1);
> +	normal->type                    = TTY_DRIVER_TYPE_SERIAL;
> +	normal->subtype                 = SERIAL_TYPE_NORMAL;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +
> +#else
> +	normal->flags                   = TTY_DRIVER_REAL_RAW ;
> +#endif
> +
> +	normal->init_termios            = tty_std_termios;
> +	normal->init_termios.c_cflag    = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
> +	normal->init_termios.c_iflag    = 0;
> +
> +	normal->driver_state            = drv;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +	tty_set_operations(normal, &sunix_tty_ops);
> +#else
> +	normal->refcount                = &sunix_ser_refcount;
> +	normal->table				    = sunix_ser_tty;
> +
> +	normal->termios				    = sunix_ser_termios;
> +	normal->termios_locked		    = sunix_ser_termios_locked;
> +
> +	normal->open                    = snx_ser_open;
> +	normal->close                   = snx_ser_close;
> +	normal->write                   = snx_ser_write;
> +	normal->put_char                = snx_ser_put_char;
> +	normal->flush_chars             = snx_ser_flush_chars;
> +	normal->write_room              = snx_ser_write_room;
> +	normal->chars_in_buffer         = snx_ser_chars_in_buffer;
> +	normal->flush_buffer            = snx_ser_flush_buffer;
> +	normal->ioctl                   = snx_ser_ioctl;
> +	normal->throttle                = snx_ser_throttle;
> +	normal->unthrottle              = snx_ser_unthrottle;
> +	normal->send_xchar              = snx_ser_send_xchar;
> +	normal->set_termios             = snx_ser_set_termios;
> +	normal->stop                    = snx_ser_stop;
> +	normal->start                   = snx_ser_start;
> +	normal->hangup                  = snx_ser_hangup;
> +	normal->break_ctl               = snx_ser_break_ctl;
> +	normal->wait_until_sent         = snx_ser_wait_until_sent;
> +#endif
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	tty_port_link_device(&snx_service_port, normal, SUNIX_SDC_UART_MAX);
> +#endif
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
> +	kref_init(&normal->kref);
> +#endif
> +
> +	ret = tty_register_driver(normal);
> +
> +	if (ret < 0)
> +	{
> +		printk("SUNIX: Register tty driver fail !\n");
> +		goto out;
> +	}
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
> +	for (i = 0; i < drv->nr; i++)
> +	{
> +		struct snx_ser_state *state = drv->state + i;
> +		struct tty_port *tport = &state->tport;
> +
> +		tty_port_destroy(tport);
> +	}
> +#endif
> +
> +out:
> +	if (ret < 0)
> +	{
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +		put_tty_driver(normal);
> +#endif
> +		kfree(drv->state);
> +	}
> +
> +	return (ret);
> +}
> +
> +
> +void sunix_ser_unregister_driver(void)
> +{
> +	struct snx_ser_driver *drv = &sunix_ser_reg;
> +	struct tty_driver *normal = NULL;
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
> +	unsigned int i;
> +#endif
> +
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
> +	normal = drv->tty_driver;
> +
> +	if (!normal)
> +	{
> +		return;
> +	}
> +
> +	tty_unregister_driver(normal);
> +	put_tty_driver(normal);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
> +	for (i = 0; i < drv->nr; i++)
> +	{
> +		struct snx_ser_state *state = drv->state + i;
> +		struct tty_port *tport = &state->tport;
> +
> +		tty_port_destroy(tport);
> +	}
> +#endif
> +
> +	drv->tty_driver = NULL;
> +
> +#else
> +	normal = &drv->tty_driver;
> +	if (!normal)
> +	{
> +		return;
> +	}
> +
> +	tty_unregister_driver(normal);
> +#endif
> +
> +	if (drv->state)
> +	{
> +		kfree(drv->state);
> +	}
> +}
> +
> +
> +static void sunix_ser_request_io(struct snx_ser_port *port)
> +{
> +	struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)port;
> +
> +
> +	switch (sp->port.iotype)
> +	{
> +		case SNX_UPIO_PORT:
> +			request_region(sp->port.iobase, sp->port.iosize, "sunix_sdc_uart");
> +			break;
> +
> +		default:
> +			break;
> +	}
> +}
> +
> +
> +static void sunix_ser_configure_port(struct snx_ser_driver *drv, struct snx_ser_state *state, struct snx_ser_port *port)
> +{
> +	unsigned long flags;
> +
> +
> +	if (!port->iobase)
> +	{
> +		return;
> +	}
> +
> +	flags = SNX_UART_CONFIG_TYPE;
> +
> +	if (port->type != PORT_UNKNOWN)
> +	{
> +		sunix_ser_request_io(port);
> +
> +		spin_lock_irqsave(&port->lock, flags);
> +
> +		sunix_ser_set_mctrl(port, 0);
> +		spin_unlock_irqrestore(&port->lock, flags);
> +	}
> +}
> +
> +
> +static int sunix_ser_add_one_port(struct snx_ser_driver *drv, struct snx_ser_port *port)
> +{
> +	struct snx_ser_state *state = NULL;
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	struct tty_port *tport;
> +	struct device *tty_dev;
> +#endif
> +	int ret = 0;
> +
> +
> +	if (port->line >= drv->nr)
> +	{
> +		return -EINVAL;
> +	}
> +
> +	state = drv->state + port->line;
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	tport = &state->tport;
> +#endif
> +
> +	down(&ser_port_sem);
> +
> +	if (state->port)
> +	{
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	state->port = port;
> +
> +	port->info = state->info;
> +
> +	sunix_ser_configure_port(drv, state, port);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +
> +	tty_dev = tty_port_register_device(tport, drv->tty_driver, port->line, port->dev);
> +
> +	if (likely(!IS_ERR(tty_dev)))
> +	{
> +		device_set_wakeup_capable(tty_dev, 1);
> +	}
> +	else
> +	{
> +		printk("SUNIX: Cannot register tty device on line %d\n", port->line);
> +	}
> +
> +#endif
> +
> +out:
> +	up(&ser_port_sem);
> +
> +	return ret;
> +}
> +
> +
> +int sunix_ser_register_ports(void)
> +{
> +	struct snx_ser_driver *drv = &sunix_ser_reg;
> +	struct sunix_sdc_board *sb = NULL;
> +	int i;
> +	int ret;
> +
> +
> +	sb = &sunix_sdc_board_table[0];
> +	if (sb == NULL)
> +	{
> +		return 0;
> +	}
> +
> +	pci_set_drvdata(sb->pdev, sb);
> +
> +	for (i = 0; i < SUNIX_SDC_UART_MAX + 1; i++)
> +	{
> +		struct sunix_sdc_uart_channel *sp = &sunix_sdc_uart_table[i];
> +
> +		if (!sp)
> +		{
> +			return -1;
> +		}
> +
> +		sp->port.line = i;
> +
> +		if (sp->port.iobase)
> +		{
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
> +			timer_setup(&sp->timer, sunix_ser_timeout, 0);
> +#else
> +			init_timer(&sp->timer);
> +			sp->timer.function = sunix_ser_timeout;
> +#endif
> +			sp->mcr_mask = ~0;
> +			sp->mcr_force = 0;
> +
> +			ret = sunix_ser_add_one_port(drv, &sp->port);
> +
> +			if (ret != 0)
> +			{
> +				return ret;
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +
> +static void sunix_ser_release_io(struct snx_ser_port *port)
> +{
> +	struct sunix_sdc_uart_channel *sp = (struct sunix_sdc_uart_channel *)port;
> +
> +
> +	switch (sp->port.iotype)
> +	{
> +		case SNX_UPIO_PORT:
> +			release_region(sp->port.iobase, sp->port.iosize);
> +			break;
> +
> +		default:
> +			break;
> +	}
> +}
> +
> +
> +static void sunix_ser_unconfigure_port(struct snx_ser_driver *drv, struct snx_ser_state *state)
> +{
> +	struct snx_ser_port *port = state->port;
> +	struct snx_ser_info *info = state->info;
> +
> +
> +	if (info && info->tty)
> +	{
> +		tty_hangup(info->tty);
> +	}
> +
> +	down(&state->sem);
> +
> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
> +	tty_unregister_device(drv->tty_driver, port->line);
> +#endif
> +
> +	state->info = NULL;
> +
> +	if (port->type != PORT_UNKNOWN)
> +	{
> +		sunix_ser_release_io(port);
> +	}
> +
> +	port->type = PORT_UNKNOWN;
> +
> +	if (info)
> +	{
> +		tasklet_kill(&info->tlet);
> +		kfree(info);
> +	}
> +
> +	up(&state->sem);
> +}
> +
> +
> +static int sunix_ser_remove_one_port(struct snx_ser_driver *drv, struct snx_ser_port *port)
> +{
> +	struct snx_ser_state *state = drv->state + port->line;
> +
> +
> +	if (state->port != port)
> +	{
> +		printk("SUNIX: Removing wrong port: %p != %p\n", state->port, port);
> +	}
> +
> +	down(&ser_port_sem);
> +
> +	sunix_ser_unconfigure_port(drv, state);
> +
> +	state->port = NULL;
> +
> +	up(&ser_port_sem);
> +
> +	return 0;
> +}
> +
> +
> +void sunix_ser_unregister_ports(void)
> +{
> +	struct snx_ser_driver *drv = &sunix_ser_reg;
> +	int i;
> +
> +
> +	for (i = 0; i < SUNIX_SDC_UART_MAX + 1; i++)
> +	{
> +		struct sunix_sdc_uart_channel *sp = &sunix_sdc_uart_table[i];
> +
> +		if (sp->port.iobase)
> +		{
> +			sunix_ser_remove_one_port(drv, &sp->port);
> +		}
> +	}
> +}
> +
> +
> +int sunix_ser_interrupt(struct sunix_sdc_uart_channel *sp)
> +{
> +	unsigned char iir;
> +
> +
> +	iir = READ_UART_IIR(sp) & 0x0f;
> +
> +	if (!(iir & UART_IIR_NO_INT))
> +	{
> +		spin_lock(&sp->port.lock);
> +		sunix_ser_handle_port(sp, iir);
> +		spin_unlock(&sp->port.lock);
> +	}
> +
> +    return 0;
> +}
> +

Summary:

Around 90% of your code is completely redundant, introducing completely
incompatible device-specific userland api's (char devices), instead of
using the corresponding subsystems (gpio, serial, spi, etc).

Major 2do's:

* remove all dead code (drop everything that's just for ancient kernel
   versions)
* use the corresponding subsystems for the subdevices, eg:
   gpio for the dio sebdev
   serial/8250 for the sdc subdev
   spi fo the spi subdev
* move that code under the corresponding subsys trees, make the drivers
   standalone (eg. as platform devices) and let the mfd just handle the
   board specialties and instantiate the individual sub devices
* drop the useless printf()s
* use the pci subsystem for card probing (not manually scanning)
* drop the global arrays, use per-device privdata

If some of these subdevs really have some special functionality, that
can't be handled by the corresponding subsystems yet, let us know.

And please read the documentation before writing that much code.


thx

--mtx

-- 
---
Hinweis: unverschlüsselte E-Mails können leicht abgehört und manipuliert
werden ! Für eine vertrauliche Kommunikation senden Sie bitte ihren
GPG/PGP-Schlüssel zu.
---
Enrico Weigelt, metux IT consult
Free software and Linux embedded engineering
info@...ux.net -- +49-151-27565287

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ