diff --git a/Makefile b/Makefile index cc4de67..54fcc63 100755 --- a/Makefile +++ b/Makefile @@ -2,6 +2,8 @@ obj-m += soft_uart.o soft_uart-objs := module.o raspberry_soft_uart.o queue.o +ccflags-y := -Wno-incompatible-pointer-types + RELEASE = $(shell uname -r) LINUX = /usr/src/linux-headers-$(RELEASE) diff --git a/README.md b/README.md index 643fffa..a390a7f 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This module creates a software-based serial port using a configurable pair of GP Fetch the source: ``` -git clone https://github.com/adrianomarto/soft_uart +git clone --depth 1 https://github.com/sfera-labs/soft_uart ``` Install the package `raspberrypi-kernel-headers`: diff --git a/module.c b/module.c index eb6c8c5..d79a8bf 100755 --- a/module.c +++ b/module.c @@ -6,6 +6,7 @@ #include #include #include +#include #define SOFT_UART_MAJOR 0 #define N_PORTS 1 @@ -30,7 +31,7 @@ static int soft_uart_write(struct tty_struct*, const unsigned char*, int); static unsigned int soft_uart_write_room(struct tty_struct*); static void soft_uart_flush_buffer(struct tty_struct*); static unsigned int soft_uart_chars_in_buffer(struct tty_struct*); -static void soft_uart_set_termios(struct tty_struct*, struct ktermios*); +static void soft_uart_set_termios(struct tty_struct*, const struct ktermios*); static void soft_uart_stop(struct tty_struct*); static void soft_uart_start(struct tty_struct*); static void soft_uart_hangup(struct tty_struct*); @@ -71,9 +72,17 @@ static struct tty_port port; */ static int __init soft_uart_init(void) { + bool success = true; + printk(KERN_INFO "soft_uart: Initializing module...\n"); + + success &= gpio_request(gpio_tx, "soft_uart_tx") == 0; + success &= gpio_direction_output(gpio_tx, 1) == 0; + + success &= gpio_request(gpio_rx, "soft_uart_rx") == 0; + success &= gpio_direction_input(gpio_rx) == 0; - if (!raspberry_soft_uart_init(gpio_tx, gpio_rx)) + if (!success || !raspberry_soft_uart_init(gpio_to_desc(gpio_tx), gpio_to_desc(gpio_rx))) { printk(KERN_ALERT "soft_uart: Failed initialize GPIO.\n"); return -ENOMEM; @@ -256,7 +265,7 @@ static unsigned int soft_uart_chars_in_buffer(struct tty_struct* tty) * @param tty given TTY * @param termios parameters */ -static void soft_uart_set_termios(struct tty_struct* tty, struct ktermios* termios) +static void soft_uart_set_termios(struct tty_struct* tty, const struct ktermios* termios) { int cflag = 0; speed_t baudrate = tty_get_baud_rate(tty); diff --git a/raspberry_soft_uart.c b/raspberry_soft_uart.c index 51a214c..d7dbe17 100755 --- a/raspberry_soft_uart.c +++ b/raspberry_soft_uart.c @@ -2,7 +2,6 @@ #include "raspberry_soft_uart.h" #include "queue.h" -#include #include #include #include @@ -10,7 +9,7 @@ #include #include -static irq_handler_t handle_rx_start(unsigned int irq, void* device, struct pt_regs* registers); +static irqreturn_t handle_rx_start(int irq, void *device); static enum hrtimer_restart handle_tx(struct hrtimer* timer); static enum hrtimer_restart handle_rx(struct hrtimer* timer); static void receive_character(unsigned char character); @@ -21,9 +20,11 @@ static DEFINE_MUTEX(current_tty_mutex); static struct hrtimer timer_tx; static struct hrtimer timer_rx; static ktime_t period; -static int gpio_tx = 0; -static int gpio_rx = 0; +static ktime_t half_period; +static struct gpio_desc *gpio_tx; +static struct gpio_desc *gpio_rx; static int rx_bit_index = -1; +static void (*rx_callback)(unsigned char) = NULL; /** * Initializes the Raspberry Soft UART infrastructure. @@ -34,7 +35,7 @@ static int rx_bit_index = -1; * @param gpio_rx GPIO pin used as RX * @return 1 if the initialization is successful. 0 otherwise. */ -int raspberry_soft_uart_init(const int _gpio_tx, const int _gpio_rx) +int raspberry_soft_uart_init(struct gpio_desc *_gpio_tx, struct gpio_desc *_gpio_rx) { bool success = true; @@ -51,21 +52,15 @@ int raspberry_soft_uart_init(const int _gpio_tx, const int _gpio_rx) // Initializes the GPIO pins. gpio_tx = _gpio_tx; gpio_rx = _gpio_rx; - - success &= gpio_request(gpio_tx, "soft_uart_tx") == 0; - success &= gpio_direction_output(gpio_tx, 1) == 0; - - success &= gpio_request(gpio_rx, "soft_uart_rx") == 0; - success &= gpio_direction_input(gpio_rx) == 0; // Initializes the interruption. success &= request_irq( - gpio_to_irq(gpio_rx), - (irq_handler_t) handle_rx_start, + gpiod_to_irq(gpio_rx), + handle_rx_start, IRQF_TRIGGER_FALLING, "soft_uart_irq_handler", NULL) == 0; - disable_irq(gpio_to_irq(gpio_rx)); + disable_irq(gpiod_to_irq(gpio_rx)); return success; } @@ -75,10 +70,10 @@ int raspberry_soft_uart_init(const int _gpio_tx, const int _gpio_rx) */ int raspberry_soft_uart_finalize(void) { - free_irq(gpio_to_irq(gpio_rx), NULL); - gpio_set_value(gpio_tx, 0); - gpio_free(gpio_tx); - gpio_free(gpio_rx); + free_irq(gpiod_to_irq(gpio_rx), NULL); + gpiod_set_value(gpio_tx, 0); + gpiod_put(gpio_tx); + gpiod_put(gpio_rx); return 1; } @@ -91,12 +86,13 @@ int raspberry_soft_uart_open(struct tty_struct* tty) { int success = 0; mutex_lock(¤t_tty_mutex); + rx_bit_index = -1; if (current_tty == NULL) { current_tty = tty; initialize_queue(&queue_tx); success = 1; - enable_irq(gpio_to_irq(gpio_rx)); + enable_irq(gpiod_to_irq(gpio_rx)); } mutex_unlock(¤t_tty_mutex); return success; @@ -107,18 +103,13 @@ int raspberry_soft_uart_open(struct tty_struct* tty) */ int raspberry_soft_uart_close(void) { - int success = 0; mutex_lock(¤t_tty_mutex); - if (current_tty != NULL) - { - disable_irq(gpio_to_irq(gpio_rx)); - hrtimer_cancel(&timer_tx); - hrtimer_cancel(&timer_rx); - current_tty = NULL; - success = 1; - } + disable_irq(gpiod_to_irq(gpio_rx)); + hrtimer_cancel(&timer_tx); + hrtimer_cancel(&timer_rx); + current_tty = NULL; mutex_unlock(¤t_tty_mutex); - return success; + return 1; } /** @@ -129,7 +120,8 @@ int raspberry_soft_uart_close(void) int raspberry_soft_uart_set_baudrate(const int baudrate) { period = ktime_set(0, 1000000000/baudrate); - gpio_set_debounce(gpio_rx, 1000/baudrate/2); + half_period = ktime_set(0, 1000000000/baudrate/2); + gpiod_set_debounce(gpio_rx, 1000/baudrate/2); return 1; } @@ -170,6 +162,16 @@ int raspberry_soft_uart_get_tx_queue_size(void) return get_queue_size(&queue_tx); } +/** + * Sets the callback function to be called on received character. + * @param callback the callback function + */ +int raspberry_soft_uart_set_rx_callback(void (*callback)(unsigned char)) +{ + rx_callback = callback; + return 1; +} + //----------------------------------------------------------------------------- // Internals //----------------------------------------------------------------------------- @@ -178,13 +180,13 @@ int raspberry_soft_uart_get_tx_queue_size(void) * If we are waiting for the RX start bit, then starts the RX timer. Otherwise, * does nothing. */ -static irq_handler_t handle_rx_start(unsigned int irq, void* device, struct pt_regs* registers) +static irqreturn_t handle_rx_start(int irq, void *device) { if (rx_bit_index == -1) { - hrtimer_start(&timer_rx, ktime_set(0, period / 2), HRTIMER_MODE_REL); + hrtimer_start(&timer_rx, half_period, HRTIMER_MODE_REL); } - return (irq_handler_t) IRQ_HANDLED; + return IRQ_HANDLED; } @@ -204,7 +206,7 @@ static enum hrtimer_restart handle_tx(struct hrtimer* timer) { if (dequeue_character(&queue_tx, &character)) { - gpio_set_value(gpio_tx, 0); + gpiod_set_value(gpio_tx, 0); bit_index++; must_restart_timer = true; } @@ -213,7 +215,7 @@ static enum hrtimer_restart handle_tx(struct hrtimer* timer) // Data bits. else if (0 <= bit_index && bit_index < 8) { - gpio_set_value(gpio_tx, 1 & (character >> bit_index)); + gpiod_set_value(gpio_tx, 1 & (character >> bit_index)); bit_index++; must_restart_timer = true; } @@ -221,7 +223,7 @@ static enum hrtimer_restart handle_tx(struct hrtimer* timer) // Stop bit. else if (bit_index == 8) { - gpio_set_value(gpio_tx, 1); + gpiod_set_value(gpio_tx, 1); character = 0; bit_index = -1; must_restart_timer = get_queue_size(&queue_tx) > 0; @@ -244,7 +246,7 @@ static enum hrtimer_restart handle_rx(struct hrtimer* timer) { ktime_t current_time = ktime_get(); static unsigned int character = 0; - int bit_value = gpio_get_value(gpio_rx); + int bit_value = gpiod_get_value(gpio_rx); enum hrtimer_restart result = HRTIMER_NORESTART; bool must_restart_timer = false; @@ -298,18 +300,22 @@ static enum hrtimer_restart handle_rx(struct hrtimer* timer) void receive_character(unsigned char character) { mutex_lock(¤t_tty_mutex); + if (rx_callback != NULL) { + (*rx_callback)(character); + } else { #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) - if (current_tty != NULL && current_tty->port != NULL) - { - tty_insert_flip_char(current_tty->port, character, TTY_NORMAL); - tty_flip_buffer_push(current_tty->port); - } + if (current_tty != NULL && current_tty->port != NULL) + { + tty_insert_flip_char(current_tty->port, character, TTY_NORMAL); + tty_flip_buffer_push(current_tty->port); + } #else - if (tty != NULL) - { - tty_insert_flip_char(current_tty, character, TTY_NORMAL); - tty_flip_buffer_push(tty); - } + if (tty != NULL) + { + tty_insert_flip_char(current_tty, character, TTY_NORMAL); + tty_flip_buffer_push(tty); + } #endif + } mutex_unlock(¤t_tty_mutex); } diff --git a/raspberry_soft_uart.h b/raspberry_soft_uart.h index 9297bdf..f900f3d 100755 --- a/raspberry_soft_uart.h +++ b/raspberry_soft_uart.h @@ -2,8 +2,9 @@ #define RASPBERRY_SOFT_UART_H #include +#include -int raspberry_soft_uart_init(const int gpio_tx, const int gpio_rx); +int raspberry_soft_uart_init(struct gpio_desc *_gpio_tx, struct gpio_desc *_gpio_rx); int raspberry_soft_uart_finalize(void); int raspberry_soft_uart_open(struct tty_struct* tty); int raspberry_soft_uart_close(void); @@ -11,5 +12,6 @@ int raspberry_soft_uart_set_baudrate(const int baudrate); int raspberry_soft_uart_send_string(const unsigned char* string, int string_size); int raspberry_soft_uart_get_tx_queue_room(void); int raspberry_soft_uart_get_tx_queue_size(void); +int raspberry_soft_uart_set_rx_callback(void (*callback)(unsigned char)); #endif