add hrtimer to schedule tx_proc and to monitor tx_fifo
authorMiroslav Ondra <ondra@faster.cz>
Mon, 3 Sep 2018 20:40:04 +0000 (22:40 +0200)
committerMiroslav Ondra <ondra@faster.cz>
Mon, 3 Sep 2018 20:40:04 +0000 (22:40 +0200)
modules/unipi/current
modules/unipi/raspbian
modules/unipi/src/unipi_common.h
modules/unipi/src/unipi_spi.c
modules/unipi/src/unipi_spi.h
modules/unipi/src/unipi_uart.c
modules/unipi/src/unipi_uart.h

index 2a3d3346ed0d2d1660423ea52861f2064276a512..d79fb96ee0a72aa0b1e776e3c6a75d5c38244267 100755 (executable)
@@ -1,5 +1,10 @@
 #!/bin/bash
 
+##########################################
+##
+## compile module agains kernel tree in tmp
+##
+##########################################
 
 cd tmp
 . versions
index b48e09d981e5d64cc5ea1d4198d115e6444ca477..464d0dd88cba9a87544d3cbeb18581bc394d15ed 100755 (executable)
@@ -2,20 +2,22 @@
 
 ###############################################
 #
-# for new version checking delete file tmp/versions
-#
+# check latest raspbian kernel version, download it to directory tmp
+# compile module 
 #################################################
-if [ -s tmp/versions ]; then
-       mkdir -p tmp
-       wget -q http://archive.raspberrypi.org/debian/dists/stretch/main/binary-armhf/Packages.gz -O - | gunzip \
-       | awk '/^Package: raspberrypi-kernel-headers[[:blank:]]*$/ { ok=1; next} /^Package: / {ok=0;} (ok!=1) {next} 
+
+mkdir -p tmp
+
+# get latest raspbian kernel version
+wget -q http://archive.raspberrypi.org/debian/dists/stretch/main/binary-armhf/Packages.gz -O - | gunzip \
+| awk '/^Package: raspberrypi-kernel-headers[[:blank:]]*$/ { ok=1; next} /^Package: / {ok=0;} (ok!=1) {next} 
        /^Version: / {print "RPI_FIRMWARE_VER=" $2 } 
        /^Filename: / {print "RPI_FIRMWARE_FILE=" $2; nextfile }' > tmp/versions
-fi
 
 cd tmp
 . versions
 
+# get kernel source
 #-----------------------------------------------------------------------
 # this method doesn't work if tag in git wasn't created
 #wget https://github.com/raspberrypi/linux/archive/raspberrypi-kernel_${RPI_FIRMWARE_VER}.zip
@@ -23,7 +25,7 @@ cd tmp
 
 # alternate method to get raspberrypi-kernel_${RPI_FIRMWARE_VER}.zip
 # get commit number used for making this kernel version
-if [ ! -d linux-raspberrypi-kernel_${RPI_FIRMWARE_VER} ]; then
+
        wget https://raw.githubusercontent.com/raspberrypi/firmware/stable/extra/git_hash -O- > .git_hash
        GIT_VER=`cat .git_hash`
        wget https://github.com/raspberrypi/linux/archive/$GIT_VER.zip -O raspberrypi-kernel_${RPI_FIRMWARE_VER}.zip
@@ -31,14 +33,12 @@ if [ ! -d linux-raspberrypi-kernel_${RPI_FIRMWARE_VER} ]; then
        mv linux-$GIT_VER linux-raspberrypi-kernel_${RPI_FIRMWARE_VER}
        #-----------------------------------------------------------------------
        rm raspberrypi-kernel_${RPI_FIRMWARE_VER}.zip
-fi
 
-if [ ! -r `basename ${RPI_FIRMWARE_FILE}` ]; then
-       wget http://archive.raspberrypi.org/debian/${RPI_FIRMWARE_FILE}
-       dpkg-deb -x `basename ${RPI_FIRMWARE_FILE}` h
-       ### raspberrypi-kernel-headers_1.20180417-1_armhf.deb h
-fi
+# download headers and symbols
+wget http://archive.raspberrypi.org/debian/${RPI_FIRMWARE_FILE}
+dpkg-deb -x `basename ${RPI_FIRMWARE_FILE}` h
 
