|
@@ -56,6 +56,8 @@ static union pd_msg *last_dpm_request = NULL;
|
56
|
56
|
static bool capability_match = false;
|
57
|
57
|
/* Whether or not we have an explicit contract */
|
58
|
58
|
static bool explicit_contract = false;
|
|
59
|
+/* Whether or not we're receiving minimum power*/
|
|
60
|
+static bool min_power = false;
|
59
|
61
|
/* Keep track of how many hard resets we've sent */
|
60
|
62
|
static int hard_reset_counter = 0;
|
61
|
63
|
/* Policy Engine thread mailbox */
|
|
@@ -183,6 +185,8 @@ static enum policy_engine_state pe_sink_select_cap(void)
|
183
|
185
|
/* Transition to Sink Standby if necessary */
|
184
|
186
|
pdb_dpm_sink_standby();
|
185
|
187
|
|
|
188
|
+ min_power = false;
|
|
189
|
+
|
186
|
190
|
chPoolFree(&pdb_msg_pool, policy_engine_message);
|
187
|
191
|
policy_engine_message = NULL;
|
188
|
192
|
return PESinkTransitionSink;
|
|
@@ -203,9 +207,10 @@ static enum policy_engine_state pe_sink_select_cap(void)
|
203
|
207
|
return PESinkWaitCap;
|
204
|
208
|
/* If we do have an explicit contract, go to the ready state */
|
205
|
209
|
} else {
|
206
|
|
- /* TODO: we should take note if we got here from a Wait
|
207
|
|
- * message, because we Should run the SinkRequestTimer in the
|
208
|
|
- * Ready state if that's the case. */
|
|
210
|
+ /* If we got here from a Wait message, we Should run
|
|
211
|
+ * SinkRequestTimer in the Ready state. */
|
|
212
|
+ min_power = (PD_MSGTYPE_GET(policy_engine_message) == PD_MSGTYPE_WAIT);
|
|
213
|
+
|
209
|
214
|
chPoolFree(&pdb_msg_pool, policy_engine_message);
|
210
|
215
|
policy_engine_message = NULL;
|
211
|
216
|
return PESinkReady;
|
|
@@ -242,7 +247,7 @@ static enum policy_engine_state pe_sink_transition_sink(void)
|
242
|
247
|
explicit_contract = true;
|
243
|
248
|
|
244
|
249
|
/* Set the output appropriately */
|
245
|
|
- pdb_dpm_output_set(capability_match);
|
|
250
|
+ pdb_dpm_output_set(capability_match && !min_power);
|
246
|
251
|
|
247
|
252
|
chPoolFree(&pdb_msg_pool, policy_engine_message);
|
248
|
253
|
policy_engine_message = NULL;
|
|
@@ -265,9 +270,16 @@ static enum policy_engine_state pe_sink_transition_sink(void)
|
265
|
270
|
|
266
|
271
|
static enum policy_engine_state pe_sink_ready(void)
|
267
|
272
|
{
|
|
273
|
+ eventmask_t evt;
|
|
274
|
+
|
268
|
275
|
/* Wait for an event */
|
269
|
|
- eventmask_t evt = chEvtWaitAny(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET
|
270
|
|
- | PDB_EVT_PE_I_OVRTEMP);
|
|
276
|
+ if (min_power) {
|
|
277
|
+ evt = chEvtWaitAnyTimeout(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET
|
|
278
|
+ | PDB_EVT_PE_I_OVRTEMP, PD_T_SINK_REQUEST);
|
|
279
|
+ } else {
|
|
280
|
+ evt = chEvtWaitAny(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET
|
|
281
|
+ | PDB_EVT_PE_I_OVRTEMP);
|
|
282
|
+ }
|
271
|
283
|
|
272
|
284
|
/* If we got reset signaling, transition to default */
|
273
|
285
|
if (evt & PDB_EVT_PE_RESET) {
|
|
@@ -279,6 +291,12 @@ static enum policy_engine_state pe_sink_ready(void)
|
279
|
291
|
return PESinkHardReset;
|
280
|
292
|
}
|
281
|
293
|
|
|
294
|
+ /* If no event was received, the timer ran out. */
|
|
295
|
+ if (evt == 0) {
|
|
296
|
+ /* Repeat our Request message */
|
|
297
|
+ return PESinkSelectCap;
|
|
298
|
+ }
|
|
299
|
+
|
282
|
300
|
/* If we received a message */
|
283
|
301
|
if (evt & PDB_EVT_PE_MSG_RX) {
|
284
|
302
|
if (chMBFetch(&pdb_pe_mailbox, (msg_t *) &policy_engine_message, TIME_IMMEDIATE) == MSG_OK) {
|
|
@@ -330,14 +348,23 @@ static enum policy_engine_state pe_sink_ready(void)
|
330
|
348
|
chPoolFree(&pdb_msg_pool, policy_engine_message);
|
331
|
349
|
policy_engine_message = NULL;
|
332
|
350
|
return PESinkSendReject;
|
333
|
|
- /* Reject GotoMin messages
|
334
|
|
- * Until we actually support GiveBack, this is the correct
|
335
|
|
- * behavior according to S. 6.3.4 */
|
|
351
|
+ /* Handle GotoMin messages */
|
336
|
352
|
} else if (PD_MSGTYPE_GET(policy_engine_message) == PD_MSGTYPE_GOTOMIN
|
337
|
353
|
&& PD_NUMOBJ_GET(policy_engine_message) == 0) {
|
338
|
|
- chPoolFree(&pdb_msg_pool, policy_engine_message);
|
339
|
|
- policy_engine_message = NULL;
|
340
|
|
- return PESinkSendReject;
|
|
354
|
+ if (pdb_dpm_giveback_enabled()) {
|
|
355
|
+ /* We support GiveBack, so go to minimum power */
|
|
356
|
+ pdb_dpm_output_set(false);
|
|
357
|
+ min_power = true;
|
|
358
|
+
|
|
359
|
+ chPoolFree(&pdb_msg_pool, policy_engine_message);
|
|
360
|
+ policy_engine_message = NULL;
|
|
361
|
+ return PESinkTransitionSink;
|
|
362
|
+ } else {
|
|
363
|
+ /* We don't support GiveBack, so send a Reject */
|
|
364
|
+ chPoolFree(&pdb_msg_pool, policy_engine_message);
|
|
365
|
+ policy_engine_message = NULL;
|
|
366
|
+ return PESinkSendReject;
|
|
367
|
+ }
|
341
|
368
|
/* Evaluate new Source_Capabilities */
|
342
|
369
|
} else if (PD_MSGTYPE_GET(policy_engine_message) == PD_MSGTYPE_SOURCE_CAPABILITIES
|
343
|
370
|
&& PD_NUMOBJ_GET(policy_engine_message) > 0) {
|