|
19 | 19 | /* The longest command found so far is 5 bytes long */ |
20 | 20 | #define QNAP_MCU_MAX_CMD_SIZE 5 |
21 | 21 | #define QNAP_MCU_MAX_DATA_SIZE 36 |
| 22 | +#define QNAP_MCU_ERROR_SIZE 2 |
22 | 23 | #define QNAP_MCU_CHECKSUM_SIZE 1 |
23 | 24 |
|
24 | 25 | #define QNAP_MCU_RX_BUFFER_SIZE \ |
@@ -103,6 +104,48 @@ static int qnap_mcu_write(struct qnap_mcu *mcu, const u8 *data, u8 data_size) |
103 | 104 | return serdev_device_write(mcu->serdev, tx, length, HZ); |
104 | 105 | } |
105 | 106 |
|
| 107 | +static bool qnap_mcu_is_error_msg(size_t size) |
| 108 | +{ |
| 109 | + return (size == QNAP_MCU_ERROR_SIZE + QNAP_MCU_CHECKSUM_SIZE); |
| 110 | +} |
| 111 | + |
| 112 | +static bool qnap_mcu_reply_is_generic_error(unsigned char *buf, size_t size) |
| 113 | +{ |
| 114 | + if (!qnap_mcu_is_error_msg(size)) |
| 115 | + return false; |
| 116 | + |
| 117 | + if (buf[0] == '@' && buf[1] == '9') |
| 118 | + return true; |
| 119 | + |
| 120 | + return false; |
| 121 | +} |
| 122 | + |
| 123 | +static bool qnap_mcu_reply_is_checksum_error(unsigned char *buf, size_t size) |
| 124 | +{ |
| 125 | + if (!qnap_mcu_is_error_msg(size)) |
| 126 | + return false; |
| 127 | + |
| 128 | + if (buf[0] == '@' && buf[1] == '8') |
| 129 | + return true; |
| 130 | + |
| 131 | + return false; |
| 132 | +} |
| 133 | + |
| 134 | +static bool qnap_mcu_reply_is_any_error(struct qnap_mcu *mcu, unsigned char *buf, size_t size) |
| 135 | +{ |
| 136 | + if (qnap_mcu_reply_is_generic_error(buf, size)) { |
| 137 | + dev_err(&mcu->serdev->dev, "Controller sent generic error response\n"); |
| 138 | + return true; |
| 139 | + } |
| 140 | + |
| 141 | + if (qnap_mcu_reply_is_checksum_error(buf, size)) { |
| 142 | + dev_err(&mcu->serdev->dev, "Controller received invalid checksum for the command\n"); |
| 143 | + return true; |
| 144 | + } |
| 145 | + |
| 146 | + return false; |
| 147 | +} |
| 148 | + |
106 | 149 | static size_t qnap_mcu_receive_buf(struct serdev_device *serdev, const u8 *buf, size_t size) |
107 | 150 | { |
108 | 151 | struct device *dev = &serdev->dev; |
@@ -136,6 +179,24 @@ static size_t qnap_mcu_receive_buf(struct serdev_device *serdev, const u8 *buf, |
136 | 179 | } |
137 | 180 | } |
138 | 181 |
|
| 182 | + /* |
| 183 | + * We received everything the uart had to offer for now. |
| 184 | + * This could mean that either the uart will send more in a 2nd |
| 185 | + * receive run, or that the MCU cut the reply short because it |
| 186 | + * sent an error code instead of the expected reply. |
| 187 | + * |
| 188 | + * So check if the received data has the correct size for an error |
| 189 | + * reply and if it matches, is an actual error code. |
| 190 | + */ |
| 191 | + if (qnap_mcu_is_error_msg(reply->received) && |
| 192 | + qnap_mcu_verify_checksum(reply->data, reply->received) && |
| 193 | + qnap_mcu_reply_is_any_error(mcu, reply->data, reply->received)) { |
| 194 | + /* The reply was an error code, we're done */ |
| 195 | + reply->length = 0; |
| 196 | + |
| 197 | + complete(&reply->done); |
| 198 | + } |
| 199 | + |
139 | 200 | /* |
140 | 201 | * The only way to get out of the above loop and end up here |
141 | 202 | * is through consuming all of the supplied data, so here we |
@@ -182,10 +243,13 @@ int qnap_mcu_exec(struct qnap_mcu *mcu, |
182 | 243 | } |
183 | 244 |
|
184 | 245 | if (!qnap_mcu_verify_checksum(rx, reply->received)) { |
185 | | - dev_err(&mcu->serdev->dev, "Invalid Checksum received\n"); |
| 246 | + dev_err(&mcu->serdev->dev, "Invalid Checksum received from controller\n"); |
186 | 247 | return -EPROTO; |
187 | 248 | } |
188 | 249 |
|
| 250 | + if (qnap_mcu_reply_is_any_error(mcu, rx, reply->received)) |
| 251 | + return -EPROTO; |
| 252 | + |
189 | 253 | memcpy(reply_data, rx, reply_data_size); |
190 | 254 |
|
191 | 255 | return 0; |
|
0 commit comments