struct mutex neuronspi_master_mutex;
struct mutex unipi_inv_speed_mutex;
int neuronspi_model_id = -1;
-struct spi_device *neuronspi_s_dev[NEURONSPI_MAX_DEVS];
+struct spi_device *neuronspi_s_dev[NEURONSPI_MAX_DEVS]; // global list of neuron spi devices
struct task_struct *neuronspi_invalidate_thread;
static u8 neuronspi_probe_count = 0;
u16 packet_crc;
u16 crc_send_buf[2];
u16 crc_recv_buf[2];
+ u8 opcode;
+ int portindex;
+ struct neuronspi_port* port;
+
struct neuronspi_driver_data *d_data;
struct spi_transfer* s_trans;
if (recv_crc1 == packet_crc) {
unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI CRC1 Correct (=%04x)", packet_crc);
-
- if (d_data != NULL && !d_data->reserved_device && ((recv_buf->first_message[0] & 0xfd) == 0x41)) {
+ opcode = recv_buf->first_message[0];
+ if (d_data != NULL && (opcode >= 0x41)&&(opcode <= 0x44)) {
// Signal the UART to issue character reads
- unipi_spi_trace(KERN_INFO "UNIPISPI: Reading UART data for device %d\n", d_data->neuron_index);
-
- if (recv_buf->first_message[0] == 0x41) {
- // read one incomming character from UART
- d_data->uart_buf[0] = recv_buf->first_message[3];
- for (i = 0; i < d_data->uart_data->p_count; i++) {
- if (d_data->uart_data->p[i].dev_index == d_data->neuron_index) {
- neuronspi_uart_handle_rx(&d_data->uart_data->p[i], 1, 1);
- }
- }
- }
- if (!(d_data->uart_read) && (d_data->uart_count)) {
+ portindex = (opcode==0x43) ? 0 : (opcode - 0x41);
+ if (d_data->uart_count && (portindex < d_data->uart_count)) {
+ unipi_spi_trace(KERN_INFO "UNIPISPI: Reading UART data for device %d, opcode=%02x\n", d_data->neuron_index, opcode);
+ port = neuronspi_uart_data_global->p + d_data->uart_pindex + portindex;
+ if (opcode != 0x43) {
+ // read one incomming character from UART
+ neuronspi_rx_queue_add(port, recv_buf->first_message[3]);
+ //neuronspi_uart_handle_rx(port, 1, 1);
+ }
// read queue length
- d_data->uart_read = recv_buf->first_message[2];
- for (i = 0; i < d_data->uart_data->p_count; i++) {
- unipi_spi_trace(KERN_INFO "UNIPISPI: UART Buffer:%d, UART Local Port Count:%d, UART Global Port Count:%d\n", d_data->uart_read,
- d_data->uart_count, d_data->uart_data->p_count);
- if (d_data->uart_data->p[i].dev_index == d_data->neuron_index && !d_data->reserved_device) {
- kthread_queue_work(&d_data->uart_data->kworker, &d_data->uart_data->p[i].rx_work);
- }
- }
- }
+ port->rx_remain = recv_buf->first_message[2];
+ //if (!d_data->uart_read) {
+ // d_data->uart_read = recv_buf->first_message[2];
+ unipi_spi_trace(KERN_INFO "UNIPISPI: UART Buffer:%d, ttyNS%d(%d:%d)\n", port->rx_remain, port->port.line, port->dev_index, port->dev_port);
+ kthread_queue_work(&neuronspi_uart_data_global->kworker, &port->rx_work);
+
+ }
}
} else {
recv_buf->first_message[0] = 0;
} else {
packet_crc = recv_buf->second_message[len] | (recv_buf->second_message[len+1] << 8);
}
- unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI Master Read - %d:\n\t%100ph\n\t%100ph\n\t%100ph\n\t%100ph\n", len, recv_buf->second_message, &recv_buf->second_message[64],
- &recv_buf->second_message[128], &recv_buf->second_message[192]);
+ unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI Master Read - %d:\n\t%64ph\n\t%64ph\n\t%64ph\n\t%64ph\n", len,
+ recv_buf->second_message, recv_buf->second_message + 64,
+ recv_buf->second_message+128, recv_buf->second_message+192);
if (recv_crc2 != packet_crc) {
unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI CRC2 Not Correct: %04x COMPUTED: %04x\n", packet_crc, recv_crc2);
if (send_header & UNIPISPI_OP_MODE_SEND_HEADER)
recv_buf->second_message[0] = 0;
ret_code = 1;
- }
+
+ } else if (recv_buf->second_message[0] == 0x65) {
+
+ // this op can be invoked only from kernel_work rx_proc
+ portindex = 0; // second_message[2]; Overit ve firmware
+ if (d_data->uart_count && (portindex < d_data->uart_count)) {
+ port = neuronspi_uart_data_global->p + d_data->uart_pindex + portindex;
+ port->rx_remain = recv_buf->second_message[3];
+ neuronspi_rx_queue_swap(port);
+ }
+ }
}
mutex_unlock(&neuronspi_master_mutex);
return ret_code;
simple_write_to_buffer(private_data->send_buf.second_message, NEURONSPI_BUFFER_MAX, &dummy_offset, buffer, datalen);
//memcpy(private_data->send_buf.second_message, buffer + NEURONSPI_HEADER_LENGTH, private_data->message_len);
}
-
// clear receive buffer content
#if NEURONSPI_DETAILED_DEBUG > 1
memset(private_data->recv_buf.first_message, 0, sizeof(private_data->recv_buf.first_message));
private_data->recv_buf.second_message[0] = 0;
#endif
+ if (private_data->message_len) {
+ if (private_data->send_buf.second_message[0] == 0x65) {
+ // op read string is not allowed here
+ mutex_unlock(&private_data->lock);
+ return len;
+ }
+ }
neuronspi_spi_send_op(spi_driver_data, &private_data->send_buf, &private_data->recv_buf, private_data->message_len,
frequency, delay, send_header, reservation);
mutex_unlock(&private_data->lock);
frequency = d_data->ideal_frequency;
}
- unipi_spi_trace(KERN_INFO "UNIPISPI: UART SPI Write, dev:%d, len:%d\n", uart_index, length);
+ unipi_spi_trace(KERN_INFO "UNIPISPI: SPI uart write, dev:%d, len:%d\n", uart_index, length);
if ((length == 0) || (length > 256)) {
return -1;
}
frequency = d_data->ideal_frequency;
}
- unipi_spi_trace(KERN_INFO "UNIPISPI: UART SPI Read, cs:%d, len:%d\n", uart_index, len);
+ unipi_spi_trace(KERN_INFO "UNIPISPI: SPI uart read, dev:%d, len:%d\n", uart_index, len);
if (len < 246) {
len = (len+4);
} else {
send_buf = kzalloc(transmit_len, GFP_ATOMIC);
- if (NEURON_FIRMWARE_VERSION(d_data) < 0x518) {
- send_op.first_message[0] = 0x65;
- } else {
- send_op.first_message[0] = 0x68;
- }
+#if 1
+ send_op.first_message[0] = 0x65;
+#else
+ send_op.first_message[0] = (NEURON_FIRMWARE_VERSION(d_data) < 0x518) ? 0x65 : 0x68;
+#endif
send_buf[0] = 0x65;
send_op.second_message = send_buf;
s32 i;
struct spi_device *spi;
struct neuronspi_driver_data *d_data;
- struct neuronspi_uart_data *u_data;
+ //struct neuronspi_uart_data *u_data;
spi = (struct spi_device *)dev_id;
d_data = spi_get_drvdata(spi);
unipi_spi_trace(KERN_INFO "UNIPISPI: SPI IRQ\n");
if (d_data->uart_count) {
- u_data = d_data->uart_data;
- for (i = 0; i < u_data->p_count; i++) {
- if (u_data->p[i].dev_index == d_data->neuron_index) {
- kthread_queue_work(&u_data->kworker, &u_data->p[i].irq_work);
+ for (i = 0; i < neuronspi_uart_data_global->p_count; i++) {
+ if (neuronspi_uart_data_global->p[i].dev_index == d_data->neuron_index) {
+ kthread_queue_work(&neuronspi_uart_data_global->kworker, &neuronspi_uart_data_global->p[i].irq_work);
}
}
spin_unlock_irqrestore(neuronspi_probe_spinlock, flags);
if (!n_spi)
return -ENOMEM;
- printk(KERN_INFO "UNIPISPI: Probe Started\n");
- if (n_spi == NULL || spi == NULL) {
+ unipi_spi_trace(KERN_INFO "UNIPISPI: Probe Started\n");
+ if (spi == NULL) {
+ kfree(n_spi);
return -8;
}
- unipi_spi_trace(KERN_DEBUG "UNIPISPI: Chip Max Hz-%d\n",spi->master->max_speed_hz);
/* Setup SPI bus */
spi->bits_per_word = 8;
- spi->mode = spi->mode ? spi->mode : SPI_MODE_0;
+ spi->mode = spi->mode ? spi->mode : SPI_MODE_0;
spi->max_speed_hz = spi->max_speed_hz ? spi->max_speed_hz : 12000000;
ret = spi_setup(spi);
+ if (ret) {
+ kfree(n_spi);
+ return ret;
+ }
+
n_spi->neuron_index = spi->chip_select - 1;
n_spi->reserved_device = 0;
platform_device_add(neuron_plc_dev);
}
- if (ret)
- return ret;
- unipi_spi_trace(KERN_DEBUG "UNIPISPI: Chip Max Hz-%d %d\n", spi->master->max_speed_hz, spi->max_speed_hz);
+ unipi_spi_trace(KERN_DEBUG "UNIPISPI: CS: %d, Chip Max Hz-%d %d\n", spi->chip_select, spi->master->max_speed_hz, spi->max_speed_hz);
if (spi->dev.of_node) {
const struct of_device_id *of_id =
of_match_device(neuronspi_id_match, &spi->dev);
n_spi->ideal_frequency = NEURONSPI_COMMON_FREQ;
for (i = 0; i < NEURONSPI_SLOWER_MODELS_LEN; i++) {
if (NEURONSPI_SLOWER_MODELS[i] == (n_spi->first_probe_reply[19-6] << 8 | n_spi->first_probe_reply[18-6])) {
- n_spi->slower_model = 1;
+ //n_spi->slower_model = 1;
n_spi->ideal_frequency = NEURONSPI_SLOWER_FREQ;
}
}
}
}
-
- if (uart_count && neuronspi_uart == NULL) { // Register UART if not registered
- neuronspi_uart = kzalloc(sizeof(struct uart_driver), GFP_ATOMIC);
- neuronspi_uart->owner = THIS_MODULE;
- neuronspi_uart->dev_name = "ttyNS";
- neuronspi_uart->driver_name = "ttyNS";
- neuronspi_uart->nr = NEURONSPI_MAX_UART;
- ret = uart_register_driver(neuronspi_uart);
- if (ret) {
- printk(KERN_ERR "UNIPISPI: Failed to register the neuronspi uart driver, ERR:%d\n", ret);
- } else {
- unipi_spi_trace(KERN_DEBUG "UNIPISPI: UART driver registered successfully!\n");
-
- }
- if (neuronspi_uart_glob_data != NULL) {
- printk(KERN_ERR "UNIPISPI: Uart data already allocated!\n");
- } else {
- neuronspi_uart_glob_data = kzalloc(sizeof(struct neuronspi_uart_data), GFP_ATOMIC);
- unipi_spi_trace(KERN_DEBUG "UNIPISPI: UART driver data allocated successfully!\n");
-
- }
-
- }
- if (neuronspi_uart_glob_data != NULL) {
- n_spi->uart_data = neuronspi_uart_glob_data;
- }
n_spi->char_driver = &neuronspi_cdrv;
- if (uart_count) {
- n_spi->serial_driver = neuronspi_uart;
- } else {
- n_spi->serial_driver = NULL;
- }
- n_spi->uart_count = uart_count;
- unipi_spi_trace(KERN_DEBUG "UNIPISPI: CHIP SELECT %d\n", spi->chip_select);
spin_lock_irqsave(neuronspi_probe_spinlock, flags);
neuronspi_s_dev[n_spi->neuron_index] = spi;
- spi_set_drvdata(neuronspi_s_dev[n_spi->neuron_index], n_spi);
+ spi_set_drvdata(spi, n_spi);
+
+ //spi_set_drvdata(neuronspi_s_dev[n_spi->neuron_index], n_spi);
if (neuronspi_probe_count == NEURONSPI_MAX_DEVS) {
neuronspi_model_id = neuronspi_find_model_id(neuronspi_probe_count);
}
}
}
+ n_spi->uart_count_to_probe = uart_count;
if (uart_count) {
- unipi_spi_trace(KERN_DEBUG "UNIPISPI: UART registration 1\n");
-
- n_spi->uart_buf = kzalloc(NEURONSPI_FIFO_SIZE, GFP_ATOMIC);
- neuronspi_uart_probe(spi, n_spi->neuron_index);
- //unipi_spi_trace(KERN_DEBUG "UNIPISPI: UART PROBE MCTRL:%d\n", neuronspi_spi_uart_get_cflag(spi, 0));
+ //n_spi->uart_buf = kzalloc(NEURONSPI_FIFO_SIZE, GFP_ATOMIC);
+ if (neuronspi_uart_driver_global != NULL) {
+ // Normalne se registrace portu udela az po inicializaci unipispi driveru. (Na konci __init__)
+ // Opravit proceduru probe !!!
+ unipi_spi_trace(KERN_DEBUG "UNIPISPI: UART registration\n");
+
+ neuronspi_uart_probe(spi, n_spi);
+ //n_spi->uart_count = uart_count;
+ } else {
+ unipi_spi_trace(KERN_DEBUG "UNIPISPI: Neuronspi uart driver not registered yet. Uart port add later.\n");
+ }
}
- unipi_spi_trace(KERN_DEBUG "UNIPISPI: UART registration\n");
neuronspi_spi_set_irqs(spi, 0x5);
for (i = 0; i < NEURONSPI_NO_INTERRUPT_MODELS_LEN; i++) {
n_spi->sec_ao_driver = NULL;
}
printk(KERN_INFO "UNIPISPI: IIO DRIVER UNREGISTERED\n");
- if (n_spi->uart_buf) {
- kfree(n_spi->uart_buf);
- n_spi->uart_buf = NULL;
- }
+ //if (n_spi->uart_buf) {
+ // kfree(n_spi->uart_buf);
+ // n_spi->uart_buf = NULL;
+ //}
printk(KERN_INFO "UNIPISPI: SPI/UART DRIVER UNREGISTERED\n");
if (n_spi->board_device) {
platform_set_drvdata(n_spi->board_device, 0);
static s32 __init neuronspi_init(void)
{
s32 ret = 0;
+
+ //neuronspi_uart_driver_init();
+
neuronspi_probe_spinlock = kzalloc(sizeof(struct spinlock), GFP_ATOMIC);
spin_lock_init(neuronspi_probe_spinlock);
mutex_init(&neuronspi_master_mutex);
mutex_init(&unipi_inv_speed_mutex);
+ // clear global neuron spi devices list
memset(&neuronspi_s_dev, 0, sizeof(neuronspi_s_dev));
ret = spi_register_driver(&neuronspi_spi_driver);
if (ret < 0) {
if (neuronspi_invalidate_thread != NULL) {
wake_up_process(neuronspi_invalidate_thread);
}
+
+ neuronspi_uart_driver_init();
+ neuronspi_uart_probe_all();
+
unipi_tty_init();
return ret;
}
kthread_stop(neuronspi_invalidate_thread);
}
char_unregister_driver();
- if (neuronspi_uart) {
- neuronspi_uart_remove(neuronspi_uart_glob_data);
- uart_unregister_driver(neuronspi_uart);
- kfree(neuronspi_uart);
- kfree(neuronspi_uart_glob_data);
- }
+ neuronspi_uart_driver_exit();
spi_unregister_driver(&neuronspi_spi_driver);
if (neuron_plc_dev) {
platform_device_unregister(neuron_plc_dev);
#include "unipi_spi.h"
#if NEURONSPI_DETAILED_DEBUG > 2
-# define unipi_uart_trace_2(f, args...) printk(f, ##args)
+# define unipi_uart_trace_2(f, args...) printk(KERN_INFO "UNIPIUART: " f, ##args)
#else
# define unipi_uart_trace_2(f, args...)
#endif
#if NEURONSPI_DETAILED_DEBUG > 1
-# define unipi_uart_trace_1(f, args...) printk(f, ##args)
+# define unipi_uart_trace_1(f, args...) printk(KERN_INFO "UNIPIUART: " f, ##args)
#else
# define unipi_uart_trace_1(f, args...)
#endif
#if NEURONSPI_DETAILED_DEBUG > 0
-# define unipi_uart_trace(f, args...) printk(f, ##args)
+# define unipi_uart_trace(f, args...) printk(KERN_INFO "UNIPIUART: " f, ##args)
#else
# define unipi_uart_trace(f, args...)
#endif
* Data Definitions *
********************/
-struct neuronspi_uart_data* neuronspi_uart_glob_data;
-unsigned long neuronspi_lines;
-struct uart_driver* neuronspi_uart;
+struct neuronspi_uart_data* neuronspi_uart_data_global = NULL;
+struct uart_driver* neuronspi_uart_driver_global = NULL;
+//unsigned long neuronspi_lines;
static struct sched_param neuronspi_sched_param = { .sched_priority = MAX_RT_PRIO / 2 };
+void neuronspi_uart_update_timeout(struct neuronspi_port *n_port, unsigned int cflag, unsigned int baud);
+
/********************
* Static Functions *
********************/
-void neuronspi_uart_update_timeout(struct neuronspi_port *n_port, unsigned int cflag, unsigned int baud);
-void neuronspi_uart_set_cflag(struct spi_device* spi_dev, u8 port, u32 to)
+#define NEURONSPI_UART_CFLAGS_REGISTER 500
+#define NEURONSPI_UART_IFLAGS_REGISTER 502
+#define NEURONSPI_UART_LDISC_REGISTER 503
+#define NEURONSPI_UART_TIMEOUT_REGISTER 504
+//#define NEURONSPI_UART_FIFO_REGISTER 505
+
+static inline int port_to_uartregs(u8 port, u16 reg)
{
- unipispi_modbus_write_u32(spi_dev, 500, to);
- unipi_uart_trace(KERN_INFO "UNIPI_UART: TERMIOS cflag SET, Dev-CS:%d, to:%08x\n", spi_dev->chip_select, to);
+ return reg + ((port==0) ? 0 : (10*(port+1)));
}
+static void neuronspi_uart_set_cflag(struct neuronspi_port *n_port, u32 to)
+{
+ struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
+ unipispi_modbus_write_u32(spi, port_to_uartregs(n_port->dev_port, NEURONSPI_UART_CFLAGS_REGISTER), to);
+ unipi_uart_trace("ttyNS%d Set cflag: %08x\n", n_port->port.line, to);
+}
-static void neuronspi_uart_set_iflags(struct uart_port *port, int to)
+
+static void neuronspi_uart_set_iflags(struct neuronspi_port *n_port, int to)
{
- struct neuronspi_port *n_port;
- struct spi_device *spi;
- n_port = to_neuronspi_port(port, port);
- spi = neuronspi_s_dev[n_port->dev_index];
- //n_spi = spi_get_drvdata(spi);
- unipi_uart_trace(KERN_INFO "UNIPI_UART: TERMIOS iflag SET: %s\n", to ? "PARMRK" : "0");
+ struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
+ unipi_uart_trace("ttyNS%d Set iflag: %s\n", n_port->port.line, (to & PARMRK)? "PARMRK" : "0");
- unipispi_modbus_write_register(spi, NEURONSPI_UART_IFLAGS_REGISTER, to);
-/*
- write_length = neuronspi_spi_compose_single_register_write(NEURONSPI_UART_IFLAGS_REGISTER, &inp_buf, &outp_buf, to);
- neuronspi___spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 25, 1, 0);
- kfree(inp_buf);
- kfree(outp_buf); */
+ unipispi_modbus_write_register(spi, port_to_uartregs(n_port->dev_port, NEURONSPI_UART_IFLAGS_REGISTER), to);
+}
+
+
+/*******************
+ * Empty functions *
+ *******************/
+
+void neuronspi_uart_power(struct uart_port *port, s32 on)
+{
+ /* Do nothing */
+}
+void neuronspi_uart_set_mctrl(struct uart_port *port, u32 mctrl)
+{
+ /* Do nothing */
+}
+void neuronspi_uart_break_ctl(struct uart_port *port, int break_state)
+{
+ /* Do nothing */
+}
+void neuronspi_uart_null_void(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+void neuronspi_uart_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_NEURONSPI;
+ }
+}
+
+s32 neuronspi_uart_verify_port(struct uart_port *port, struct serial_struct *s)
+{
+ if ((s->type != PORT_UNKNOWN) && (s->type != PORT_NEURONSPI))
+ return -EINVAL;
+ if (s->irq != port->irq)
+ return -EINVAL;
+
+ return 0;
+}
+
+void neuronspi_uart_pm(struct uart_port *port, u32 state, u32 oldstate)
+{
+ neuronspi_uart_power(port, (state == UART_PM_STATE_ON) ? 1 : 0);
}
/************************
u32 neuronspi_spi_uart_get_cflag(struct spi_device* spi_dev, u8 port)
{
u32 value;
- unipispi_modbus_read_u32(spi_dev, 500, &value);
- unipi_uart_trace_1(KERN_INFO "UNIPI_UART: SPI TERMIOS cflag GET, Dev-CS:%d, val:%08x\n", spi_dev->chip_select, value);
+ unipispi_modbus_read_u32(spi_dev, port_to_uartregs(port, NEURONSPI_UART_CFLAGS_REGISTER), &value);
+ unipi_uart_trace_1("Get cflag val:%08x\n", value);
return value;
}
-
void neuronspi_uart_set_ldisc(struct uart_port *port, struct ktermios *kterm)
{
- struct neuronspi_port *n_port;
- struct spi_device *spi;
- n_port = to_neuronspi_port(port, port);
- spi = neuronspi_s_dev[n_port->dev_index];
- unipi_uart_trace(KERN_INFO "UNIPI_UART: TERMIOS ldisc SET: dsc=%d\n", kterm->c_line);
+ struct neuronspi_port *n_port = to_neuronspi_port(port, port);
+ struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
- unipispi_modbus_write_register(spi, NEURONSPI_UART_LDISC_REGISTER, kterm->c_line);
+ unipi_uart_trace("ttyNS%d Set ldisc: dsc=%d\n", port->line, kterm->c_line);
+ /* NEURONSPI_UART_LDISC_REGISTER + (10*port) + ((port==0) ? 0 : 10) */
+ unipispi_modbus_write_register(spi, port_to_uartregs(n_port->dev_port, NEURONSPI_UART_LDISC_REGISTER), kterm->c_line);
}
-void neuronspi_uart_tx_proc(struct kthread_work *ws)
-{
- struct neuronspi_port *port = to_neuronspi_port(ws, tx_work);
-
- if ((port->port.rs485.flags & SER_RS485_ENABLED) &&
- (port->port.rs485.delay_rts_before_send > 0)) {
- msleep(port->port.rs485.delay_rts_before_send);
- }
- neuronspi_uart_handle_tx(port);
+void neuronspi_uart_flush_buffer(struct uart_port* port)
+{
+ //port->lock taken, This call must not sleep
+ // ToDo :
+ unipi_uart_trace("ttyNS%d Flush buffer\n", port->line);
}
u32 neuronspi_uart_tx_empty(struct uart_port *port)
{
- unipi_uart_trace(KERN_INFO "UNIPISPI: UART TX Empty\n");
- return TIOCSER_TEMT;
+ struct neuronspi_port *n_port = to_neuronspi_port(port, port);
+ unipi_uart_trace("ttyNS%d Tx empty: %d\n", port->line, n_port->tx_fifo_len==0);
+ return (n_port->tx_fifo_len==0) ? TIOCSER_TEMT : 0;
}
u32 neuronspi_uart_get_mctrl(struct uart_port *port)
{
- unipi_uart_trace(KERN_DEBUG "UNIPISPI: UART MCTRL Get\n");
+ unipi_uart_trace_1("ttyNS%d Get mctrl\n", port->line);
return TIOCM_DSR | TIOCM_CAR;
}
int neuronspi_uart_ioctl (struct uart_port *port, unsigned int ioctl_code, unsigned long ioctl_arg)
{
u32 value;
- struct neuronspi_port *n_port;
- struct spi_device *spi;
- struct neuronspi_driver_data *n_spi;
- n_port = to_neuronspi_port(port, port);
- spi = neuronspi_s_dev[n_port->dev_index];
- n_spi = spi_get_drvdata(spi);
+ struct neuronspi_port *n_port = to_neuronspi_port(port, port);
+ struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
+ //struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+
switch (ioctl_code) {
case TIOCSETD: {
- unipi_uart_trace(KERN_INFO "UNIPISPI: IOCTL TIOCSETD (processed via set_termios)\n");
+ unipi_uart_trace("ttyNS%d Ioctl TIOCSETD (processed via set_termios)\n", port->line);
return 1;
}
case 0x5481: {
value = ((ioctl_arg * 1000000) / n_port->baud);
if (value > 0xffff) value = 0xffff;
- unipi_uart_trace(KERN_INFO "UNIPISPI: IOCTL 0x5481 timeout=%d\n", value);
- unipispi_modbus_write_register(spi, NEURONSPI_UART_TIMEOUT_REGISTER, value);
+ unipi_uart_trace("ttyNS%d Ioctl 0x5481 set timeout=%d\n", port->line, value);
+ unipispi_modbus_write_register(spi, port_to_uartregs(n_port->dev_port, NEURONSPI_UART_TIMEOUT_REGISTER), value);
return 0;
}
case 0x5480: {
value = (ioctl_arg * 10);
if (value > 0xffff) value = 0xffff;
- unipi_uart_trace(KERN_INFO "UNIPISPI: IOCTL 0x5480 timeout=%d\n", value);
- unipispi_modbus_write_register(spi, NEURONSPI_UART_TIMEOUT_REGISTER, value);
+ unipi_uart_trace("ttyNS%d Ioctl 0x5480 set timeout=%d\n", port->line, value);
+ unipispi_modbus_write_register(spi, port_to_uartregs(n_port->dev_port, NEURONSPI_UART_TIMEOUT_REGISTER), value);
return 0;
}
default: {
n_port = to_neuronspi_port(port, port);
if (old) {
- unipi_uart_trace(KERN_INFO "UNIPI_UART: Termios port:%d old:0x%04x %04x %04x %04x ldisc:%d", port->line,\
+ unipi_uart_trace("ttyNS%d Termios old:0x%04x %04x %04x %04x ldisc:%d", port->line,\
old->c_cflag, old->c_iflag, \
old->c_oflag, old->c_lflag, old->c_line);
}
if (termios) {
- unipi_uart_trace(KERN_INFO "UNIPI_UART: Termios port:%d new:0x%04x %04x %04x %04x ldisc:%d", port->line,\
+ unipi_uart_trace("ttyNS%d Termios new:0x%04x %04x %04x %04x ldisc:%d", port->line,\
termios->c_cflag, termios->c_iflag, \
termios->c_oflag, termios->c_lflag, termios->c_line);
}
- neuronspi_uart_set_cflag(neuronspi_s_dev[n_port->dev_index], n_port->dev_port, termios->c_cflag);
+ neuronspi_uart_set_cflag(n_port, termios->c_cflag);
if (termios && (!old || ((old->c_iflag & PARMRK) != (termios->c_iflag & PARMRK)))) {
- neuronspi_uart_set_iflags(port, termios->c_iflag);
+ neuronspi_uart_set_iflags(n_port, termios->c_iflag);
}
if (termios && !old) {
// set line discipline only in case of new setting - Mervis behavior
if (cflag & PARENB)
bits++;
/*
- * time in microseconds for sending one character
+ * time in nanoseconds for sending one character
*/
- n_port->one_char_usec = (1000000 * bits) / baud;
+ n_port->one_char_nsec = (((long)1000000 * bits) / baud)*1000;
}
const char* neuronspi_uart_type(struct uart_port *port)
s32 neuronspi_uart_request_port(struct uart_port *port)
{
- unipi_uart_trace(KERN_DEBUG "UNIPISPI: UART requested port %d\n", port->line);
+ unipi_uart_trace("ttyNS%d Request port\n", port->line);
return 0;
}
-void neuronspi_uart_fifo_read(struct uart_port *port, u32 rxlen)
+
+void neuronspi_uart_start_tx(struct uart_port *port)
{
- s32 i;
- struct neuronspi_port *s = to_neuronspi_port(port,port);
- struct neuronspi_driver_data *d_data = spi_get_drvdata(neuronspi_s_dev[s->dev_index]);
- unipi_uart_trace_1(KERN_INFO "UNIPISPI: FIFO Read len:%d\n", rxlen);
+ struct neuronspi_port *n_port = to_neuronspi_port(port,port);
+ unipi_uart_trace("Start TX\n");
- memcpy(s->buf, d_data->uart_buf, rxlen);
- for (i = 0; i < rxlen; i++) {
- unipi_uart_trace_2(KERN_INFO "UNIPISPI: UART Char Read: %x\n", d_data->uart_buf[i]);
+ if (!kthread_queue_work(&neuronspi_uart_data_global->kworker, &n_port->tx_work)) {
+ //unipi_uart_trace("TX WORK OVERFLOW\n");
}
}
-int static neuronspi_uart_get_charcount(struct neuronspi_port *port)
+// set port->tx_fifo_len by reading modbus register
+// return 0 if success, 1 if couldnt read register - fifo len has old value
+int static neuronspi_uart_read_tx_fifo_len(struct neuronspi_port *port)
{
- u16 read_length16;
+ u16 read_length16 = - 1;
struct spi_device *spi;
- struct neuronspi_driver_data *n_spi;
- int ret = 0;
+ int ret = 1;
- spi = neuronspi_s_dev[port->dev_index];
- n_spi = spi_get_drvdata(spi);
- if (n_spi && n_spi->combination_id != 0xFF && n_spi->reg_map && n_spi->regstart_table->uart_queue_reg) {
- if (unipispi_modbus_read_register(spi, n_spi->regstart_table->uart_queue_reg, &read_length16) == 0) {
- ret = read_length16;
+ if (port->tx_fifo_reg) {
+ spi = neuronspi_s_dev[port->dev_index];
+ if (unipispi_modbus_read_register(spi, port->tx_fifo_reg, &read_length16) == 0) {
+ port->tx_fifo_len = read_length16;
+ ret = 0;
}
- }
- unipi_uart_trace(KERN_INFO "UNIPI_UART: GET Char count:%d\n", ret);
+ } else {
+ // unknown port!
+ port->tx_fifo_len = 0;
+ ret = 0;
+ }
+ unipi_uart_trace("ttyNS%d Get tx fifo len:%d\n", port->port.line, read_length16);
return ret;
}
+/*
void neuronspi_uart_fifo_write(struct neuronspi_port *n_port, u8 to_send)
{
- int i, in_queue, need;
+ int in_queue, need;
+
+ unipi_uart_trace("FIFO Write to_send:%d %16ph\n", to_send, n_port->tx_buf);
+ //unipi_uart_trace_2(KERN_INFO "FIFO Write to_send:%d %16ph\n", to_send, n_port->tx_buf);
- unipi_uart_trace_2(KERN_INFO "UNIPISPI: FIFO Write to_send:%d\n", to_send);
- for (i = 0; i < to_send; i++) {
- unipi_uart_trace_2(KERN_INFO "UNIPISPI: UART Char Send: %x\n", n_port->buf[i]);
- }
do {
in_queue = neuronspi_uart_get_charcount(n_port);
need = (int)to_send - (NEURONSPI_FIFO_SIZE - in_queue);
if (need <= 0) break;
usleep_range(need * n_port->one_char_usec, (need + NEURONSPI_FIFO_SIZE/4) * n_port->one_char_usec);
} while(1);
- neuronspi_spi_uart_write(neuronspi_s_dev[n_port->dev_index], n_port->buf, to_send, n_port->dev_port);
+ neuronspi_spi_uart_write(neuronspi_s_dev[n_port->dev_index], n_port->tx_buf, to_send, n_port->dev_port);
}
+*/
+/*
s32 neuronspi_uart_alloc_line(void)
{
s32 i;
return i;
}
+*/
+
+void neuronspi_rx_queue_clear(struct neuronspi_port *port, u8 data)
+{
+ port->rx_qlen_secondary = 0;
+}
+
+int neuronspi_rx_queue_add(struct neuronspi_port *port, u8 data)
+{
+ unsigned long flags;
+ int ret = 1;
+ spin_lock_irqsave(&port->rx_queue_lock, flags);
+ if (port->rx_qlen_primary < MAX_RX_QUEUE_LEN) {
+ port->rx_queue_primary[port->rx_qlen_primary++] = data;
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&port->rx_queue_lock, flags);
+ return ret;
+}
+
+void neuronspi_rx_queue_swap(struct neuronspi_port *port)
+{
+ unsigned long flags;
+ u8* x;
+
+ spin_lock_irqsave(&port->rx_queue_lock, flags);
+ x = port->rx_queue_primary;
+ port->rx_queue_primary = port->rx_queue_secondary;
+ port->rx_queue_secondary = x;
+ port->rx_qlen_secondary = port->rx_qlen_primary;
+ port->rx_qlen_primary = 0;
+ spin_unlock_irqrestore(&port->rx_queue_lock, flags);
+}
-void neuronspi_uart_handle_rx(struct neuronspi_port *port, u32 rxlen, u32 iir)
+static void neuronspi_uart_handle_rx(struct neuronspi_port *port, int rxlen, u8* pbuf)
{
unsigned long flags;
u32 ch, flag, bytes_read, i;
+
+ unipi_uart_trace("ttyNS%d Insert Chars (%d): %16ph\n", port->port.line, rxlen, pbuf);
+
while (rxlen) {
- neuronspi_uart_fifo_read(&port->port, rxlen);
+ //neuronspi_uart_fifo_read(&port->port, rxlen);
bytes_read = rxlen;
spin_lock_irqsave(&port->port.lock, flags);
port->port.icount.rx++;
flag = TTY_NORMAL;
for (i = 0; i < bytes_read; ++i) {
- unipi_uart_trace(KERN_INFO "UNIPISPI: UART Insert Char:%x\n", port->buf[i]);
- ch = port->buf[i];
+ ch = *pbuf;
+ pbuf++;
if (uart_handle_sysrq_char(port, ch))
continue;
tty_flip_buffer_push(&port->port.state->port);
}
+
+#define start_tx_timer(port, lowlimit, delta) hrtimer_start_range_ns(&port->tx_timer, lowlimit * port->one_char_nsec, delta*port->one_char_nsec, HRTIMER_MODE_REL)
+
+#define MAX_TXLEN (NEURONSPI_FIFO_SIZE >> 1)
+
void neuronspi_uart_handle_tx(struct neuronspi_port *port)
{
- s32 max_txlen, to_send, to_send_packet;//, i;
+ int to_send, to_send_packet, ret, need;
+ u8 tx_buf[MAX_TXLEN + 16];
unsigned long flags;
struct spi_device *spi;
struct neuronspi_driver_data *d_data;
port->port.icount.tx++;
spin_unlock_irqrestore(&port->port.lock, flags);
port->port.x_char = 0;
+ kthread_queue_work(&neuronspi_uart_data_global->kworker, &port->tx_work);
return;
}
- //spin_lock_irqsave(&port->port.lock, flags);
xmit = &port->port.state->xmit;
- //spin_unlock_irqrestore(&port->port.lock, flags);
spin_lock_irqsave(&port->port.lock, flags);
if (uart_circ_empty(xmit) || uart_tx_stopped(&port->port)) {
spin_unlock_irqrestore(&port->port.lock, flags);
+ // check tx_fifo status
+ if (port->tx_fifo_len) {
+ ret = neuronspi_uart_read_tx_fifo_len(port);
+ if (ret || port->tx_fifo_len) {
+ // set timer to check tx_empty
+ unipi_uart_trace("ttyNS%d Handle TX. Start timer=%llu", port->port.line, port->tx_fifo_len * port->one_char_nsec);
+ start_tx_timer(port, port->tx_fifo_len, 2);
+ //hrtimer_start_range_ns(&port->tx_timer, port->tx_fifo_len * port->one_char_nsec, 2*port->one_char_nsec, HRTIMER_MODE_REL);
+ }
+ }
return;
}
spin_unlock_irqrestore(&port->port.lock, flags);
- /* Get length of data pending in circular buffer */
+ // Get length of data pending in circular buffer
to_send = uart_circ_chars_pending(xmit);
- unipi_uart_trace(KERN_INFO "UNIPISPI: UART_HANDLE_TX A, to_send:%d", to_send);
+ unipi_uart_trace("ttyNS%d Handle TX. tty->pending=%d", port->port.line, to_send);
if (likely(to_send)) {
- /* Limit to size of (TX FIFO / 2) */
- max_txlen = NEURONSPI_FIFO_SIZE >> 1;
- while (to_send > 0) {
- to_send_packet = (to_send > max_txlen) ? max_txlen : to_send;
-
- /* Add data to send */
- port->port.icount.tx += to_send_packet;
- new_tail = (xmit->tail + to_send_packet) & (UART_XMIT_SIZE - 1);
- if (new_tail <= xmit->tail) {
- memcpy(port->buf, xmit->buf+xmit->tail, UART_XMIT_SIZE - xmit->tail);
- memcpy(port->buf+UART_XMIT_SIZE - xmit->tail, xmit->buf, new_tail);
- } else {
- memcpy(port->buf, xmit->buf+xmit->tail, to_send_packet);
- }
- xmit->tail = new_tail;
-
- /* Convert to linear buffer */
- //for (i = 0; i < to_send_packet; ++i) {
- // port->buf[i] = xmit->buf[xmit->tail];
- // xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- //}
- unipi_uart_trace(KERN_INFO "UNIPISPI: UART_HANDLE_TX B, to_send:%d", to_send_packet);
- neuronspi_uart_fifo_write(port, to_send_packet);
-
- spin_lock_irqsave(&port->port.lock, flags);
- to_send = uart_circ_chars_pending(xmit);
- if (to_send < WAKEUP_CHARS) {
- uart_write_wakeup(&port->port);
- }
- spin_unlock_irqrestore(&port->port.lock, flags);
+
+ // Limit to size of (TX FIFO / 2)
+ to_send_packet = (to_send > MAX_TXLEN) ? MAX_TXLEN : to_send;
+ if (port->tx_fifo_len + to_send_packet > NEURONSPI_FIFO_SIZE) {
+ // read current tx_fifo_len
+ ret = neuronspi_uart_read_tx_fifo_len(port);
+ need = to_send_packet - (NEURONSPI_FIFO_SIZE - port->tx_fifo_len);
+ if ((ret != 0) || (need > 0)) {
+ // reschedule work with pause
+ start_tx_timer(port, need, NEURONSPI_FIFO_SIZE/4);
+ //hrtimer_start_range_ns(&port->tx_timer, need * port->one_char_nsec, NEURONSPI_FIFO_SIZE/4*port->one_char_nsec, HRTIMER_MODE_REL);
+ //kthread_queue_work(&neuronspi_uart_data_global->kworker, &port->tx_work);
+ //usleep_range(need * port->one_char_usec, (need + NEURONSPI_FIFO_SIZE/4) * port->one_char_usec);
+ return;
+ }
+ }
+
+ /* Read data from tty buffer and send it to spi */
+ spin_lock_irqsave(&port->port.lock, flags);
+ port->port.icount.tx += to_send_packet;
+ new_tail = (xmit->tail + to_send_packet) & (UART_XMIT_SIZE - 1);
+ if (new_tail <= xmit->tail) {
+ memcpy(tx_buf, xmit->buf+xmit->tail, UART_XMIT_SIZE - xmit->tail);
+ memcpy(tx_buf+UART_XMIT_SIZE - xmit->tail, xmit->buf, new_tail);
+ } else {
+ memcpy(tx_buf, xmit->buf+xmit->tail, to_send_packet);
+ }
+ xmit->tail = new_tail;
+
+ /*
+ for (i = 0; i < to_send_packet; ++i) {
+ port->tx_buf[i] = xmit->buf[xmit->tail];
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ }*/
+ spin_unlock_irqrestore(&port->port.lock, flags);
+
+ unipi_uart_trace("ttyNS%d Handle TX Send: %d %16ph\n", port->port.line, to_send_packet, tx_buf);
+ neuronspi_spi_uart_write(spi, tx_buf, to_send_packet, port->dev_port);
+ //neuronspi_uart_fifo_write(port, to_send_packet);
+ port->tx_fifo_len += to_send_packet;
+
+ spin_lock_irqsave(&port->port.lock, flags);
+ to_send = uart_circ_chars_pending(xmit);
+ if (to_send < WAKEUP_CHARS) {
+ uart_write_wakeup(&port->port);
}
+ spin_unlock_irqrestore(&port->port.lock, flags);
+ if (to_send) {
+ // reschedule work
+ kthread_queue_work(&neuronspi_uart_data_global->kworker, &port->tx_work);
+ } else {
+ // set timer to check tx_empty
+ unipi_uart_trace("ttyNS%d Handle TX. Start timer=%llu", port->port.line, to_send_packet * port->one_char_nsec);
+ start_tx_timer(port, to_send_packet, 2);
+ //hrtimer_start_range_ns(&port->tx_timer, to_send_packet * port->one_char_nsec, 2*port->one_char_nsec, HRTIMER_MODE_REL);
+ }
}
/*
spin_lock_irqsave(&port->port.lock, flags);
*/
}
-void neuronspi_uart_handle_irq(struct neuronspi_uart_data *uart_data, u32 portno)
-{
- struct neuronspi_port *n_port = &uart_data->p[portno];
- struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
- struct neuronspi_op_buffer recv_buf;
- neuronspi_spi_send_const_op(spi, &UNIPISPI_IDLE_MESSAGE, &recv_buf, 0, NEURONSPI_DEFAULT_FREQ, 25);
-}
-
-void neuronspi_uart_ist(struct kthread_work *ws)
+// callback of tx_timer. Schedule port->tx_work
+static enum hrtimer_restart neuronspi_uart_timer_func(struct hrtimer *timer)
{
- struct neuronspi_port *p = to_neuronspi_port(ws, irq_work);
- neuronspi_uart_handle_irq(p->parent, p->line);
-}
+ struct neuronspi_port* n_port = ((container_of((timer), struct neuronspi_port, tx_timer)));
-void neuronspi_uart_config_port(struct uart_port *port, int flags)
-{
- if (flags & UART_CONFIG_TYPE) {
- port->type = PORT_NEURONSPI;
- }
+ kthread_queue_work(&neuronspi_uart_data_global->kworker, &n_port->tx_work);
+ return HRTIMER_NORESTART;
}
-s32 neuronspi_uart_verify_port(struct uart_port *port,
- struct serial_struct *s)
-{
- if ((s->type != PORT_UNKNOWN) && (s->type != PORT_NEURONSPI))
- return -EINVAL;
- if (s->irq != port->irq)
- return -EINVAL;
- return 0;
-}
-
-void neuronspi_uart_pm(struct uart_port *port, u32 state, u32 oldstate)
-{
- neuronspi_uart_power(port, (state == UART_PM_STATE_ON) ? 1 : 0);
-}
-
-s32 neuronspi_uart_probe(struct spi_device* dev, u8 device_index)
+void neuronspi_uart_handle_irq(struct neuronspi_uart_data *uart_data, u32 portno)
{
- struct neuronspi_driver_data* driver_data = spi_get_drvdata(dev);
-
- s32 i, j, ret, new_uart_count;
- struct neuronspi_uart_data *uart_data = driver_data->uart_data;
-
- if (uart_data->p == NULL) {
- uart_data->p = kzalloc(sizeof(struct neuronspi_port[NEURONSPI_MAX_UART]), GFP_ATOMIC);
- for (i = 0; i < NEURONSPI_MAX_UART; i++) {
- uart_data->p[i].parent = uart_data;
- }
- unipi_uart_trace(KERN_DEBUG "UNIPISPI: Allocated port structure for %d potential UART devices", NEURONSPI_MAX_UART);
- }
-
- new_uart_count = driver_data->uart_count + uart_data->p_count;
-
- // Initialise port data
- for (i = uart_data->p_count; i < new_uart_count; i++) {
- uart_data->p[i].dev_index = device_index;
- uart_data->p[i].dev_port = i - uart_data->p_count;
- uart_data->p[i].line = i;
- uart_data->p[i].port.dev = &(dev->dev);
- uart_data->p[i].port.irq = dev->irq;
- uart_data->p[i].port.type = PORT_NEURONSPI;
- uart_data->p[i].port.fifosize = NEURONSPI_FIFO_SIZE*8;
- uart_data->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
- uart_data->p[i].port.iotype = UPIO_PORT;
- uart_data->p[i].port.uartclk = 9600;
- uart_data->p[i].port.rs485_config = neuronspi_uart_config_rs485;
- uart_data->p[i].port.ops = &neuronspi_uart_ops;
- uart_data->p[i].port.line = neuronspi_uart_alloc_line();
- spin_lock_init(&uart_data->p[i].port.lock);
- if (uart_data->p[i].port.line >= NEURONSPI_MAX_DEVS) {
- ret = -ENOMEM;
- }
- kthread_init_work(&(uart_data->p[i].tx_work), neuronspi_uart_tx_proc);
- kthread_init_work(&(uart_data->p[i].rx_work), neuronspi_uart_rx_proc);
- kthread_init_work(&(uart_data->p[i].irq_work), neuronspi_uart_ist);
- uart_add_one_port(driver_data->serial_driver, &uart_data->p[i].port);
- unipi_uart_trace(KERN_INFO "UNIPISPI: Added UART port %d\n", i);
- }
-
- // For ports on multiple SPI devices renumber the ports to correspond to SPI chip-select numbering
- if (uart_data->p_count) {
- // First remove all existing ports
- for (i = 0; i < new_uart_count; i++) {
- uart_remove_one_port(driver_data->serial_driver, &uart_data->p[i].port);
- clear_bit(uart_data->p[i].port.line, &neuronspi_lines);
- kthread_flush_worker(&uart_data->kworker);
- }
- // Now add the ports in the correct order
- for (i = 0; i < NEURONSPI_MAX_DEVS; i++) {
- if (neuronspi_s_dev[i] != NULL) {
- driver_data = spi_get_drvdata(neuronspi_s_dev[i]);
- unipi_uart_trace(KERN_DEBUG "UNIPISPI: Renumber not NULL %d UC:%d\n", i, driver_data->uart_count);
- if (driver_data->uart_count) {
- for (j = 0; j < new_uart_count; j++) {
- if (uart_data->p[j].dev_index == i) {
- uart_data->p[j].port.dev = &(neuronspi_s_dev[i]->dev);
- uart_data->p[j].port.irq = neuronspi_s_dev[i]->irq;
- uart_data->p[j].port.type = PORT_NEURONSPI;
- uart_data->p[j].port.fifosize = NEURONSPI_FIFO_SIZE;
- uart_data->p[j].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
- uart_data->p[j].port.iotype = UPIO_PORT;
- uart_data->p[j].port.uartclk = 9600;
- uart_data->p[j].port.rs485_config = neuronspi_uart_config_rs485;
- uart_data->p[j].port.ops = &neuronspi_uart_ops;
- uart_data->p[j].port.line = neuronspi_uart_alloc_line();
- uart_add_one_port(driver_data->serial_driver, &uart_data->p[j].port);
- unipi_uart_trace(KERN_DEBUG "UNIPISPI: Added UART port %d\n", j);
- }
- }
- }
- }
- }
- }
-
- uart_data->p_count = new_uart_count;
- if (uart_data->kworker_task == NULL) {
- unipi_uart_trace(KERN_DEBUG "UNIPISPI: KWorker Task is NULL\n");
-
- kthread_init_worker(&uart_data->kworker);
-
- uart_data->kworker_task = kthread_run(kthread_worker_fn, &uart_data->kworker,
- "neuronspi");
- if (IS_ERR(uart_data->kworker_task)) {
- ret = PTR_ERR(uart_data->kworker_task);
- }
- sched_setscheduler(uart_data->kworker_task, SCHED_FIFO, &neuronspi_sched_param);
- }
-
- unipi_uart_trace(KERN_DEBUG "UNIPISPI: UART PROBE MCTRL:%d\n", neuronspi_spi_uart_get_cflag(dev, 0));
- return ret;
+ struct neuronspi_port *n_port = &neuronspi_uart_data_global->p[portno];
+ struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
+ struct neuronspi_op_buffer recv_buf;
+ neuronspi_spi_send_const_op(spi, &UNIPISPI_IDLE_MESSAGE, &recv_buf, 0, NEURONSPI_DEFAULT_FREQ, 25);
}
-s32 neuronspi_uart_remove(struct neuronspi_uart_data *u_data)
+void neuronspi_uart_tx_proc(struct kthread_work *ws)
{
- struct neuronspi_driver_data *d_data;
- struct spi_device *spi;
- s32 i;
-
- for (i = 0; i < NEURONSPI_MAX_DEVS; i++) {
- if (!(neuronspi_s_dev[i] == NULL)) {
- spi = neuronspi_s_dev[i];
- d_data = spi_get_drvdata(spi);
- if (d_data->poll_thread != NULL) {
- kthread_stop(d_data->poll_thread);
- }
- }
- }
- for (i = 0; i < u_data->p_count; i++) {
- uart_remove_one_port(neuronspi_uart, &u_data->p[i].port);
- clear_bit(u_data->p[i].port.line, &neuronspi_lines);
- neuronspi_uart_power(&u_data->p[i].port, 0);
+ struct neuronspi_port *port = to_neuronspi_port(ws, tx_work);
+/*
+ if ((port->port.rs485.flags & SER_RS485_ENABLED) &&
+ (port->port.rs485.delay_rts_before_send > 0)) {
+ msleep(port->port.rs485.delay_rts_before_send);
}
-
- kthread_flush_worker(&u_data->kworker);
- return 0;
+*/
+ neuronspi_uart_handle_tx(port);
}
void neuronspi_uart_rx_proc(struct kthread_work *ws)
{
- s32 end_flag = 0;
- s32 read_count = 0;
struct neuronspi_port *n_port = to_neuronspi_port(ws, rx_work);
struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
- struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
- //u8 *send_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_ATOMIC);
u8 *recv_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_ATOMIC);
- mutex_lock(&neuronspi_master_mutex);
- read_count = d_data->uart_read;
- mutex_unlock(&neuronspi_master_mutex);
-
- while (!end_flag) {
- memset(recv_buf, 0, NEURONSPI_BUFFER_MAX);
- //neuronspi_spi_uart_read(spi, send_buf, recv_buf, read_count, n_port->dev_port);
- neuronspi_spi_uart_read(spi, recv_buf, read_count, n_port->dev_port);
- if (((recv_buf[0] == 0x65) || (recv_buf[0] == 0x68))) {
- if (recv_buf[1] > 0) {
- mutex_lock(&neuronspi_master_mutex);
- memcpy(&d_data->uart_buf[0], &recv_buf[4], recv_buf[1]);
- mutex_unlock(&neuronspi_master_mutex);
- neuronspi_uart_handle_rx(n_port, recv_buf[1], 1);
- }
- //mutex_lock(&neuronspi_master_mutex);
- if ((read_count == 0) && ( recv_buf[3] == 0)) {
- mutex_lock(&neuronspi_master_mutex);
- d_data->uart_read = 0;
- end_flag = 1;
- mutex_unlock(&neuronspi_master_mutex);
- } else {
- read_count = recv_buf[3];
- }
- //mutex_unlock(&neuronspi_master_mutex);
- } else { //if ((recv_buf[0]&0xfd) != 0x41) {
- mutex_lock(&neuronspi_master_mutex);
- d_data->uart_read = 0;
- end_flag = 1;
- mutex_unlock(&neuronspi_master_mutex);
- }
- }
+ if (n_port->rx_qlen_secondary) {
+ //send to tty and clear secondary queue
+ neuronspi_uart_handle_rx(n_port, n_port->rx_qlen_secondary, n_port->rx_queue_secondary);
+ n_port->rx_qlen_secondary = 0;
+ }
+
+ #if NEURONSPI_DETAILED_DEBUG > 0
+ memset(recv_buf, 0, NEURONSPI_BUFFER_MAX);
+ #endif
+
+ neuronspi_spi_uart_read(spi, recv_buf, n_port->rx_remain, n_port->dev_port);
+
+ if (recv_buf[0] == 0x65) {
+ if (n_port->rx_qlen_secondary) {
+ neuronspi_uart_handle_rx(n_port, n_port->rx_qlen_secondary, n_port->rx_queue_secondary);
+ n_port->rx_qlen_secondary = 0;
+ }
+ if (recv_buf[1] > 0) {
+ // send string to tty
+ neuronspi_uart_handle_rx(n_port, recv_buf[1], recv_buf+4);
+ }
+ }
+ neuronspi_rx_queue_swap(n_port);
+ if (n_port->rx_qlen_secondary) {
+ //send to tty and clear secondary queue
+ neuronspi_uart_handle_rx(n_port, n_port->rx_qlen_secondary, n_port->rx_queue_secondary);
+ n_port->rx_qlen_secondary = 0;
+ }
+
+ if (n_port->rx_remain > 0) {
+ kthread_queue_work(&neuronspi_uart_data_global->kworker, &n_port->rx_work);
+ }
kfree(recv_buf);
- //kfree(send_buf);
}
-void neuronspi_uart_start_tx(struct uart_port *port)
+void neuronspi_uart_ist(struct kthread_work *ws)
{
- struct neuronspi_port *n_port = to_neuronspi_port(port,port);
- unipi_uart_trace(KERN_INFO "UNIPISPI: Start TX\n");
- if (!kthread_queue_work(&n_port->parent->kworker, &n_port->tx_work)) {
- unipi_uart_trace(KERN_INFO "UNIPISPI: TX WORK OVERFLOW\n");
- }
+ struct neuronspi_port *port = to_neuronspi_port(ws, irq_work);
+ neuronspi_uart_handle_irq(neuronspi_uart_data_global, port->port.line);
}
+
s32 neuronspi_uart_poll(void *data)
{
struct neuronspi_driver_data *d_data = (struct neuronspi_driver_data*) data;
- struct neuronspi_uart_data *u_data;
+ //struct neuronspi_uart_data *u_data;
s32 i;
while (!kthread_should_stop()) {
usleep_range(2000,8000);
if (d_data->uart_count) {
- u_data = d_data->uart_data;
- for (i = 0; i < u_data->p_count; i++) {
- if (u_data->p[i].dev_index == d_data->neuron_index) {
- kthread_queue_work(&u_data->kworker, &u_data->p[i].irq_work);
+ //u_data = d_data->uart_data;
+ for (i = 0; i < neuronspi_uart_data_global->p_count; i++) {
+ if (neuronspi_uart_data_global->p[i].dev_index == d_data->neuron_index) {
+ kthread_queue_work(&neuronspi_uart_data_global->kworker, &neuronspi_uart_data_global->p[i].irq_work);
}
}
}
return 0;
}
-// Initialise the driver
+// Initialise the driver - called once on open
s32 neuronspi_uart_startup(struct uart_port *port)
{
struct neuronspi_port *n_port = to_neuronspi_port(port, port);
}
neuronspi_uart_power(port, 1);
// TODO: /* Reset FIFOs*/
- unipi_uart_trace(KERN_DEBUG "UNIPISPI: UART Startup\n");
+ unipi_uart_trace("ttyNS%d Startup\n", port->line);
return 0;
}
+
void neuronspi_uart_shutdown(struct uart_port *port)
{
+ unipi_uart_trace("ttyNS%d Shutdown\n", port->line);
neuronspi_uart_power(port, 0);
}
-/*******************
- * Empty functions *
- *******************/
-void neuronspi_uart_power(struct uart_port *port, s32 on)
+s32 neuronspi_uart_remove(struct neuronspi_uart_data *u_data)
{
- /* Do nothing */
+ struct neuronspi_driver_data *d_data;
+ struct spi_device *spi;
+ struct neuronspi_port *port;
+ int i;
+
+ for (i = 0; i < NEURONSPI_MAX_DEVS; i++) {
+ if (!(neuronspi_s_dev[i] == NULL)) {
+ spi = neuronspi_s_dev[i];
+ d_data = spi_get_drvdata(spi);
+ if (d_data->poll_thread != NULL) {
+ kthread_stop(d_data->poll_thread);
+ }
+ }
+ }
+ for (i = 0; i < u_data->p_count; i++) {
+ port = u_data->p + i;
+ hrtimer_cancel(&port->tx_timer);
+ uart_remove_one_port(neuronspi_uart_driver_global, &port->port);
+ neuronspi_uart_power(&port->port, 0);
+ kfree(port->rx_queue_primary);
+ kfree(port->rx_queue_secondary);
+ }
+
+ kthread_flush_worker(&u_data->kworker);
+ return 0;
}
-void neuronspi_uart_set_mctrl(struct uart_port *port, u32 mctrl)
+
+
+static const struct uart_ops neuronspi_uart_ops =
{
- /* Do nothing */
+ .tx_empty = neuronspi_uart_tx_empty,
+ .set_mctrl = neuronspi_uart_set_mctrl,
+ .get_mctrl = neuronspi_uart_get_mctrl,
+ .stop_tx = neuronspi_uart_null_void,
+ .start_tx = neuronspi_uart_start_tx,
+ .stop_rx = neuronspi_uart_null_void,
+ .flush_buffer = neuronspi_uart_flush_buffer,
+ .break_ctl = neuronspi_uart_break_ctl,
+ .startup = neuronspi_uart_startup,
+ .shutdown = neuronspi_uart_shutdown,
+ .set_termios = neuronspi_uart_set_termios,
+ .set_ldisc = neuronspi_uart_set_ldisc,
+ .type = neuronspi_uart_type,
+ .request_port = neuronspi_uart_request_port,
+ .release_port = neuronspi_uart_null_void,
+ .config_port = neuronspi_uart_config_port,
+ .verify_port = neuronspi_uart_verify_port,
+ .pm = neuronspi_uart_pm,
+ .ioctl = neuronspi_uart_ioctl,
+};
+
+
+int neuronspi_uart_probe(struct spi_device* spi, struct neuronspi_driver_data *n_spi)
+{
+ struct neuronspi_port* port;
+ int i, ret = 0;
+
+ if (n_spi->uart_count_to_probe) {
+ n_spi->uart_pindex = neuronspi_uart_data_global->p_count;
+ for (i=0; i<n_spi->uart_count_to_probe; i++) {
+ // port is pointer to item ->p[x]
+ port = neuronspi_uart_data_global->p + neuronspi_uart_data_global->p_count;
+
+ port->port.dev = &(spi->dev);
+ port->dev_index = n_spi->neuron_index;
+ port->dev_port = i; //neuronspi_uart_data_global->p_count;
+
+ //port->line = neuronspi_uart_data_global->p_count;
+ //port->port.line = neuronspi_uart_alloc_line(); // neuronspi_uart_data_global->p_count; Myslim, ze tam muze byt tohle
+ port->port.line = neuronspi_uart_data_global->p_count;
+ port->port.irq = spi->irq;
+ port->port.type = PORT_NEURONSPI;
+ port->port.fifosize = NEURONSPI_FIFO_SIZE*8;
+ port->port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
+ port->port.iotype = UPIO_PORT;
+ port->port.uartclk = 9600;
+ port->port.rs485_config = neuronspi_uart_config_rs485;
+ port->port.ops = &neuronspi_uart_ops;
+ spin_lock_init(&port->port.lock);
+
+ spin_lock_init(&port->rx_queue_lock);
+ port->rx_queue_primary = kzalloc(MAX_RX_QUEUE_LEN, GFP_ATOMIC); // missing dealloc
+ port->rx_queue_secondary = kzalloc(MAX_RX_QUEUE_LEN, GFP_ATOMIC); // missing dealloc
+
+ port->tx_fifo_len = 0x7fff; //set it to big number; invoke reading current value from Neuron
+ if (n_spi && n_spi->combination_id != 0xFF && n_spi->reg_map && n_spi->regstart_table->uart_queue_reg) {
+ port->tx_fifo_reg = n_spi->regstart_table->uart_queue_reg; // define modbus register
+ }
+
+ hrtimer_init(&port->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ port->tx_timer.function = neuronspi_uart_timer_func;
+
+ kthread_init_work(&(port->tx_work), neuronspi_uart_tx_proc);
+ kthread_init_work(&(port->rx_work), neuronspi_uart_rx_proc);
+ kthread_init_work(&(port->irq_work), neuronspi_uart_ist);
+ uart_add_one_port(neuronspi_uart_driver_global, &port->port);
+ //uart_add_one_port(driver_data->serial_driver, &uart_data->p[i].port);
+ printk(KERN_INFO "UNIPIUART: Add port ttyNS%d on UniPi Board spi%d:%d\n", neuronspi_uart_data_global->p_count, port->dev_index, port->dev_port);
+ unipi_uart_trace("Probe mctrl:%d\n", neuronspi_spi_uart_get_cflag(spi, i));
+
+ n_spi->uart_count++;
+
+ if (neuronspi_uart_data_global->p_count < NEURONSPI_MAX_UART) {
+ neuronspi_uart_data_global->p_count++;
+ } else {
+ printk(KERN_INFO "UNIPIUART: PROBE maximum UART devices reached!\n");
+ ret = 1;
+ break;
+ }
+ }
+ n_spi->uart_count_to_probe = 0;
+ }
+ return ret;
}
-void neuronspi_uart_break_ctl(struct uart_port *port, int break_state)
+
+int neuronspi_uart_probe_all(void)
{
- /* Do nothing */
+ struct spi_device* spi;
+ struct neuronspi_driver_data* n_spi;// = spi_get_drvdata(dev);
+ int si, ret=0;
+
+ for (si=0; si < NEURONSPI_MAX_DEVS; si++) {
+ spi = neuronspi_s_dev[si];
+ if (spi == NULL) {
+ //unipi_uart_trace("Probe si=%d empty slot\n", si);
+ continue;
+ }
+ n_spi = spi_get_drvdata(spi);
+ //unipi_uart_trace("Probe si=%d uart_count_to_probe=%d\n", si, n_spi->uart_count_to_probe);
+ if (n_spi->uart_count_to_probe == 0) continue;
+
+ if (neuronspi_uart_data_global->p == NULL) {
+
+ neuronspi_uart_data_global->p = kzalloc(sizeof(struct neuronspi_port[NEURONSPI_MAX_UART]), GFP_ATOMIC);
+ unipi_uart_trace("Allocated port structure for %d ttyNS devices", NEURONSPI_MAX_UART);
+ }
+
+ if (neuronspi_uart_data_global->kworker_task == NULL) {
+
+ kthread_init_worker(&neuronspi_uart_data_global->kworker);
+
+ neuronspi_uart_data_global->kworker_task = kthread_run(kthread_worker_fn, &neuronspi_uart_data_global->kworker,
+ "neuronspi");
+ if (IS_ERR(neuronspi_uart_data_global->kworker_task)) {
+ ret = PTR_ERR(neuronspi_uart_data_global->kworker_task);
+ }
+ sched_setscheduler(neuronspi_uart_data_global->kworker_task, SCHED_FIFO, &neuronspi_sched_param);
+ unipi_uart_trace("KWorker Task started\n");
+ }
+
+ ret = neuronspi_uart_probe(spi, n_spi);
+ if (ret) break;
+ }
+ return ret;
}
-void neuronspi_uart_null_void(struct uart_port *port)
+
+
+int neuronspi_uart_driver_init(void)
{
- /* Do nothing */
+ int ret;
+ if (neuronspi_uart_driver_global != NULL) {
+ return 0;
+ }
+ // Register UART if not registered
+ neuronspi_uart_driver_global = kzalloc(sizeof(struct uart_driver), GFP_ATOMIC);
+ neuronspi_uart_driver_global->owner = THIS_MODULE;
+ neuronspi_uart_driver_global->dev_name = "ttyNS";
+ neuronspi_uart_driver_global->driver_name = "ttyNS";
+ neuronspi_uart_driver_global->nr = NEURONSPI_MAX_UART;
+ ret = uart_register_driver(neuronspi_uart_driver_global);
+ if (ret) {
+ printk(KERN_ERR "UNIPIUART: Failed to register the neuronspi uart driver, ERR:%d\n", ret);
+ kfree(neuronspi_uart_driver_global);
+ neuronspi_uart_driver_global = NULL;
+ return ret;
+ }
+ unipi_uart_trace("UART driver registered successfully!\n");
+ if (neuronspi_uart_data_global != NULL) {
+ printk(KERN_ERR "UNIPIUART: Uart data already allocated!\n");
+ return 0;
+ }
+ neuronspi_uart_data_global = kzalloc(sizeof(struct neuronspi_uart_data), GFP_ATOMIC);
+ unipi_uart_trace("UART driver data allocated successfully!\n");
+ return 0;
+}
+
+int neuronspi_uart_driver_exit(void)
+{
+ if (neuronspi_uart_driver_global) {
+ neuronspi_uart_remove(neuronspi_uart_data_global);
+ uart_unregister_driver(neuronspi_uart_driver_global);
+ kfree(neuronspi_uart_driver_global);
+ kfree(neuronspi_uart_data_global);
+ }
+ return 0;
}