+# prepare kernel tree and compile module
 KERNEL_VER=`ls -1 h/lib/modules | grep '\-v7'`
 echo $KERNEL_VER
 cp h/usr/src/linux-headers-${KERNEL_VER}/.config linux-raspberrypi-kernel_${RPI_FIRMWARE_VER}
index 8c76cf2c35dca83b15c8b15b4c1251c83de0ba9b..514e3b4a232ba3f028e538875670a39299f89686 100644 (file)
 #if NEURONSPI_SCHED_REQUIRED > 0
        #include <uapi/linux/sched/types.h>
 #endif
-#define NEURONSPI_MAJOR_VERSIONSTRING "Version 1.15:2018:08:14"
+#define NEURONSPI_MAJOR_VERSIONSTRING "Version 1.15:2018:09:03 (devel)"
 
 #define NEURONSPI_MAX_DEVS                             3
-#define NEURONSPI_MAX_UART                             128
+#define NEURONSPI_MAX_UART                             16
 #define NEURONSPI_BUFFER_MAX                   1152
 #define NEURONSPI_HEADER_LENGTH                10
 #define NEURONSPI_FIRST_MESSAGE_LENGTH 6
@@ -69,8 +69,9 @@
 #define NEURONSPI_MAX_BAUD                             115200
 #define NEURONSPI_FIFO_SIZE                            256
 #define NEURONSPI_FIFO_MIN_CONTINUOUS  50
-#define NEURONSPI_DETAILED_DEBUG               1
+#define NEURONSPI_DETAILED_DEBUG               0
 #define NEURONSPI_LAST_TRANSFER_DELAY  40
+#define MAX_RX_QUEUE_LEN                16
 
 #define NEURON_DEVICE_NAME                             "unipispi"
 #define NEURON_DEVICE_CLASS                    "modbus_spi"
@@ -125,20 +126,30 @@ struct neuronspi_op_buffer
 struct neuronspi_port
 {
        struct uart_port                        port;
-       u8                                                      line;
+       u8                                                      dev_index;  // index into global array neuronspi_s_dev 
+       u8                                                      dev_port;   // index of port on neuronspi device
+    
+    spinlock_t                  rx_queue_lock;
+    u8*                         rx_queue_primary;
+    int                         rx_qlen_primary;
+    u8*                         rx_queue_secondary;
+    int                         rx_qlen_secondary;
+    u8                          rx_remain;
+    
        struct kthread_work                     tx_work;
        struct kthread_work                     rx_work;
-       struct kthread_work                     irq_work;
-       u32                                                     flags;
-       u8                                                      ier_clear;
-       u8                                                      buf[NEURONSPI_FIFO_SIZE];
-       struct neuronspi_uart_data      *parent;
-       u8                                                      dev_index;
-       u8                                                      dev_port;
-//     u8                                                      parmrk_enabled;
-//     u64                                                     parmrk_frame_delay;
+       struct kthread_work                     irq_work;  // move it to neuronspi device
+       //u32                                                   flags;
+       //u8                                                    ier_clear;
+       //u8                                                    tx_buf[NEURONSPI_FIFO_SIZE];
+
+    u16                         tx_fifo_reg;  // register in neuronspi device modbus map to read internal tx fifo length
+                                              // 0 if undefined
+    u16                         tx_fifo_len;  // estimates char count in neuron internal tx fifo
+       struct hrtimer                          tx_timer;
+
        s32                                                     baud;
-    unsigned int                one_char_usec;
+    s64                         one_char_nsec;
 };
 
 struct neuronspi_uart_data
@@ -146,7 +157,7 @@ struct neuronspi_uart_data
        const struct neuronspi_devtype  *devtype;
        struct kthread_worker                   kworker;
        struct task_struct                              *kworker_task;
-       struct neuronspi_port                   *p;
+       struct neuronspi_port                   *p;             // array p[p_count]
        u8                                                              p_count;
 };
 
