1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/portability/cmsis_types.h>
9 #include <string.h>
10 #include "wrapper.h"
11
12 K_MEM_SLAB_DEFINE(cmsis_rtos_mutex_cb_slab, sizeof(struct cmsis_rtos_mutex_cb),
13 CONFIG_CMSIS_V2_MUTEX_MAX_COUNT, 4);
14
15 static const osMutexAttr_t init_mutex_attrs = {
16 .name = "ZephyrMutex",
17 .attr_bits = osMutexPrioInherit,
18 .cb_mem = NULL,
19 .cb_size = 0,
20 };
21
22 /**
23 * @brief Create and Initialize a Mutex object.
24 */
osMutexNew(const osMutexAttr_t * attr)25 osMutexId_t osMutexNew(const osMutexAttr_t *attr)
26 {
27 struct cmsis_rtos_mutex_cb *mutex;
28
29 if (k_is_in_isr()) {
30 return NULL;
31 }
32
33 if (attr == NULL) {
34 attr = &init_mutex_attrs;
35 }
36
37 __ASSERT(attr->attr_bits & osMutexPrioInherit,
38 "Zephyr supports osMutexPrioInherit by default. Do not unselect it\n");
39
40 __ASSERT(!(attr->attr_bits & osMutexRobust), "Zephyr does not support osMutexRobust.\n");
41
42 if (attr->cb_mem != NULL) {
43 __ASSERT(attr->cb_size == sizeof(struct cmsis_rtos_mutex_cb), "Invalid cb_size\n");
44 mutex = (struct cmsis_rtos_mutex_cb *)attr->cb_mem;
45 } else if (k_mem_slab_alloc(&cmsis_rtos_mutex_cb_slab, (void **)&mutex, K_MSEC(100)) != 0) {
46 return NULL;
47 }
48 memset(mutex, 0, sizeof(struct cmsis_rtos_mutex_cb));
49 mutex->is_cb_dynamic_allocation = attr->cb_mem == NULL;
50
51 k_mutex_init(&mutex->z_mutex);
52 mutex->state = attr->attr_bits;
53
54 mutex->name = (attr->name == NULL) ? init_mutex_attrs.name : attr->name;
55
56 return (osMutexId_t)mutex;
57 }
58
59 /**
60 * @brief Wait until a Mutex becomes available.
61 */
osMutexAcquire(osMutexId_t mutex_id,uint32_t timeout)62 osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout)
63 {
64 struct cmsis_rtos_mutex_cb *mutex = (struct cmsis_rtos_mutex_cb *)mutex_id;
65 int status;
66
67 if (mutex_id == NULL) {
68 return osErrorParameter;
69 }
70
71 if (k_is_in_isr()) {
72 return osErrorISR;
73 }
74
75 if (timeout == osWaitForever) {
76 status = k_mutex_lock(&mutex->z_mutex, K_FOREVER);
77 } else if (timeout == 0U) {
78 status = k_mutex_lock(&mutex->z_mutex, K_NO_WAIT);
79 } else {
80 status = k_mutex_lock(&mutex->z_mutex, K_TICKS(timeout));
81 }
82
83 if (timeout != 0 && (status == -EAGAIN || status == -EBUSY)) {
84 return osErrorTimeout;
85 } else if (status != 0) {
86 return osErrorResource;
87 } else {
88 return osOK;
89 }
90 }
91
92 /**
93 * @brief Release a Mutex that was obtained by osMutexWait.
94 */
osMutexRelease(osMutexId_t mutex_id)95 osStatus_t osMutexRelease(osMutexId_t mutex_id)
96 {
97 struct cmsis_rtos_mutex_cb *mutex = (struct cmsis_rtos_mutex_cb *)mutex_id;
98
99 if (mutex_id == NULL) {
100 return osErrorParameter;
101 }
102
103 if (k_is_in_isr()) {
104 return osErrorISR;
105 }
106
107 if (k_mutex_unlock(&mutex->z_mutex) != 0) {
108 return osErrorResource;
109 }
110
111 return osOK;
112 }
113
114 /**
115 * @brief Delete a Mutex that was created by osMutexCreate.
116 */
osMutexDelete(osMutexId_t mutex_id)117 osStatus_t osMutexDelete(osMutexId_t mutex_id)
118 {
119 struct cmsis_rtos_mutex_cb *mutex = (struct cmsis_rtos_mutex_cb *)mutex_id;
120
121 if (mutex_id == NULL) {
122 return osErrorParameter;
123 }
124
125 if (k_is_in_isr()) {
126 return osErrorISR;
127 }
128
129 /* The status code "osErrorResource" (mutex specified by parameter
130 * mutex_id is in an invalid mutex state) is not supported in Zephyr.
131 */
132 if (mutex->is_cb_dynamic_allocation) {
133 k_mem_slab_free(&cmsis_rtos_mutex_cb_slab, (void *)mutex);
134 }
135
136 return osOK;
137 }
138
osMutexGetOwner(osMutexId_t mutex_id)139 osThreadId_t osMutexGetOwner(osMutexId_t mutex_id)
140 {
141 struct cmsis_rtos_mutex_cb *mutex = (struct cmsis_rtos_mutex_cb *)mutex_id;
142
143 if (k_is_in_isr() || (mutex == NULL)) {
144 return NULL;
145 }
146
147 /* Mutex was not obtained before */
148 if (mutex->z_mutex.lock_count == 0U) {
149 return NULL;
150 }
151
152 return get_cmsis_thread_id(mutex->z_mutex.owner);
153 }
154
155 /**
156 * @brief Get name of a mutex.
157 * This function may be called from Interrupt Service Routines.
158 */
osMutexGetName(osMutexId_t mutex_id)159 const char *osMutexGetName(osMutexId_t mutex_id)
160 {
161 struct cmsis_rtos_mutex_cb *mutex = (struct cmsis_rtos_mutex_cb *)mutex_id;
162
163 if (mutex == NULL) {
164 return NULL;
165 }
166 return mutex->name;
167 }
168