Re: [PATCH] Add Driver for SUNIX PCI(e) I/O expansion board

From: Enrico Weigelt, metux IT consult
Date: Wed Mar 31 2021 - 15:22:14 EST


On 30.03.21 08:58, Moriis Ku wrote:

Hi folks,

From: Morris <saumah@xxxxxxxxx>

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@xxxxxxxxx>
---
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@xxxxxxxxxxxx>");
+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@xxxxxxxxx -- +49-151-27565287