From 7dbe1f497b445ead3a6c5f0895d002960a2b07f2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 5 May 2016 14:32:30 +0530 Subject: [PATCH] greybus: UART: convert to a gpbridge driver This converts the UART driver to be a gpbridge driver, moving it away from the "legacy" interface. Testing Done: Tested on gbsim. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Vaibhav Hiremath [vaibhav.hiremath@linaro.org: 1.Changed code to retain init/exit fns of drivers. 2.Exit path fix. 3. Fixed review comments] Reviewed-by: Viresh Kumar Tested-by: Viresh Kumar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/gpbridge.c | 9 ++- drivers/staging/greybus/gpbridge.h | 4 +- drivers/staging/greybus/legacy.c | 1 - drivers/staging/greybus/uart.c | 114 ++++++++++++++++++----------- 4 files changed, 80 insertions(+), 48 deletions(-) diff --git a/drivers/staging/greybus/gpbridge.c b/drivers/staging/greybus/gpbridge.c index 5a12b344f065..2a23a309b83e 100644 --- a/drivers/staging/greybus/gpbridge.c +++ b/drivers/staging/greybus/gpbridge.c @@ -252,6 +252,7 @@ static int gb_gpbridge_probe(struct gb_bundle *bundle, static const struct greybus_bundle_id gb_gpbridge_id_table[] = { { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_BRIDGED_PHY) }, + { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_UART) }, { }, }; MODULE_DEVICE_TABLE(greybus, gb_gpbridge_id_table); @@ -287,8 +288,8 @@ static int __init gpbridge_init(void) pr_err("error initializing pwm protocol\n"); goto error_pwm; } - if (gb_uart_protocol_init()) { - pr_err("error initializing uart protocol\n"); + if (gb_uart_driver_init()) { + pr_err("error initializing uart driver\n"); goto error_uart; } if (gb_sdio_protocol_init()) { @@ -317,7 +318,7 @@ error_i2c: error_usb: gb_sdio_protocol_exit(); error_sdio: - gb_uart_protocol_exit(); + gb_uart_driver_exit(); error_uart: gb_pwm_protocol_exit(); error_pwm: @@ -337,7 +338,7 @@ static void __exit gpbridge_exit(void) gb_i2c_protocol_exit(); gb_usb_protocol_exit(); gb_sdio_protocol_exit(); - gb_uart_protocol_exit(); + gb_uart_driver_exit(); gb_pwm_protocol_exit(); gb_gpio_protocol_exit(); diff --git a/drivers/staging/greybus/gpbridge.h b/drivers/staging/greybus/gpbridge.h index aa2cdc08223f..fb17f02861d1 100644 --- a/drivers/staging/greybus/gpbridge.h +++ b/drivers/staging/greybus/gpbridge.h @@ -72,8 +72,8 @@ extern void gb_gpio_protocol_exit(void); extern int gb_pwm_protocol_init(void); extern void gb_pwm_protocol_exit(void); -extern int gb_uart_protocol_init(void); -extern void gb_uart_protocol_exit(void); +extern int gb_uart_driver_init(void); +extern void gb_uart_driver_exit(void); extern int gb_sdio_protocol_init(void); extern void gb_sdio_protocol_exit(void); diff --git a/drivers/staging/greybus/legacy.c b/drivers/staging/greybus/legacy.c index 58b277979a60..f391a5dccba4 100644 --- a/drivers/staging/greybus/legacy.c +++ b/drivers/staging/greybus/legacy.c @@ -238,7 +238,6 @@ static void legacy_disconnect(struct gb_bundle *bundle) static const struct greybus_bundle_id legacy_id_table[] = { { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_GPIO) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_I2C) }, - { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_UART) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_USB) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SDIO) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_PWM) }, diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c index be718918c135..eb83c04d7b69 100644 --- a/drivers/staging/greybus/uart.c +++ b/drivers/staging/greybus/uart.c @@ -42,6 +42,7 @@ struct gb_tty_line_coding { }; struct gb_tty { + struct gpbridge_device *gpbdev; struct tty_port port; void *buffer; size_t buffer_payload_max; @@ -78,7 +79,7 @@ static int gb_uart_receive_data_handler(struct gb_operation *op) unsigned long tty_flags = TTY_NORMAL; if (request->payload_size < sizeof(*receive_data)) { - dev_err(&connection->bundle->dev, + dev_err(&gb_tty->gpbdev->dev, "short receive-data request received (%zu < %zu)\n", request->payload_size, sizeof(*receive_data)); return -EINVAL; @@ -88,7 +89,7 @@ static int gb_uart_receive_data_handler(struct gb_operation *op) recv_data_size = le16_to_cpu(receive_data->size); if (recv_data_size != request->payload_size - sizeof(*receive_data)) { - dev_err(&connection->bundle->dev, + dev_err(&gb_tty->gpbdev->dev, "malformed receive-data request received (%u != %zu)\n", recv_data_size, request->payload_size - sizeof(*receive_data)); @@ -113,7 +114,7 @@ static int gb_uart_receive_data_handler(struct gb_operation *op) count = tty_insert_flip_string_fixed_flag(port, receive_data->data, tty_flags, recv_data_size); if (count != recv_data_size) { - dev_err(&connection->bundle->dev, + dev_err(&gb_tty->gpbdev->dev, "UART: RX 0x%08x bytes only wrote 0x%08x\n", recv_data_size, count); } @@ -130,7 +131,7 @@ static int gb_uart_serial_state_handler(struct gb_operation *op) struct gb_uart_serial_state_request *serial_state; if (request->payload_size < sizeof(*serial_state)) { - dev_err(&connection->bundle->dev, + dev_err(&gb_tty->gpbdev->dev, "short serial-state event received (%zu < %zu)\n", request->payload_size, sizeof(*serial_state)); return -EINVAL; @@ -142,9 +143,11 @@ static int gb_uart_serial_state_handler(struct gb_operation *op) return 0; } -static int gb_uart_request_recv(u8 type, struct gb_operation *op) +static int gb_uart_request_handler(struct gb_operation *op) { struct gb_connection *connection = op->connection; + struct gb_tty *gb_tty = gb_connection_get_data(connection); + int type = op->type; int ret; switch (type) { @@ -155,7 +158,7 @@ static int gb_uart_request_recv(u8 type, struct gb_operation *op) ret = gb_uart_serial_state_handler(op); break; default: - dev_err(&connection->bundle->dev, + dev_err(&gb_tty->gpbdev->dev, "unsupported unsolicited request: 0x%02x\n", type); ret = -EINVAL; } @@ -209,7 +212,7 @@ static int send_break(struct gb_tty *gb_tty, u8 state) struct gb_uart_set_break_request request; if ((state != 0) && (state != 1)) { - dev_err(&gb_tty->connection->bundle->dev, + dev_err(&gb_tty->gpbdev->dev, "invalid break state of %d\n", state); return -EINVAL; } @@ -619,8 +622,10 @@ static struct tty_port_operations null_ops = { }; static int gb_tty_init(void); static void gb_tty_exit(void); -static int gb_uart_connection_init(struct gb_connection *connection) +static int gb_uart_probe(struct gpbridge_device *gpbdev, + const struct gpbridge_device_id *id) { + struct gb_connection *connection; size_t max_payload; struct gb_tty *gb_tty; struct device *tty_dev; @@ -639,13 +644,21 @@ static int gb_uart_connection_init(struct gb_connection *connection) gb_tty = kzalloc(sizeof(*gb_tty), GFP_KERNEL); if (!gb_tty) { retval = -ENOMEM; - goto error_alloc; + goto exit_tty; + } + + connection = gb_connection_create(gpbdev->bundle, + le16_to_cpu(gpbdev->cport_desc->id), + gb_uart_request_handler); + if (IS_ERR(connection)) { + retval = PTR_ERR(connection); + goto exit_tty_free; } max_payload = gb_operation_get_payload_size_max(connection); if (max_payload < sizeof(struct gb_uart_send_data_request)) { retval = -EINVAL; - goto error_payload; + goto exit_connection_destroy; } gb_tty->buffer_payload_max = max_payload - @@ -654,22 +667,19 @@ static int gb_uart_connection_init(struct gb_connection *connection) gb_tty->buffer = kzalloc(gb_tty->buffer_payload_max, GFP_KERNEL); if (!gb_tty->buffer) { retval = -ENOMEM; - goto error_payload; + goto exit_connection_destroy; } - gb_tty->connection = connection; - gb_connection_set_data(connection, gb_tty); - minor = alloc_minor(gb_tty); if (minor < 0) { if (minor == -ENOSPC) { dev_err(&connection->bundle->dev, "no more free minor numbers\n"); retval = -ENODEV; - goto error_minor; + } else { + retval = minor; } - retval = minor; - goto error_minor; + goto exit_buf_free; } gb_tty->minor = minor; @@ -681,6 +691,19 @@ static int gb_uart_connection_init(struct gb_connection *connection) tty_port_init(&gb_tty->port); gb_tty->port.ops = &null_ops; + gb_tty->connection = connection; + gb_tty->gpbdev = gpbdev; + gb_connection_set_data(connection, gb_tty); + gb_gpbridge_set_data(gpbdev, gb_tty); + + retval = gb_connection_enable_tx(connection); + if (retval) + goto exit_release_minor; + + retval = gb_gpbridge_get_version(connection); + if (retval) + goto exit_connection_disable; + send_control(gb_tty, gb_tty->ctrlout); /* initialize the uart to be 9600n81 */ @@ -690,41 +713,47 @@ static int gb_uart_connection_init(struct gb_connection *connection) gb_tty->line_coding.data_bits = 8; send_line_coding(gb_tty); + retval = gb_connection_enable(connection); + if (retval) + goto exit_connection_disable; + tty_dev = tty_port_register_device(&gb_tty->port, gb_tty_driver, minor, - &connection->bundle->dev); + &gpbdev->dev); if (IS_ERR(tty_dev)) { retval = PTR_ERR(tty_dev); - goto error; + goto exit_connection_disable; } + return 0; -error: - tty_port_destroy(&gb_tty->port); + +exit_connection_disable: + gb_connection_disable(connection); +exit_release_minor: release_minor(gb_tty); -error_minor: - gb_connection_set_data(connection, NULL); +exit_buf_free: kfree(gb_tty->buffer); -error_payload: +exit_connection_destroy: + gb_connection_destroy(connection); +exit_tty_free: kfree(gb_tty); -error_alloc: +exit_tty: if (atomic_dec_return(&reference_count) == 0) gb_tty_exit(); + return retval; } -static void gb_uart_connection_exit(struct gb_connection *connection) +static void gb_uart_remove(struct gpbridge_device *gpbdev) { - struct gb_tty *gb_tty = gb_connection_get_data(connection); + struct gb_tty *gb_tty = gb_gpbridge_get_data(gpbdev); + struct gb_connection *connection = gb_tty->connection; struct tty_struct *tty; - if (!gb_tty) - return; - mutex_lock(&gb_tty->mutex); gb_tty->disconnected = true; wake_up_all(&gb_tty->wioctl); - gb_connection_set_data(connection, NULL); mutex_unlock(&gb_tty->mutex); tty = tty_port_tty_get(&gb_tty->port); @@ -732,13 +761,15 @@ static void gb_uart_connection_exit(struct gb_connection *connection) tty_vhangup(tty); tty_kref_put(tty); } - /* FIXME - stop all traffic */ + gb_connection_disable_rx(connection); tty_unregister_device(gb_tty_driver, gb_tty->minor); /* FIXME - free transmit / receive buffers */ + gb_connection_disable(connection); tty_port_destroy(&gb_tty->port); + gb_connection_destroy(connection); kfree(gb_tty->buffer); kfree(gb_tty); @@ -790,14 +821,15 @@ static void gb_tty_exit(void) idr_destroy(&tty_minors); } -static struct gb_protocol uart_protocol = { - .name = "uart", - .id = GREYBUS_PROTOCOL_UART, - .major = GB_UART_VERSION_MAJOR, - .minor = GB_UART_VERSION_MINOR, - .connection_init = gb_uart_connection_init, - .connection_exit = gb_uart_connection_exit, - .request_recv = gb_uart_request_recv, +static const struct gpbridge_device_id gb_uart_id_table[] = { + { GPBRIDGE_PROTOCOL(GREYBUS_PROTOCOL_UART) }, + { }, }; -gb_builtin_protocol_driver(uart_protocol); +static struct gpbridge_driver uart_driver = { + .name = "uart", + .probe = gb_uart_probe, + .remove = gb_uart_remove, + .id_table = gb_uart_id_table, +}; +gb_gpbridge_builtin_driver(uart_driver); -- 2.20.1