|
@@ -232,6 +232,26 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+void skip_change_remote_baud(unsigned char **ptr, long *len)
|
|
|
+{
|
|
|
+ unsigned char *nxt_action, *cur_action;
|
|
|
+ cur_action = *ptr;
|
|
|
+
|
|
|
+ nxt_action = cur_action + sizeof(struct bts_action) +
|
|
|
+ ((struct bts_action *) cur_action)->size;
|
|
|
+
|
|
|
+ if (((struct bts_action *) nxt_action)->type != ACTION_WAIT_EVENT) {
|
|
|
+ pr_err("invalid action after change remote baud command");
|
|
|
+ } else {
|
|
|
+ *ptr = *ptr + sizeof(struct bts_action) +
|
|
|
+ ((struct bts_action *)nxt_action)->size;
|
|
|
+ *len = *len - (sizeof(struct bts_action) +
|
|
|
+ ((struct bts_action *)nxt_action)->size);
|
|
|
+ /* warn user on not commenting these in firmware */
|
|
|
+ pr_warn("skipping the wait event of change remote baud");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* download_firmware -
|
|
|
* internal function which parses through the .bts firmware
|
|
@@ -244,6 +264,9 @@ static long download_firmware(struct kim_data_s *kim_gdata)
|
|
|
unsigned char *ptr = NULL;
|
|
|
unsigned char *action_ptr = NULL;
|
|
|
unsigned char bts_scr_name[30] = { 0 }; /* 30 char long bts scr name? */
|
|
|
+ int wr_room_space;
|
|
|
+ int cmd_size;
|
|
|
+ unsigned long timeout;
|
|
|
|
|
|
err = read_local_version(kim_gdata, bts_scr_name);
|
|
|
if (err != 0) {
|
|
@@ -280,13 +303,43 @@ static long download_firmware(struct kim_data_s *kim_gdata)
|
|
|
0xFF36)) {
|
|
|
/* ignore remote change
|
|
|
* baud rate HCI VS command */
|
|
|
- pr_err
|
|
|
- (" change remote baud"
|
|
|
+ pr_warn("change remote baud"
|
|
|
" rate command in firmware");
|
|
|
+ skip_change_remote_baud(&ptr, &len);
|
|
|
break;
|
|
|
}
|
|
|
+ /*
|
|
|
+ * Make sure we have enough free space in uart
|
|
|
+ * tx buffer to write current firmware command
|
|
|
+ */
|
|
|
+ cmd_size = ((struct bts_action *)ptr)->size;
|
|
|
+ timeout = jiffies + msecs_to_jiffies(CMD_WR_TIME);
|
|
|
+ do {
|
|
|
+ wr_room_space =
|
|
|
+ st_get_uart_wr_room(kim_gdata->core_data);
|
|
|
+ if (wr_room_space < 0) {
|
|
|
+ pr_err("Unable to get free "
|
|
|
+ "space info from uart tx buffer");
|
|
|
+ release_firmware(kim_gdata->fw_entry);
|
|
|
+ return wr_room_space;
|
|
|
+ }
|
|
|
+ mdelay(1); /* wait 1ms before checking room */
|
|
|
+ } while ((wr_room_space < cmd_size) &&
|
|
|
+ time_before(jiffies, timeout));
|
|
|
+
|
|
|
+ /* Timeout happened ? */
|
|
|
+ if (time_after_eq(jiffies, timeout)) {
|
|
|
+ pr_err("Timeout while waiting for free "
|
|
|
+ "free space in uart tx buffer");
|
|
|
+ release_firmware(kim_gdata->fw_entry);
|
|
|
+ return -ETIMEDOUT;
|
|
|
+ }
|
|
|
|
|
|
- INIT_COMPLETION(kim_gdata->kim_rcvd);
|
|
|
+ /*
|
|
|
+ * Free space found in uart buffer, call st_int_write
|
|
|
+ * to send current firmware command to the uart tx
|
|
|
+ * buffer.
|
|
|
+ */
|
|
|
err = st_int_write(kim_gdata->core_data,
|
|
|
((struct bts_action_send *)action_ptr)->data,
|
|
|
((struct bts_action *)ptr)->size);
|
|
@@ -294,15 +347,28 @@ static long download_firmware(struct kim_data_s *kim_gdata)
|
|
|
release_firmware(kim_gdata->fw_entry);
|
|
|
return err;
|
|
|
}
|
|
|
+ /*
|
|
|
+ * Check number of bytes written to the uart tx buffer
|
|
|
+ * and requested command write size
|
|
|
+ */
|
|
|
+ if (err != cmd_size) {
|
|
|
+ pr_err("Number of bytes written to uart "
|
|
|
+ "tx buffer are not matching with "
|
|
|
+ "requested cmd write size");
|
|
|
+ release_firmware(kim_gdata->fw_entry);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case ACTION_WAIT_EVENT: /* wait */
|
|
|
if (!wait_for_completion_timeout
|
|
|
- (&kim_gdata->kim_rcvd,
|
|
|
- msecs_to_jiffies(CMD_RESP_TIME))) {
|
|
|
- pr_err
|
|
|
- (" response timeout during fw download ");
|
|
|
+ (&kim_gdata->kim_rcvd,
|
|
|
+ msecs_to_jiffies(CMD_RESP_TIME))) {
|
|
|
+ pr_err("response timeout during fw download ");
|
|
|
/* timed out */
|
|
|
release_firmware(kim_gdata->fw_entry);
|
|
|
return -ETIMEDOUT;
|
|
|
}
|
|
|
+ INIT_COMPLETION(kim_gdata->kim_rcvd);
|
|
|
break;
|
|
|
case ACTION_DELAY: /* sleep */
|
|
|
pr_info("sleep command in scr");
|