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