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 
11 K_MEM_SLAB_DEFINE(cmsis_rtos_semaphore_cb_slab, sizeof(struct cmsis_rtos_semaphore_cb),
12 		  CONFIG_CMSIS_V2_SEMAPHORE_MAX_COUNT, 4);
13 
14 static const osSemaphoreAttr_t init_sema_attrs = {
15 	.name = "ZephyrSem",
16 	.attr_bits = 0,
17 	.cb_mem = NULL,
18 	.cb_size = 0,
19 };
20 
21 /**
22  * @brief Create and Initialize a semaphore object.
23  */
osSemaphoreNew(uint32_t max_count,uint32_t initial_count,const osSemaphoreAttr_t * attr)24 osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count,
25 			       const osSemaphoreAttr_t *attr)
26 {
27 	struct cmsis_rtos_semaphore_cb *semaphore;
28 
29 	if (k_is_in_isr()) {
30 		return NULL;
31 	}
32 
33 	if (attr == NULL) {
34 		attr = &init_sema_attrs;
35 	}
36 
37 	if (attr->cb_mem != NULL) {
38 		__ASSERT(attr->cb_size == sizeof(struct cmsis_rtos_semaphore_cb),
39 			 "Invalid cb_size\n");
40 		semaphore = (struct cmsis_rtos_semaphore_cb *)attr->cb_mem;
41 	} else if (k_mem_slab_alloc(&cmsis_rtos_semaphore_cb_slab, (void **)&semaphore,
42 				    K_MSEC(100)) != 0) {
43 		return NULL;
44 	}
45 	(void)memset(semaphore, 0, sizeof(struct cmsis_rtos_semaphore_cb));
46 	semaphore->is_cb_dynamic_allocation = attr->cb_mem == NULL;
47 
48 	k_sem_init(&semaphore->z_semaphore, initial_count, max_count);
49 
50 	if (attr->name == NULL) {
51 		strncpy(semaphore->name, init_sema_attrs.name, sizeof(semaphore->name) - 1);
52 	} else {
53 		strncpy(semaphore->name, attr->name, sizeof(semaphore->name) - 1);
54 	}
55 
56 	return (osSemaphoreId_t)semaphore;
57 }
58 
59 /**
60  * @brief Wait until a semaphore becomes available.
61  */
osSemaphoreAcquire(osSemaphoreId_t semaphore_id,uint32_t timeout)62 osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout)
63 {
64 	struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id;
65 	int status;
66 
67 	if (semaphore_id == NULL) {
68 		return osErrorParameter;
69 	}
70 
71 	/* Can be called from ISRs only if timeout is set to 0 */
72 	if (timeout > 0 && k_is_in_isr()) {
73 		return osErrorParameter;
74 	}
75 
76 	if (timeout == osWaitForever) {
77 		status = k_sem_take(&semaphore->z_semaphore, K_FOREVER);
78 	} else if (timeout == 0U) {
79 		status = k_sem_take(&semaphore->z_semaphore, K_NO_WAIT);
80 	} else {
81 		status = k_sem_take(&semaphore->z_semaphore, K_TICKS(timeout));
82 	}
83 
84 	if (status == -EBUSY) {
85 		return osErrorResource;
86 	} else if (status == -EAGAIN) {
87 		return osErrorTimeout;
88 	} else {
89 		return osOK;
90 	}
91 }
92 
osSemaphoreGetCount(osSemaphoreId_t semaphore_id)93 uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id)
94 {
95 	struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id;
96 
97 	if (semaphore_id == NULL) {
98 		return 0;
99 	}
100 
101 	return k_sem_count_get(&semaphore->z_semaphore);
102 }
103 
104 /**
105  * @brief Release a semaphore that was obtained by osSemaphoreWait.
106  */
osSemaphoreRelease(osSemaphoreId_t semaphore_id)107 osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id)
108 {
109 	struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id;
110 
111 	if (semaphore_id == NULL) {
112 		return osErrorParameter;
113 	}
114 
115 	/* All tokens have already been released */
116 	if (k_sem_count_get(&semaphore->z_semaphore) == semaphore->z_semaphore.limit) {
117 		return osErrorResource;
118 	}
119 
120 	k_sem_give(&semaphore->z_semaphore);
121 
122 	return osOK;
123 }
124 
125 /**
126  * @brief Delete a semaphore that was created by osSemaphoreCreate.
127  */
osSemaphoreDelete(osSemaphoreId_t semaphore_id)128 osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id)
129 {
130 	struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id;
131 
132 	if (semaphore_id == NULL) {
133 		return osErrorParameter;
134 	}
135 
136 	if (k_is_in_isr()) {
137 		return osErrorISR;
138 	}
139 
140 	/* The status code "osErrorResource" (the semaphore specified by
141 	 * parameter semaphore_id is in an invalid semaphore state) is not
142 	 * supported in Zephyr.
143 	 */
144 	if (semaphore->is_cb_dynamic_allocation) {
145 		k_mem_slab_free(&cmsis_rtos_semaphore_cb_slab, (void *)semaphore);
146 	}
147 
148 	return osOK;
149 }
150 
osSemaphoreGetName(osSemaphoreId_t semaphore_id)151 const char *osSemaphoreGetName(osSemaphoreId_t semaphore_id)
152 {
153 	struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id;
154 
155 	if (!k_is_in_isr() && (semaphore_id != NULL)) {
156 		return semaphore->name;
157 	} else {
158 		return NULL;
159 	}
160 }
161