Add new D-Bus UART interface

New interface xyz.openbmc_project.Console.UART was added to P-D-I:
https://github.com/openbmc/phosphor-dbus-interfaces/blob/3826910ef8f91c05562a716929221745c92dd9d7/yaml/xyz/openbmc_project/Console/UART.interface.yaml

Tested: With obmc-console@ttyS2:
bmc# alias xyz=xyz.openbmc_project; alias XYZ=/xyz/openbmc_project
bmc# stty -F /dev/ttyS2 speed
921600
bmc# busctl introspect $xyz.Console.default $XYZ/console/default $xyz.Console.UART
NAME                             TYPE      SIGNATURE RESULT/VALUE FLAGS
.Baud                            property  t         921600       writable

bmc# busctl set-property $xyz.Console.default $XYZ/console/default \
        $xyz.Console.UART Baud t 57600
bmc# stty -F /dev/ttyS2 speed
57600

bmc# busctl set-property $xyz.Console.default $XYZ/console/default \
        $xyz.Console.UART Baud t 57601
Failed to set property Baud on interface xyz.openbmc_project.Console.UART: Invalid argument

Change-Id: I055f2a95c515636b38a694bf565b71aa648fe7b7
Signed-off-by: Jonathan Doman <jonathan.doman@intel.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7926339..542f34c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -22,6 +22,8 @@
 1. console-server: Add PTY support for testing purposes
 2. console-server: Add --console-id option
 3. console-server: Add DBUS interface to find console unix socket FD.
+4. Implement D-Bus interface `xyz.openbmc_project.Console.UART` for UART TTY
+   devices.
 
 ### Changed
 
@@ -41,6 +43,9 @@
    Deprecate the `socket-id` key in the configuration schema. Uses of
    `socket-id` should be directly replaced with `console-id`.
 
+2. Deprecate the `xyz.openbmc_project.console` D-Bus interface in favor of the
+   functionally equivalent `xyz.openbmc_project.Console.UART`.
+
 ### Fixed
 
 1. obmc-console: Consolidate handling of default socket-id
diff --git a/console-dbus.c b/console-dbus.c
index d4477c1..0b82376 100644
--- a/console-dbus.c
+++ b/console-dbus.c
@@ -28,6 +28,7 @@
 #define DBUS_ERR    "org.openbmc.error"
 #define DBUS_NAME   "xyz.openbmc_project.Console.%s"
 #define OBJ_NAME    "/xyz/openbmc_project/console/%s"
+#define UART_INTF   "xyz.openbmc_project.Console.UART"
 #define TTY_INTF    "xyz.openbmc_project.console"
 #define ACCESS_INTF "xyz.openbmc_project.Console.Access"
 
@@ -53,6 +54,7 @@
 	}
 }
 
+/* Deprecated */
 static int method_set_baud_rate(sd_bus_message *msg, void *userdata,
 				sd_bus_error *err)
 {
@@ -85,6 +87,41 @@
 	return sd_bus_reply_method_return(msg, "x", r);
 }
 
+static int set_baud_handler(sd_bus *bus, const char *path,
+			    const char *interface, const char *property,
+			    sd_bus_message *msg, void *userdata,
+			    sd_bus_error *err __attribute__((unused)))
+{
+	struct console *console = userdata;
+	uint64_t baudrate;
+	speed_t speed;
+	int r;
+
+	if (!console) {
+		return -ENOENT;
+	}
+
+	r = sd_bus_message_read(msg, "t", &baudrate);
+	if (r < 0 || baudrate > UINT32_MAX) {
+		return -EINVAL;
+	}
+
+	speed = parse_int_to_baud((uint32_t)baudrate);
+	if (!speed) {
+		warnx("Invalid baud rate: '%" PRIu64 "'", baudrate);
+		return -EINVAL;
+	}
+
+	assert(console->tty.type == TTY_DEVICE_UART);
+	console->tty.uart.baud = speed;
+	tty_change_baudrate(console);
+
+	sd_bus_emit_properties_changed(bus, path, interface, property, NULL);
+
+	return 1;
+}
+
+/* Deprecated */
 static int get_handler(sd_bus *bus __attribute__((unused)),
 		       const char *path __attribute__((unused)),
 		       const char *interface __attribute__((unused)),
@@ -107,6 +144,28 @@
 	return r;
 }
 
+static int get_baud_handler(sd_bus *bus __attribute__((unused)),
+			    const char *path __attribute__((unused)),
+			    const char *interface __attribute__((unused)),
+			    const char *property __attribute__((unused)),
+			    sd_bus_message *reply, void *userdata,
+			    sd_bus_error *error __attribute__((unused)))
+{
+	struct console *console = userdata;
+	uint64_t baudrate;
+	int r;
+
+	assert(console->tty.type == TTY_DEVICE_UART);
+	baudrate = parse_baud_to_int(console->tty.uart.baud);
+	if (!baudrate) {
+		warnx("Invalid baud rate: '%d'", console->tty.uart.baud);
+	}
+
+	r = sd_bus_message_append(reply, "t", baudrate);
+
+	return r;
+}
+
 static int method_connect(sd_bus_message *msg, void *userdata,
 			  sd_bus_error *err)
 {
@@ -138,14 +197,24 @@
 	return rc;
 }
 
+/* Deprecated */
 static const sd_bus_vtable console_tty_vtable[] = {
-	SD_BUS_VTABLE_START(0),
+	SD_BUS_VTABLE_START(SD_BUS_VTABLE_DEPRECATED),
 	SD_BUS_METHOD("setBaudRate", "u", "x", method_set_baud_rate,
 		      SD_BUS_VTABLE_UNPRIVILEGED),
 	SD_BUS_PROPERTY("baudrate", "u", get_handler, 0, 0),
 	SD_BUS_VTABLE_END,
 };
 
+static const sd_bus_vtable console_uart_vtable[] = {
+	SD_BUS_VTABLE_START(0),
+	SD_BUS_WRITABLE_PROPERTY("Baud", "t", get_baud_handler,
+				 set_baud_handler, 0,
+				 SD_BUS_VTABLE_UNPRIVILEGED |
+					 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+	SD_BUS_VTABLE_END,
+};
+
 static const sd_bus_vtable console_access_vtable[] = {
 	SD_BUS_VTABLE_START(0),
 	SD_BUS_METHOD("Connect", SD_BUS_NO_ARGS, "h", method_connect,
@@ -184,7 +253,7 @@
 	}
 
 	if (console->tty.type == TTY_DEVICE_UART) {
-		/* Register tty interface */
+		/* Register tty interface - Deprecated */
 		r = sd_bus_add_object_vtable(console->bus, NULL, obj_name,
 					     TTY_INTF, console_tty_vtable,
 					     console);
@@ -192,6 +261,15 @@
 			warnx("Failed to issue method call: %s", strerror(-r));
 			return;
 		}
+		/* Register UART interface */
+		r = sd_bus_add_object_vtable(console->bus, NULL, obj_name,
+					     UART_INTF, console_uart_vtable,
+					     console);
+		if (r < 0) {
+			warnx("Failed to register UART interface: %s",
+			      strerror(-r));
+			return;
+		}
 	}
 
 	/* Register access interface */