diff --git a/README.md b/README.md index 643fffa..1ab47bc 100644 --- a/README.md +++ b/README.md @@ -40,17 +40,22 @@ I haven't tried cross-compiling this module, but it should work as well. Module parameters: -* gpio_tx: int [default = 17] -* gpio_rx: int [default = 27] +* gpio_tx: int [default = 529] +* gpio_rx: int [default = 539] Loading the module with default parameters: ``` sudo insmod soft_uart.ko ``` -Loading module with custom parameters: +Look up GPIO number using the following command, for setting up pins other than the default. ``` -sudo insmod soft_uart.ko gpio_tx=10 gpio_rx=11 +cat /sys/kernel/debug/gpio +``` + +Loading module with custom parameters with (GPIO17:529) as TX and (GPIO27:539) as RX: +``` +sudo insmod soft_uart.ko gpio_tx=529 gpio_rx=539 ``` diff --git a/module.c b/module.c index eb6c8c5..0ce85ea 100755 --- a/module.c +++ b/module.c @@ -1,392 +1,393 @@ - -#include "raspberry_soft_uart.h" - -#include -#include -#include -#include -#include - -#define SOFT_UART_MAJOR 0 -#define N_PORTS 1 -#define NONE 0 -#define TX_BUFFER_FLUSH_TIMEOUT 4000 // milliseconds - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Adriano Marto Reis"); -MODULE_DESCRIPTION("Software-UART for Raspberry Pi"); -MODULE_VERSION("0.2"); - -static int gpio_tx = 17; -module_param(gpio_tx, int, 0); - -static int gpio_rx = 27; -module_param(gpio_rx, int, 0); - -// Module prototypes. -static int soft_uart_open(struct tty_struct*, struct file*); -static void soft_uart_close(struct tty_struct*, struct file*); -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_stop(struct tty_struct*); -static void soft_uart_start(struct tty_struct*); -static void soft_uart_hangup(struct tty_struct*); -static int soft_uart_tiocmget(struct tty_struct*); -static int soft_uart_tiocmset(struct tty_struct*, unsigned int, unsigned int); -static int soft_uart_ioctl(struct tty_struct*, unsigned int, unsigned int long); -static void soft_uart_throttle(struct tty_struct*); -static void soft_uart_unthrottle(struct tty_struct*); - -// Module operations. -static const struct tty_operations soft_uart_operations = { - .open = soft_uart_open, - .close = soft_uart_close, - .write = soft_uart_write, - .write_room = soft_uart_write_room, - .flush_buffer = soft_uart_flush_buffer, - .chars_in_buffer = soft_uart_chars_in_buffer, - .ioctl = soft_uart_ioctl, - .set_termios = soft_uart_set_termios, - .stop = soft_uart_stop, - .start = soft_uart_start, - .hangup = soft_uart_hangup, - .tiocmget = soft_uart_tiocmget, - .tiocmset = soft_uart_tiocmset, - .throttle = soft_uart_throttle, - .unthrottle = soft_uart_unthrottle -}; - -// Driver instance. -static struct tty_driver* soft_uart_driver = NULL; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) -static struct tty_port port; -#endif - -/** - * Module initialization. - */ -static int __init soft_uart_init(void) -{ - printk(KERN_INFO "soft_uart: Initializing module...\n"); - - if (!raspberry_soft_uart_init(gpio_tx, gpio_rx)) - { - printk(KERN_ALERT "soft_uart: Failed initialize GPIO.\n"); - return -ENOMEM; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) - printk(KERN_INFO "soft_uart: LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0).\n"); - - // Initializes the port. - tty_port_init(&port); - - // Allocates the driver. - soft_uart_driver = tty_alloc_driver(N_PORTS, TTY_DRIVER_REAL_RAW); - - // Returns if the allocation fails. - if (IS_ERR(soft_uart_driver)) - { - printk(KERN_ALERT "soft_uart: Failed to allocate the driver.\n"); - return -ENOMEM; - } -#else - printk(KERN_INFO "soft_uart: LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0).\n"); - - // Allocates the driver. - soft_uart_driver = alloc_tty_driver(N_PORTS); - - // Returns if the allocation fails. - if (!soft_uart_driver) - { - printk(KERN_ALERT "soft_uart: Failed to allocate the driver.\n"); - return -ENOMEM; - } -#endif - - // Initializes the driver. - soft_uart_driver->owner = THIS_MODULE; - soft_uart_driver->driver_name = "soft_uart"; - soft_uart_driver->name = "ttySOFT"; - soft_uart_driver->major = SOFT_UART_MAJOR; - soft_uart_driver->minor_start = 0; - soft_uart_driver->flags = TTY_DRIVER_REAL_RAW; - soft_uart_driver->type = TTY_DRIVER_TYPE_SERIAL; - soft_uart_driver->subtype = SERIAL_TYPE_NORMAL; - soft_uart_driver->init_termios = tty_std_termios; - soft_uart_driver->init_termios.c_ispeed = 4800; - soft_uart_driver->init_termios.c_ospeed = 4800; - soft_uart_driver->init_termios.c_cflag = B4800 | CREAD | CS8 | CLOCAL; - - // Sets the callbacks for the driver. - tty_set_operations(soft_uart_driver, &soft_uart_operations); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) - // Link the port with the driver. - tty_port_link_device(&port, soft_uart_driver, 0); -#endif - - // Registers the TTY driver. - if (tty_register_driver(soft_uart_driver)) - { - printk(KERN_ALERT "soft_uart: Failed to register the driver.\n"); - tty_driver_kref_put(soft_uart_driver); - return -1; // return if registration fails - } - - printk(KERN_INFO "soft_uart: Module initialized.\n"); - return 0; -} - -/** - * Cleanup function that gets called when the module is unloaded. - */ -static void __exit soft_uart_exit(void) -{ - printk(KERN_INFO "soft_uart: Finalizing the module...\n"); - - // Finalizes the soft UART. - if (!raspberry_soft_uart_finalize()) - { - printk(KERN_ALERT "soft_uart: Something went wrong whilst finalizing the soft UART.\n"); - } - - // Unregisters the driver. - tty_unregister_driver(soft_uart_driver); - - tty_driver_kref_put(soft_uart_driver); - printk(KERN_INFO "soft_uart: Module finalized.\n"); -} - -/** - * Opens a given TTY device. - * @param tty given TTY device - * @param file - * @return error code. - */ -static int soft_uart_open(struct tty_struct* tty, struct file* file) -{ - int error = NONE; - - if (raspberry_soft_uart_open(tty)) - { - printk(KERN_INFO "soft_uart: Device opened.\n"); - } - else - { - printk(KERN_ALERT "soft_uart: Device busy.\n"); - error = -ENODEV; - } - - return error; -} - -/** - * Closes a given TTY device. - * @param tty - * @param file - */ -static void soft_uart_close(struct tty_struct* tty, struct file* file) -{ - // Waits for the TX buffer to be empty before closing the UART. - int wait_time = 0; - while ((raspberry_soft_uart_get_tx_queue_size() > 0) - && (wait_time < TX_BUFFER_FLUSH_TIMEOUT)) - { - msleep(100); - wait_time += 100; - } - - if (raspberry_soft_uart_close()) - { - printk(KERN_INFO "soft_uart: Device closed.\n"); - } - else - { - printk(KERN_ALERT "soft_uart: Could not close the device.\n"); - } -} - -/** - * Writes the contents of a given buffer into a given TTY device. - * @param tty given TTY device - * @param buffer given buffer - * @param buffer_size number of bytes contained in the given buffer - * @return number of bytes successfuly written into the TTY device - */ -static int soft_uart_write(struct tty_struct* tty, const unsigned char* buffer, int buffer_size) -{ - return raspberry_soft_uart_send_string(buffer, buffer_size); -} - -/** - * Tells the kernel the number of bytes that can be written to a given TTY. - * @param tty given TTY - * @return number of bytes - */ -static unsigned int soft_uart_write_room(struct tty_struct* tty) -{ - return raspberry_soft_uart_get_tx_queue_room(); -} - -/** - * Does nothing. - * @param tty - */ -static void soft_uart_flush_buffer(struct tty_struct* tty) -{ -} - -/** - * Tells the kernel the number of bytes contained in the buffer of a given TTY. - * @param tty given TTY - * @return number of bytes - */ -static unsigned int soft_uart_chars_in_buffer(struct tty_struct* tty) -{ - return raspberry_soft_uart_get_tx_queue_size(); -} - -/** - * Sets the UART parameters for a given TTY (only the baudrate is taken into account). - * @param tty given TTY - * @param termios parameters - */ -static void soft_uart_set_termios(struct tty_struct* tty, struct ktermios* termios) -{ - int cflag = 0; - speed_t baudrate = tty_get_baud_rate(tty); - printk(KERN_INFO "soft_uart: soft_uart_set_termios: baudrate = %d.\n", baudrate); - - // Gets the cflag. -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) - cflag = tty->termios.c_cflag; -#else - cflag = tty->termios->c_cflag; -#endif - - // Verifies the number of data bits (it must be 8). - if ((cflag & CSIZE) != CS8) - { - printk(KERN_ALERT "soft_uart: Invalid number of data bits.\n"); - } - - // Verifies the number of stop bits (it must be 1). - if (cflag & CSTOPB) - { - printk(KERN_ALERT "soft_uart: Invalid number of stop bits.\n"); - } - - // Verifies the parity (it must be none). - if (cflag & PARENB) - { - printk(KERN_ALERT "soft_uart: Invalid parity.\n"); - } - - // Configure the baudrate. - if (!raspberry_soft_uart_set_baudrate(baudrate)) - { - printk(KERN_ALERT "soft_uart: Invalid baudrate.\n"); - } -} - -/** - * Does nothing. - * @param tty - */ -static void soft_uart_stop(struct tty_struct* tty) -{ - printk(KERN_DEBUG "soft_uart: soft_uart_stop.\n"); -} - -/** - * Does nothing. - * @param tty - */ -static void soft_uart_start(struct tty_struct* tty) -{ - printk(KERN_DEBUG "soft_uart: soft_uart_start.\n"); -} - -/** - * Does nothing. - * @param tty - */ -static void soft_uart_hangup(struct tty_struct* tty) -{ - printk(KERN_DEBUG "soft_uart: soft_uart_hangup.\n"); -} - -/** - * Does nothing. - * @param tty - */ -static int soft_uart_tiocmget(struct tty_struct* tty) -{ - return 0; -} - -/** - * Does nothing. - * @param tty - * @param set - * @param clear - */ -static int soft_uart_tiocmset(struct tty_struct* tty, unsigned int set, unsigned int clear) -{ - return 0; -} - -/** - * Does nothing. - * @param tty - * @param command - * @param parameter - */ -static int soft_uart_ioctl(struct tty_struct* tty, unsigned int command, unsigned int long parameter) -{ - int error = NONE; - - switch (command) - { - case TIOCMSET: - error = NONE; - break; - - case TIOCMGET: - error = NONE; - break; - - default: - error = -ENOIOCTLCMD; - break; - } - - return error; -} - -/** - * Does nothing. - * @param tty - */ -static void soft_uart_throttle(struct tty_struct* tty) -{ - printk(KERN_DEBUG "soft_uart: soft_uart_throttle.\n"); -} - -/** - * Does nothing. - * @param tty - */ -static void soft_uart_unthrottle(struct tty_struct* tty) -{ - printk(KERN_DEBUG "soft_uart: soft_uart_unthrottle.\n"); -} - -// Module entry points. -module_init(soft_uart_init); -module_exit(soft_uart_exit); + +#include "raspberry_soft_uart.h" + +#include +#include +#include +#include +#include + +#define SOFT_UART_MAJOR 0 +#define N_PORTS 1 +#define NONE 0 +#define TX_BUFFER_FLUSH_TIMEOUT 4000 // milliseconds + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Adriano Marto Reis"); +MODULE_DESCRIPTION("Software-UART for Raspberry Pi"); +MODULE_VERSION("0.2"); + +static int gpio_tx = 529; +module_param(gpio_tx, int, 0); + +static int gpio_rx = 539; +module_param(gpio_rx, int, 0); + +// Module prototypes. +static int soft_uart_open(struct tty_struct*, struct file*); +static void soft_uart_close(struct tty_struct*, struct file*); +static long int soft_uart_write(struct tty_struct*, const unsigned char*, long unsigned 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*, 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*); +static int soft_uart_tiocmget(struct tty_struct*); +static int soft_uart_tiocmset(struct tty_struct*, unsigned int, unsigned int); +static int soft_uart_ioctl(struct tty_struct*, unsigned int, unsigned int long); +static void soft_uart_throttle(struct tty_struct*); +static void soft_uart_unthrottle(struct tty_struct*); + +// Module operations. +static const struct tty_operations soft_uart_operations = { + .open = soft_uart_open, + .close = soft_uart_close, + .write = soft_uart_write, + .write_room = soft_uart_write_room, + .flush_buffer = soft_uart_flush_buffer, + .chars_in_buffer = soft_uart_chars_in_buffer, + .ioctl = soft_uart_ioctl, + .set_termios = soft_uart_set_termios, + .stop = soft_uart_stop, + .start = soft_uart_start, + .hangup = soft_uart_hangup, + .tiocmget = soft_uart_tiocmget, + .tiocmset = soft_uart_tiocmset, + .throttle = soft_uart_throttle, + .unthrottle = soft_uart_unthrottle +}; + +// Driver instance. +static struct tty_driver* soft_uart_driver = NULL; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) +static struct tty_port port; +#endif + +/** + * Module initialization. + */ +static int __init soft_uart_init(void) +{ + printk(KERN_INFO "soft_uart: Initializing module...\n"); + + if (!raspberry_soft_uart_init(gpio_tx, gpio_rx)) + { + printk(KERN_ALERT "soft_uart: Failed initialize GPIO.\n"); + raspberry_soft_uart_finalize(); + return -ENOMEM; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + printk(KERN_INFO "soft_uart: LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0).\n"); + + // Initializes the port. + tty_port_init(&port); + + // Allocates the driver. + soft_uart_driver = tty_alloc_driver(N_PORTS, TTY_DRIVER_REAL_RAW); + + // Returns if the allocation fails. + if (IS_ERR(soft_uart_driver)) + { + printk(KERN_ALERT "soft_uart: Failed to allocate the driver.\n"); + return -ENOMEM; + } +#else + printk(KERN_INFO "soft_uart: LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0).\n"); + + // Allocates the driver. + soft_uart_driver = alloc_tty_driver(N_PORTS); + + // Returns if the allocation fails. + if (!soft_uart_driver) + { + printk(KERN_ALERT "soft_uart: Failed to allocate the driver.\n"); + return -ENOMEM; + } +#endif + + // Initializes the driver. + soft_uart_driver->owner = THIS_MODULE; + soft_uart_driver->driver_name = "soft_uart"; + soft_uart_driver->name = "ttySOFT"; + soft_uart_driver->major = SOFT_UART_MAJOR; + soft_uart_driver->minor_start = 0; + soft_uart_driver->flags = TTY_DRIVER_REAL_RAW; + soft_uart_driver->type = TTY_DRIVER_TYPE_SERIAL; + soft_uart_driver->subtype = SERIAL_TYPE_NORMAL; + soft_uart_driver->init_termios = tty_std_termios; + soft_uart_driver->init_termios.c_ispeed = 4800; + soft_uart_driver->init_termios.c_ospeed = 4800; + soft_uart_driver->init_termios.c_cflag = B4800 | CREAD | CS8 | CLOCAL; + + // Sets the callbacks for the driver. + tty_set_operations(soft_uart_driver, &soft_uart_operations); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + // Link the port with the driver. + tty_port_link_device(&port, soft_uart_driver, 0); +#endif + + // Registers the TTY driver. + if (tty_register_driver(soft_uart_driver)) + { + printk(KERN_ALERT "soft_uart: Failed to register the driver.\n"); + tty_driver_kref_put(soft_uart_driver); + return -1; // return if registration fails + } + + printk(KERN_INFO "soft_uart: Module initialized.\n"); + return 0; +} + +/** + * Cleanup function that gets called when the module is unloaded. + */ +static void __exit soft_uart_exit(void) +{ + printk(KERN_INFO "soft_uart: Finalizing the module...\n"); + + // Finalizes the soft UART. + if (!raspberry_soft_uart_finalize()) + { + printk(KERN_ALERT "soft_uart: Something went wrong whilst finalizing the soft UART.\n"); + } + + // Unregisters the driver. + tty_unregister_driver(soft_uart_driver); + + tty_driver_kref_put(soft_uart_driver); + printk(KERN_INFO "soft_uart: Module finalized.\n"); +} + +/** + * Opens a given TTY device. + * @param tty given TTY device + * @param file + * @return error code. + */ +static int soft_uart_open(struct tty_struct* tty, struct file* file) +{ + int error = NONE; + + if (raspberry_soft_uart_open(tty)) + { + printk(KERN_INFO "soft_uart: Device opened.\n"); + } + else + { + printk(KERN_ALERT "soft_uart: Device busy.\n"); + error = -ENODEV; + } + + return error; +} + +/** + * Closes a given TTY device. + * @param tty + * @param file + */ +static void soft_uart_close(struct tty_struct* tty, struct file* file) +{ + // Waits for the TX buffer to be empty before closing the UART. + int wait_time = 0; + while ((raspberry_soft_uart_get_tx_queue_size() > 0) + && (wait_time < TX_BUFFER_FLUSH_TIMEOUT)) + { + msleep(100); + wait_time += 100; + } + + if (raspberry_soft_uart_close()) + { + printk(KERN_INFO "soft_uart: Device closed.\n"); + } + else + { + printk(KERN_ALERT "soft_uart: Could not close the device.\n"); + } +} + +/** + * Writes the contents of a given buffer into a given TTY device. + * @param tty given TTY device + * @param buffer given buffer + * @param buffer_size number of bytes contained in the given buffer + * @return number of bytes successfuly written into the TTY device + */ +static long int soft_uart_write(struct tty_struct* tty, const unsigned char* buffer, long unsigned buffer_size) +{ + return raspberry_soft_uart_send_string(buffer, buffer_size); +} + +/** + * Tells the kernel the number of bytes that can be written to a given TTY. + * @param tty given TTY + * @return number of bytes + */ +static unsigned int soft_uart_write_room(struct tty_struct* tty) +{ + return raspberry_soft_uart_get_tx_queue_room(); +} + +/** + * Does nothing. + * @param tty + */ +static void soft_uart_flush_buffer(struct tty_struct* tty) +{ +} + +/** + * Tells the kernel the number of bytes contained in the buffer of a given TTY. + * @param tty given TTY + * @return number of bytes + */ +static unsigned int soft_uart_chars_in_buffer(struct tty_struct* tty) +{ + return raspberry_soft_uart_get_tx_queue_size(); +} + +/** + * Sets the UART parameters for a given TTY (only the baudrate is taken into account). + * @param tty given TTY + * @param termios parameters + */ +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); + printk(KERN_INFO "soft_uart: soft_uart_set_termios: baudrate = %d.\n", baudrate); + + // Gets the cflag. +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + cflag = tty->termios.c_cflag; +#else + cflag = tty->termios->c_cflag; +#endif + + // Verifies the number of data bits (it must be 8). + if ((cflag & CSIZE) != CS8) + { + printk(KERN_ALERT "soft_uart: Invalid number of data bits.\n"); + } + + // Verifies the number of stop bits (it must be 1). + if (cflag & CSTOPB) + { + printk(KERN_ALERT "soft_uart: Invalid number of stop bits.\n"); + } + + // Verifies the parity (it must be none). + if (cflag & PARENB) + { + printk(KERN_ALERT "soft_uart: Invalid parity.\n"); + } + + // Configure the baudrate. + if (!raspberry_soft_uart_set_baudrate(baudrate)) + { + printk(KERN_ALERT "soft_uart: Invalid baudrate.\n"); + } +} + +/** + * Does nothing. + * @param tty + */ +static void soft_uart_stop(struct tty_struct* tty) +{ + printk(KERN_DEBUG "soft_uart: soft_uart_stop.\n"); +} + +/** + * Does nothing. + * @param tty + */ +static void soft_uart_start(struct tty_struct* tty) +{ + printk(KERN_DEBUG "soft_uart: soft_uart_start.\n"); +} + +/** + * Does nothing. + * @param tty + */ +static void soft_uart_hangup(struct tty_struct* tty) +{ + printk(KERN_DEBUG "soft_uart: soft_uart_hangup.\n"); +} + +/** + * Does nothing. + * @param tty + */ +static int soft_uart_tiocmget(struct tty_struct* tty) +{ + return 0; +} + +/** + * Does nothing. + * @param tty + * @param set + * @param clear + */ +static int soft_uart_tiocmset(struct tty_struct* tty, unsigned int set, unsigned int clear) +{ + return 0; +} + +/** + * Does nothing. + * @param tty + * @param command + * @param parameter + */ +static int soft_uart_ioctl(struct tty_struct* tty, unsigned int command, unsigned int long parameter) +{ + int error = NONE; + + switch (command) + { + case TIOCMSET: + error = NONE; + break; + + case TIOCMGET: + error = NONE; + break; + + default: + error = -ENOIOCTLCMD; + break; + } + + return error; +} + +/** + * Does nothing. + * @param tty + */ +static void soft_uart_throttle(struct tty_struct* tty) +{ + printk(KERN_DEBUG "soft_uart: soft_uart_throttle.\n"); +} + +/** + * Does nothing. + * @param tty + */ +static void soft_uart_unthrottle(struct tty_struct* tty) +{ + printk(KERN_DEBUG "soft_uart: soft_uart_unthrottle.\n"); +} + +// Module entry points. +module_init(soft_uart_init); +module_exit(soft_uart_exit); diff --git a/raspberry_soft_uart.c b/raspberry_soft_uart.c index 51a214c..bb721ff 100755 --- a/raspberry_soft_uart.c +++ b/raspberry_soft_uart.c @@ -2,7 +2,7 @@ #include "raspberry_soft_uart.h" #include "queue.h" -#include +#include #include #include #include @@ -10,7 +10,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(unsigned 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); @@ -37,27 +37,27 @@ static int rx_bit_index = -1; int raspberry_soft_uart_init(const int _gpio_tx, const int _gpio_rx) { bool success = true; - + mutex_init(¤t_tty_mutex); - + // Initializes the TX timer. hrtimer_init(&timer_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL); timer_tx.function = &handle_tx; - + // Initializes the RX timer. hrtimer_init(&timer_rx, CLOCK_MONOTONIC, HRTIMER_MODE_REL); timer_rx.function = &handle_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), @@ -66,7 +66,7 @@ int raspberry_soft_uart_init(const int _gpio_tx, const int _gpio_rx) "soft_uart_irq_handler", NULL) == 0; disable_irq(gpio_to_irq(gpio_rx)); - + return success; } @@ -96,6 +96,7 @@ int raspberry_soft_uart_open(struct tty_struct* tty) current_tty = tty; initialize_queue(&queue_tx); success = 1; + rx_bit_index = -1; enable_irq(gpio_to_irq(gpio_rx)); } mutex_unlock(¤t_tty_mutex); @@ -126,10 +127,10 @@ int raspberry_soft_uart_close(void) * @param baudrate desired baudrate * @return 1 if the operation is successful. 0 otherwise. */ -int raspberry_soft_uart_set_baudrate(const int baudrate) +int raspberry_soft_uart_set_baudrate(const int baudrate) { period = ktime_set(0, 1000000000/baudrate); - gpio_set_debounce(gpio_rx, 1000/baudrate/2); + gpiod_set_debounce(gpio_to_desc(gpio_rx), 1000/baudrate/2); return 1; } @@ -142,13 +143,13 @@ int raspberry_soft_uart_set_baudrate(const int baudrate) int raspberry_soft_uart_send_string(const unsigned char* string, int string_size) { int result = enqueue_string(&queue_tx, string, string_size); - + // Starts the TX timer if it is not already running. if (!hrtimer_active(&timer_tx)) { hrtimer_start(&timer_tx, period, HRTIMER_MODE_REL); } - + return result; } @@ -178,13 +179,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(unsigned int irq, void* device) { if (rx_bit_index == -1) { hrtimer_start(&timer_rx, ktime_set(0, period / 2), HRTIMER_MODE_REL); } - return (irq_handler_t) IRQ_HANDLED; + return (irqreturn_t) IRQ_HANDLED; } @@ -198,7 +199,7 @@ static enum hrtimer_restart handle_tx(struct hrtimer* timer) static int bit_index = -1; enum hrtimer_restart result = HRTIMER_NORESTART; bool must_restart_timer = false; - + // Start bit. if (bit_index == -1) { @@ -209,7 +210,7 @@ static enum hrtimer_restart handle_tx(struct hrtimer* timer) must_restart_timer = true; } } - + // Data bits. else if (0 <= bit_index && bit_index < 8) { @@ -217,7 +218,7 @@ static enum hrtimer_restart handle_tx(struct hrtimer* timer) bit_index++; must_restart_timer = true; } - + // Stop bit. else if (bit_index == 8) { @@ -226,14 +227,14 @@ static enum hrtimer_restart handle_tx(struct hrtimer* timer) bit_index = -1; must_restart_timer = get_queue_size(&queue_tx) > 0; } - + // Restarts the TX timer. if (must_restart_timer) { hrtimer_forward(&timer_tx, current_time, period); result = HRTIMER_RESTART; } - + return result; } @@ -247,7 +248,7 @@ static enum hrtimer_restart handle_rx(struct hrtimer* timer) int bit_value = gpio_get_value(gpio_rx); enum hrtimer_restart result = HRTIMER_NORESTART; bool must_restart_timer = false; - + // Start bit. if (rx_bit_index == -1) { @@ -255,7 +256,7 @@ static enum hrtimer_restart handle_rx(struct hrtimer* timer) character = 0; must_restart_timer = true; } - + // Data bits. else if (0 <= rx_bit_index && rx_bit_index < 8) { @@ -267,26 +268,26 @@ static enum hrtimer_restart handle_rx(struct hrtimer* timer) { character |= 0x0100; } - + rx_bit_index++; character >>= 1; must_restart_timer = true; } - + // Stop bit. else if (rx_bit_index == 8) { receive_character(character); rx_bit_index = -1; } - + // Restarts the RX timer. if (must_restart_timer) { hrtimer_forward(&timer_rx, current_time, period); result = HRTIMER_RESTART; } - + return result; }