@@ -166,8 +177,8 @@ struct neuronspi_driver_data
 {
        struct spi_driver *spi_driver;
        struct neuronspi_char_driver *char_driver;
-       struct uart_driver *serial_driver;
-       struct neuronspi_uart_data *uart_data;
+       //struct uart_driver *serial_driver; -- this is global variable neuronspi_uart_driver_global
+       //struct neuronspi_uart_data *uart_data; -- this global var neuronspi_uar_data_global
        struct neuronspi_led_driver *led_driver;
        struct neuronspi_di_driver **di_driver;
        struct neuronspi_do_driver **do_driver;
@@ -188,15 +199,14 @@ struct neuronspi_driver_data
        char platform_name[sizeof("io_group0")];
        u32 probe_always_succeeds;
        u32 always_create_uart;
-       //u8 *send_buf;
-       //u8 *recv_buf;
+
        u8 *first_probe_reply;
-       //u8 *second_probe_reply;
        u8 reserved_device;
-       u8 uart_count;
-       u8 uart_read;
-       u8 *uart_buf;
-       u8 slower_model;
+       int uart_count;
+       int uart_pindex;
+       //u8 uart_read;
+       //u8 *uart_buf;
+       //u8 slower_model;
        u8 no_irq;
        u8 lower_board_id;
        u8 upper_board_id;
@@ -206,6 +216,7 @@ struct neuronspi_driver_data
        u16 sysfs_register_target;
        u16 sysfs_counter_target;
        u32 ideal_frequency;
+       u8 uart_count_to_probe;
 };
 
 struct neuronspi_di_driver {
@@ -270,8 +281,6 @@ struct neuronspi_file_data
 {
        struct spi_device** spi_device;
        struct mutex            lock;
-       //u8                                    *send_buf;
-       //u8                                    *recv_buf;
     struct neuronspi_op_buffer send_buf;
     struct neuronspi_op_buffer recv_buf;
        u32                             message_len;
index 04f893c4f390d6a01450c1cf1dfb2c862b5071f8..f383d5f9501efbdb1e984225a60f77bbba858c56 100644 (file)
@@ -77,7 +77,7 @@ struct neuronspi_char_driver neuronspi_cdrv =
 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;
@@ -153,6 +153,10 @@ int _neuronspi_spi_send_op(struct spi_device* spi_dev, s32 trans_count, const st
        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;
@@ -223,31 +227,26 @@ int _neuronspi_spi_send_op(struct spi_device* spi_dev, s32 trans_count, const st
 
                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;
@@ -262,15 +261,26 @@ int _neuronspi_spi_send_op(struct spi_device* spi_dev, s32 trans_count, const st
         } 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;
@@ -462,7 +472,6 @@ ssize_t neuronspi_write (struct file *file_p, const char *buffer, size_t len, lo
                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));
@@ -472,6 +481,13 @@ ssize_t neuronspi_write (struct file *file_p, const char *buffer, size_t len, lo
     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);
@@ -495,7 +511,7 @@ s32 neuronspi_spi_uart_write(struct spi_device *spi, u8 *send_buf, int length, u
                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;
        }
@@ -545,7 +561,7 @@ void neuronspi_spi_uart_read(struct spi_device* spi, u8 *recv_buf, s32 len, u8 u
                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 {
@@ -559,11 +575,11 @@ void neuronspi_spi_uart_read(struct spi_device* spi, u8 *recv_buf, s32 len, u8 u
 
        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;
@@ -892,16 +908,15 @@ irqreturn_t neuronspi_spi_irq(s32 irq, void *dev_id)
        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);
                        }
 
                }
@@ -925,17 +940,22 @@ s32 neuronspi_spi_probe(struct spi_device *spi)
        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;
 
@@ -945,10 +965,8 @@ s32 neuronspi_spi_probe(struct spi_device *spi)
                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);
@@ -1027,7 +1045,7 @@ s32 neuronspi_spi_probe(struct spi_device *spi)
        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;
                }
        }
@@ -1081,45 +1099,14 @@ reg1001: %x, reg1002: %x, reg1003: %x, reg1004: %x\n",
                }
        }
 
-
-       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);
        }
@@ -1316,14 +1303,20 @@ reg1001: %x, reg1002: %x, reg1003: %x, reg1004: %x\n",
                }
        }
 
+    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++) {
@@ -1408,10 +1401,10 @@ s32 neuronspi_spi_remove(struct spi_device *spi)
                        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);
