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