|
@@ -34,6 +34,7 @@
|
|
#define RTL_ROM_LMP_8821A 0x8821
|
|
#define RTL_ROM_LMP_8821A 0x8821
|
|
#define RTL_ROM_LMP_8761A 0x8761
|
|
#define RTL_ROM_LMP_8761A 0x8761
|
|
#define RTL_ROM_LMP_8822B 0x8822
|
|
#define RTL_ROM_LMP_8822B 0x8822
|
|
|
|
+#define RTL_CONFIG_MAGIC 0x8723ab55
|
|
|
|
|
|
#define IC_MATCH_FL_LMPSUBV (1 << 0)
|
|
#define IC_MATCH_FL_LMPSUBV (1 << 0)
|
|
#define IC_MATCH_FL_HCIREV (1 << 1)
|
|
#define IC_MATCH_FL_HCIREV (1 << 1)
|
|
@@ -587,6 +588,114 @@ int btrtl_setup_realtek(struct hci_dev *hdev)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(btrtl_setup_realtek);
|
|
EXPORT_SYMBOL_GPL(btrtl_setup_realtek);
|
|
|
|
|
|
|
|
+static unsigned int btrtl_convert_baudrate(u32 device_baudrate)
|
|
|
|
+{
|
|
|
|
+ switch (device_baudrate) {
|
|
|
|
+ case 0x0252a00a:
|
|
|
|
+ return 230400;
|
|
|
|
+
|
|
|
|
+ case 0x05f75004:
|
|
|
|
+ return 921600;
|
|
|
|
+
|
|
|
|
+ case 0x00005004:
|
|
|
|
+ return 1000000;
|
|
|
|
+
|
|
|
|
+ case 0x04928002:
|
|
|
|
+ case 0x01128002:
|
|
|
|
+ return 1500000;
|
|
|
|
+
|
|
|
|
+ case 0x00005002:
|
|
|
|
+ return 2000000;
|
|
|
|
+
|
|
|
|
+ case 0x0000b001:
|
|
|
|
+ return 2500000;
|
|
|
|
+
|
|
|
|
+ case 0x04928001:
|
|
|
|
+ return 3000000;
|
|
|
|
+
|
|
|
|
+ case 0x052a6001:
|
|
|
|
+ return 3500000;
|
|
|
|
+
|
|
|
|
+ case 0x00005001:
|
|
|
|
+ return 4000000;
|
|
|
|
+
|
|
|
|
+ case 0x0252c014:
|
|
|
|
+ default:
|
|
|
|
+ return 115200;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int btrtl_get_uart_settings(struct hci_dev *hdev,
|
|
|
|
+ struct btrtl_device_info *btrtl_dev,
|
|
|
|
+ unsigned int *controller_baudrate,
|
|
|
|
+ u32 *device_baudrate, bool *flow_control)
|
|
|
|
+{
|
|
|
|
+ struct rtl_vendor_config *config;
|
|
|
|
+ struct rtl_vendor_config_entry *entry;
|
|
|
|
+ int i, total_data_len;
|
|
|
|
+ bool found = false;
|
|
|
|
+
|
|
|
|
+ total_data_len = btrtl_dev->cfg_len - sizeof(*config);
|
|
|
|
+ if (total_data_len <= 0) {
|
|
|
|
+ rtl_dev_warn(hdev, "no config loaded\n");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ config = (struct rtl_vendor_config *)btrtl_dev->cfg_data;
|
|
|
|
+ if (le32_to_cpu(config->signature) != RTL_CONFIG_MAGIC) {
|
|
|
|
+ rtl_dev_err(hdev, "invalid config magic\n");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (total_data_len < le16_to_cpu(config->total_len)) {
|
|
|
|
+ rtl_dev_err(hdev, "config is too short\n");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < total_data_len; ) {
|
|
|
|
+ entry = ((void *)config->entry) + i;
|
|
|
|
+
|
|
|
|
+ switch (le16_to_cpu(entry->offset)) {
|
|
|
|
+ case 0xc:
|
|
|
|
+ if (entry->len < sizeof(*device_baudrate)) {
|
|
|
|
+ rtl_dev_err(hdev, "invalid UART config entry\n");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ *device_baudrate = get_unaligned_le32(entry->data);
|
|
|
|
+ *controller_baudrate = btrtl_convert_baudrate(
|
|
|
|
+ *device_baudrate);
|
|
|
|
+
|
|
|
|
+ if (entry->len >= 13)
|
|
|
|
+ *flow_control = !!(entry->data[12] & BIT(2));
|
|
|
|
+ else
|
|
|
|
+ *flow_control = false;
|
|
|
|
+
|
|
|
|
+ found = true;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ default:
|
|
|
|
+ rtl_dev_dbg(hdev, "skipping config entry 0x%x (len %u)\n",
|
|
|
|
+ le16_to_cpu(entry->offset), entry->len);
|
|
|
|
+ break;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ i += sizeof(*entry) + entry->len;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!found) {
|
|
|
|
+ rtl_dev_err(hdev, "no UART config entry found\n");
|
|
|
|
+ return -ENOENT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rtl_dev_dbg(hdev, "device baudrate = 0x%08x\n", *device_baudrate);
|
|
|
|
+ rtl_dev_dbg(hdev, "controller baudrate = %u\n", *controller_baudrate);
|
|
|
|
+ rtl_dev_dbg(hdev, "flow control %d\n", *flow_control);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(btrtl_get_uart_settings);
|
|
|
|
+
|
|
MODULE_AUTHOR("Daniel Drake <drake@endlessm.com>");
|
|
MODULE_AUTHOR("Daniel Drake <drake@endlessm.com>");
|
|
MODULE_DESCRIPTION("Bluetooth support for Realtek devices ver " VERSION);
|
|
MODULE_DESCRIPTION("Bluetooth support for Realtek devices ver " VERSION);
|
|
MODULE_VERSION(VERSION);
|
|
MODULE_VERSION(VERSION);
|