@@ -1477,10 +1470,14 @@ MODULE_ALIAS("spi:unipispi");
 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) {
@@ -1497,6 +1494,10 @@ static s32 __init neuronspi_init(void)
        if (neuronspi_invalidate_thread != NULL) {
                wake_up_process(neuronspi_invalidate_thread);
        }
+
+    neuronspi_uart_driver_init();
+    neuronspi_uart_probe_all();
+
        unipi_tty_init();
        return ret;
 }
@@ -1511,12 +1512,7 @@ static void __exit neuronspi_exit(void)
                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);
index 2a881de48e9095f857900b065fb241d3da5f4f34..a799247845dd44c646137943219df402de792d43 100644 (file)
@@ -45,7 +45,7 @@ static const u8 NEURONSPI_PROBE_MESSAGE[NEURONSPI_PROBE_MESSAGE_LEN] = {
 
 #define UNIPISPI_PROBE_MESSAGE_LEN                                             16
 static u8 _probe_message_second[UNIPISPI_PROBE_MESSAGE_LEN] = 
-                   {0x04, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x16};
+          {0x04, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x16};
 static const struct neuronspi_op_buffer UNIPISPI_PROBE_MESSAGE = {
     first_message: {0x04, 0x0e, 0xe8, 0x03, 0xa0, 0xdd},
     second_message: _probe_message_second,
@@ -220,18 +220,7 @@ int unipispi_modbus_write_many(struct spi_device* spi_dev, u16 reg, u16* value,
 int unipispi_modbus_write_coil(struct spi_device* spi_dev, u16 coil, int value);
 
 void neuronspi_spi_set_irqs(struct spi_device* spi_dev, u16 to);
-/*
-void neuronspi_spi_led_set_brightness(struct spi_device* spi_dev, enum led_brightness brightness, int id);
-void neuronspi_spi_iio_stm_ai_read_voltage(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-void neuronspi_spi_iio_stm_ai_read_current(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-void neuronspi_spi_iio_stm_ao_read_resistance(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-void neuronspi_spi_iio_stm_ao_set_voltage(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask);
-void neuronspi_spi_iio_stm_ao_set_current(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask);
-void neuronspi_spi_iio_sec_ai_read_voltage(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-void neuronspi_spi_iio_sec_ai_read_current(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-void neuronspi_spi_iio_sec_ai_read_resistance(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-void neuronspi_spi_iio_sec_ao_set_voltage(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask);
- */ 
+
 int neuronspi_spi_gpio_do_set(struct spi_device* spi_dev, u32 id, int value);
 int neuronspi_spi_gpio_ro_set(struct spi_device* spi_dev, u32 id, int value);
 int neuronspi_spi_gpio_di_get(struct spi_device* spi_dev, u32 id);
index 96d50fef65aaa081805121e59eb24021a97e8c46..fb601aa4dfd5375c2be8fb7ed332d5bd5316563a 100644 (file)
 #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);
 }
 
 /************************
@@ -83,72 +131,65 @@ static void neuronspi_uart_set_iflags(struct uart_port *port, int to)
 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: {
@@ -164,19 +205,19 @@ void neuronspi_uart_set_termios(struct uart_port *port, struct ktermios *termios
        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
@@ -219,9 +260,9 @@ void neuronspi_uart_update_timeout(struct neuronspi_port *n_port, unsigned int c
        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)
@@ -231,58 +272,63 @@ 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;
@@ -294,21 +340,57 @@ s32 neuronspi_uart_alloc_line(void)
 
        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;
 
@@ -320,9 +402,15 @@ void neuronspi_uart_handle_rx(struct neuronspi_port *port, u32 rxlen, u32 iir)
        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;
@@ -338,55 +426,89 @@ void neuronspi_uart_handle_tx(struct neuronspi_port *port)
                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);
@@ -397,232 +519,97 @@ void neuronspi_uart_handle_tx(struct neuronspi_port *port)
 */
 }
 
-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);
                                }
                        }
                }
@@ -630,7 +617,7 @@ s32 neuronspi_uart_poll(void *data)
        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);
@@ -645,32 +632,213 @@ s32 neuronspi_uart_startup(struct uart_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;
 }
