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 	semaphore->name = (attr->name == NULL) ? init_sema_attrs.name : attr->name;
51 
52 	return (osSemaphoreId_t)semaphore;
53 }
54 
55 /**
56  * @brief Wait until a semaphore becomes available.
57  */
osSemaphoreAcquire(osSemaphoreId_t semaphore_id,uint32_t timeout)58 osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout)
59 {
60 	struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id;
61 	int status;
62 
63 	if (semaphore_id == NULL) {
64 		return osErrorParameter;
65 	}
66 
67 	/* Can be called from ISRs only if timeout is set to 0 */
68 	if (timeout > 0 && k_is_in_isr()) {
69 		return osErrorParameter;
70 	}
71 
72 	if (timeout == osWaitForever) {
73 		status = k_sem_take(&semaphore->z_semaphore, K_FOREVER);
74 	} else if (timeout == 0U) {
75 		status = k_sem_take(&semaphore->z_semaphore, K_NO_WAIT);
76 	} else {
77 		status = k_sem_take(&semaphore->z_semaphore, K_TICKS(timeout));
78 	}
79 
80 	if (status == -EBUSY) {
81 		return osErrorResource;
82 	} else if (status == -EAGAIN) {
83 		return osErrorTimeout;
84 	} else {
85 		return osOK;
86 	}
87 }
88 
osSemaphoreGetCount(osSemaphoreId_t semaphore_id)89 uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id)
90 {
91 	struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id;
92 
93 	if (semaphore_id == NULL) {
94 		return 0;
95 	}
96 
97 	return k_sem_count_get(&semaphore->z_semaphore);
98 }
99 
100 /**
101  * @brief Release a semaphore that was obtained by osSemaphoreWait.
102  */
osSemaphoreRelease(osSemaphoreId_t semaphore_id)103 osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id)
104 {
105 	struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id;
106 
107 	if (semaphore_id == NULL) {
108 		return osErrorParameter;
109 	}
110 
111 	/* All tokens have already been released */
112 	if (k_sem_count_get(&semaphore->z_semaphore) == semaphore->z_semaphore.limit) {
113 		return osErrorResource;
114 	}
115 
116 	k_sem_give(&semaphore->z_semaphore);
117 
118 	return osOK;
119 }
120 
121 /**
122  * @brief Delete a semaphore that was created by osSemaphoreCreate.
123  */
osSemaphoreDelete(osSemaphoreId_t semaphore_id)124 osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id)
125 {
126 	struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id;
127 
128 	if (semaphore_id == NULL) {
129 		return osErrorParameter;
130 	}
131 
132 	if (k_is_in_isr()) {
133 		return osErrorISR;
134 	}
135 
136 	/* The status code "osErrorResource" (the semaphore specified by
137 	 * parameter semaphore_id is in an invalid semaphore state) is not
138 	 * supported in Zephyr.
139 	 */
140 	if (semaphore->is_cb_dynamic_allocation) {
141 		k_mem_slab_free(&cmsis_rtos_semaphore_cb_slab, (void *)semaphore);
142 	}
143 
144 	return osOK;
145 }
146 
147 /**
148  * @brief Get name of a semaphore.
149  * This function may be called from Interrupt Service Routines.
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 (semaphore == NULL) {
156 		return NULL;
157 	}
158 	return semaphore->name;
159 }
160