index aea6b863387ecf1f58b4f7cd8195ec1ccdfa5200..4eac3dde3a3e55d459914aa9f731a623cdf171b7 100644 (file)
@@ -26,9 +26,6 @@
  * Definitions *
  ***************/
 
-#define NEURONSPI_UART_IFLAGS_REGISTER         502
-#define NEURONSPI_UART_LDISC_REGISTER  503
-#define NEURONSPI_UART_TIMEOUT_REGISTER 504
 
 #define NEURONSPI_MAX_TX_WORK  4
 
  * Function Declarations *
  *************************/
 
-void neuronspi_uart_start_tx(struct uart_port *port);
-void neuronspi_uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old);
-u32 neuronspi_uart_tx_empty(struct uart_port *port);
-void neuronspi_uart_break_ctl(struct uart_port *port, int break_state);
-void neuronspi_uart_set_mctrl(struct uart_port *port, u32 mctrl);
-void neuronspi_uart_shutdown(struct uart_port *port);
-s32 neuronspi_uart_startup(struct uart_port *port);
-s32 neuronspi_uart_request_port(struct uart_port *port);
-s32 neuronspi_uart_alloc_line(void);
-int    neuronspi_uart_ioctl (struct uart_port *port, unsigned int ioctl_code, unsigned long ioctl_arg);
-void neuronspi_uart_set_ldisc(struct uart_port *port, struct ktermios *kterm);
-u32 neuronspi_uart_get_mctrl(struct uart_port *port);
-const char *neuronspi_uart_type(struct uart_port *port);
-void neuronspi_uart_null_void(struct uart_port *port);
-void neuronspi_uart_config_port(struct uart_port *port, int flags);
-s32 neuronspi_uart_verify_port(struct uart_port *port, struct serial_struct *s);
-void neuronspi_uart_pm(struct uart_port *port, u32 state,  u32 oldstate);
-s32 neuronspi_uart_poll(void *data);
-s32 neuronspi_uart_probe(struct spi_device* dev, u8 device_index);
-s32 neuronspi_uart_remove(struct neuronspi_uart_data *u_data);
-void neuronspi_uart_power(struct uart_port *port, s32 on);
-s32 neuronspi_uart_config_rs485(struct uart_port *port, struct serial_rs485 *rs485);
-void neuronspi_spi_uart_set_cflag(struct spi_device* spi_dev, u8 port, u32 to);
-u32 neuronspi_spi_uart_get_cflag(struct spi_device* spi_dev, u8 port);
-void neuronspi_uart_fifo_write(struct neuronspi_port *port, u8 to_send);
-void neuronspi_uart_fifo_read(struct uart_port *port, u32 rxlen);
-void neuronspi_uart_rx_proc(struct kthread_work *ws);
-void neuronspi_uart_tx_proc(struct kthread_work *ws);
-void neuronspi_uart_ist(struct kthread_work *ws);
-void neuronspi_uart_handle_tx(struct neuronspi_port *port);
-void neuronspi_uart_handle_rx(struct neuronspi_port *port, u32 rxlen, u32 iir);
-void neuronspi_uart_handle_irq(struct neuronspi_uart_data *uart_data, u32 portno);
+int neuronspi_rx_queue_add(struct neuronspi_port *port, u8 data);
+void neuronspi_rx_queue_swap(struct neuronspi_port *port);
+
+int neuronspi_uart_driver_init(void);
+int neuronspi_uart_driver_exit(void);
+int neuronspi_uart_probe(struct spi_device* spi, struct neuronspi_driver_data *n_spi);
+int neuronspi_uart_probe_all(void);
 
 /*********************
  * Data Declarations *
  *********************/
 
-extern struct neuronspi_uart_data* neuronspi_uart_glob_data;
-extern unsigned long neuronspi_lines;
-extern struct uart_driver* neuronspi_uart;
-
-static const struct uart_ops neuronspi_uart_ops =
-{
-       .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,
-       .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,
-};
+extern struct neuronspi_uart_data* neuronspi_uart_data_global;
+extern struct uart_driver* neuronspi_uart_driver_global;
+//extern unsigned long neuronspi_lines;
 
 #endif /* MODULES_NEURON_SPI_SRC_UNIPI_UART_H_ */