1 /* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 * 2007-01-21 Bernard the first version 9 * 2010-05-04 Bernard add rt_device_init implementation 10 * 2012-10-20 Bernard add device check in register function, 11 * provided by Rob <[email protected]> 12 * 2012-12-25 Bernard return RT_EOK if the device interface not exist. 13 * 2013-07-09 Grissiom add ref_count support 14 * 2016-04-02 Bernard fix the open_flag initialization issue. 15 */ 16 17 #include <rtthread.h> 18 #if defined(RT_USING_POSIX) 19 #include <rtdevice.h> /* for wqueue_init */ 20 #endif 21 22 #ifdef RT_USING_DEVICE 23 24 #ifdef RT_USING_DEVICE_OPS 25 #define device_init (dev->ops->init) 26 #define device_open (dev->ops->open) 27 #define device_close (dev->ops->close) 28 #define device_read (dev->ops->read) 29 #define device_write (dev->ops->write) 30 #define device_control (dev->ops->control) 31 #else 32 #define device_init (dev->init) 33 #define device_open (dev->open) 34 #define device_close (dev->close) 35 #define device_read (dev->read) 36 #define device_write (dev->write) 37 #define device_control (dev->control) 38 #endif 39 40 /** 41 * This function registers a device driver with specified name. 42 * 43 * @param dev the pointer of device driver structure 44 * @param name the device driver's name 45 * @param flags the capabilities flag of device 46 * 47 * @return the error code, RT_EOK on initialization successfully. 48 */ 49 rt_err_t rt_device_register(rt_device_t dev, 50 const char *name, 51 rt_uint16_t flags) 52 { 53 if (dev == RT_NULL) 54 return -RT_ERROR; 55 56 if (rt_device_find(name) != RT_NULL) 57 return -RT_ERROR; 58 59 rt_object_init(&(dev->parent), RT_Object_Class_Device, name); 60 dev->flag = flags; 61 dev->ref_count = 0; 62 dev->open_flag = 0; 63 64 #if defined(RT_USING_POSIX) 65 dev->fops = RT_NULL; 66 rt_wqueue_init(&(dev->wait_queue)); 67 #endif 68 69 return RT_EOK; 70 } 71 RTM_EXPORT(rt_device_register); 72 73 /** 74 * This function removes a previously registered device driver 75 * 76 * @param dev the pointer of device driver structure 77 * 78 * @return the error code, RT_EOK on successfully. 79 */ 80 rt_err_t rt_device_unregister(rt_device_t dev) 81 { 82 RT_ASSERT(dev != RT_NULL); 83 RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); 84 RT_ASSERT(rt_object_is_systemobject(&dev->parent)); 85 86 rt_object_detach(&(dev->parent)); 87 88 return RT_EOK; 89 } 90 RTM_EXPORT(rt_device_unregister); 91 92 /** 93 * This function initializes all registered device driver 94 * 95 * @return the error code, RT_EOK on successfully. 96 * 97 * @deprecated since 1.2.x, this function is not needed because the initialization 98 * of a device is performed when applicaiton opens it. 99 */ 100 rt_err_t rt_device_init_all(void) 101 { 102 return RT_EOK; 103 } 104 105 /** 106 * This function finds a device driver by specified name. 107 * 108 * @param name the device driver's name 109 * 110 * @return the registered device driver on successful, or RT_NULL on failure. 111 */ 112 rt_device_t rt_device_find(const char *name) 113 { 114 struct rt_object *object; 115 struct rt_list_node *node; 116 struct rt_object_information *information; 117 118 /* enter critical */ 119 if (rt_thread_self() != RT_NULL) 120 rt_enter_critical(); 121 122 /* try to find device object */ 123 information = rt_object_get_information(RT_Object_Class_Device); 124 RT_ASSERT(information != RT_NULL); 125 for (node = information->object_list.next; 126 node != &(information->object_list); 127 node = node->next) 128 { 129 object = rt_list_entry(node, struct rt_object, list); 130 if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0) 131 { 132 /* leave critical */ 133 if (rt_thread_self() != RT_NULL) 134 rt_exit_critical(); 135 136 return (rt_device_t)object; 137 } 138 } 139 140 /* leave critical */ 141 if (rt_thread_self() != RT_NULL) 142 rt_exit_critical(); 143 144 /* not found */ 145 return RT_NULL; 146 } 147 RTM_EXPORT(rt_device_find); 148 149 #ifdef RT_USING_HEAP 150 /** 151 * This function creates a device object with user data size. 152 * 153 * @param type, the kind type of this device object. 154 * @param attach_size, the size of user data. 155 * 156 * @return the allocated device object, or RT_NULL when failed. 157 */ 158 rt_device_t rt_device_create(int type, int attach_size) 159 { 160 int size; 161 rt_device_t device; 162 163 size = RT_ALIGN(sizeof(struct rt_device), RT_ALIGN_SIZE); 164 attach_size = RT_ALIGN(attach_size, RT_ALIGN_SIZE); 165 /* use the totoal size */ 166 size += attach_size; 167 168 device = (rt_device_t)rt_malloc(size); 169 if (device) 170 { 171 rt_memset(device, 0x0, sizeof(struct rt_device)); 172 device->type = (enum rt_device_class_type)type; 173 } 174 175 return device; 176 } 177 RTM_EXPORT(rt_device_create); 178 179 /** 180 * This function destroy the specific device object. 181 * 182 * @param dev, the specific device object. 183 */ 184 void rt_device_destroy(rt_device_t dev) 185 { 186 RT_ASSERT(dev != RT_NULL); 187 RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); 188 RT_ASSERT(rt_object_is_systemobject(&dev->parent) == RT_FALSE); 189 190 rt_object_detach(&(dev->parent)); 191 192 /* release this device object */ 193 rt_free(dev); 194 } 195 RTM_EXPORT(rt_device_destroy); 196 #endif 197 198 /** 199 * This function will initialize the specified device 200 * 201 * @param dev the pointer of device driver structure 202 * 203 * @return the result 204 */ 205 rt_err_t rt_device_init(rt_device_t dev) 206 { 207 rt_err_t result = RT_EOK; 208 209 RT_ASSERT(dev != RT_NULL); 210 211 /* get device init handler */ 212 if (device_init != RT_NULL) 213 { 214 if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED)) 215 { 216 result = device_init(dev); 217 if (result != RT_EOK) 218 { 219 rt_kprintf("To initialize device:%s failed. The error code is %d\n", 220 dev->parent.name, result); 221 } 222 else 223 { 224 dev->flag |= RT_DEVICE_FLAG_ACTIVATED; 225 } 226 } 227 } 228 229 return result; 230 } 231 232 /** 233 * This function will open a device 234 * 235 * @param dev the pointer of device driver structure 236 * @param oflag the flags for device open 237 * 238 * @return the result 239 */ 240 rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag) 241 { 242 rt_err_t result = RT_EOK; 243 244 RT_ASSERT(dev != RT_NULL); 245 RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); 246 247 /* if device is not initialized, initialize it. */ 248 if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED)) 249 { 250 if (device_init != RT_NULL) 251 { 252 result = device_init(dev); 253 if (result != RT_EOK) 254 { 255 rt_kprintf("To initialize device:%s failed. The error code is %d\n", 256 dev->parent.name, result); 257 258 return result; 259 } 260 } 261 262 dev->flag |= RT_DEVICE_FLAG_ACTIVATED; 263 } 264 265 /* device is a stand alone device and opened */ 266 if ((dev->flag & RT_DEVICE_FLAG_STANDALONE) && 267 (dev->open_flag & RT_DEVICE_OFLAG_OPEN)) 268 { 269 return -RT_EBUSY; 270 } 271 272 /* call device open interface */ 273 if (device_open != RT_NULL) 274 { 275 result = device_open(dev, oflag); 276 } 277 else 278 { 279 /* set open flag */ 280 dev->open_flag = (oflag & RT_DEVICE_OFLAG_MASK); 281 } 282 283 /* set open flag */ 284 if (result == RT_EOK || result == -RT_ENOSYS) 285 { 286 dev->open_flag |= RT_DEVICE_OFLAG_OPEN; 287 288 dev->ref_count++; 289 /* don't let bad things happen silently. If you are bitten by this assert, 290 * please set the ref_count to a bigger type. */ 291 RT_ASSERT(dev->ref_count != 0); 292 } 293 294 return result; 295 } 296 RTM_EXPORT(rt_device_open); 297 298 /** 299 * This function will close a device 300 * 301 * @param dev the pointer of device driver structure 302 * 303 * @return the result 304 */ 305 rt_err_t rt_device_close(rt_device_t dev) 306 { 307 rt_err_t result = RT_EOK; 308 309 RT_ASSERT(dev != RT_NULL); 310 RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); 311 312 if (dev->ref_count == 0) 313 return -RT_ERROR; 314 315 dev->ref_count--; 316 317 if (dev->ref_count != 0) 318 return RT_EOK; 319 320 /* call device close interface */ 321 if (device_close != RT_NULL) 322 { 323 result = device_close(dev); 324 } 325 326 /* set open flag */ 327 if (result == RT_EOK || result == -RT_ENOSYS) 328 dev->open_flag = RT_DEVICE_OFLAG_CLOSE; 329 330 return result; 331 } 332 RTM_EXPORT(rt_device_close); 333 334 /** 335 * This function will read some data from a device. 336 * 337 * @param dev the pointer of device driver structure 338 * @param pos the position of reading 339 * @param buffer the data buffer to save read data 340 * @param size the size of buffer 341 * 342 * @return the actually read size on successful, otherwise negative returned. 343 * 344 * @note since 0.4.0, the unit of size/pos is a block for block device. 345 */ 346 rt_size_t rt_device_read(rt_device_t dev, 347 rt_off_t pos, 348 void *buffer, 349 rt_size_t size) 350 { 351 RT_ASSERT(dev != RT_NULL); 352 RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); 353 354 if (dev->ref_count == 0) 355 { 356 rt_set_errno(-RT_ERROR); 357 return 0; 358 } 359 360 /* call device read interface */ 361 if (device_read != RT_NULL) 362 { 363 return device_read(dev, pos, buffer, size); 364 } 365 366 /* set error code */ 367 rt_set_errno(-RT_ENOSYS); 368 369 return 0; 370 } 371 RTM_EXPORT(rt_device_read); 372 373 /** 374 * This function will write some data to a device. 375 * 376 * @param dev the pointer of device driver structure 377 * @param pos the position of written 378 * @param buffer the data buffer to be written to device 379 * @param size the size of buffer 380 * 381 * @return the actually written size on successful, otherwise negative returned. 382 * 383 * @note since 0.4.0, the unit of size/pos is a block for block device. 384 */ 385 rt_size_t rt_device_write(rt_device_t dev, 386 rt_off_t pos, 387 const void *buffer, 388 rt_size_t size) 389 { 390 RT_ASSERT(dev != RT_NULL); 391 RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); 392 393 if (dev->ref_count == 0) 394 { 395 rt_set_errno(-RT_ERROR); 396 return 0; 397 } 398 399 /* call device write interface */ 400 if (device_write != RT_NULL) 401 { 402 return device_write(dev, pos, buffer, size); 403 } 404 405 /* set error code */ 406 rt_set_errno(-RT_ENOSYS); 407 408 return 0; 409 } 410 RTM_EXPORT(rt_device_write); 411 412 /** 413 * This function will perform a variety of control functions on devices. 414 * 415 * @param dev the pointer of device driver structure 416 * @param cmd the command sent to device 417 * @param arg the argument of command 418 * 419 * @return the result 420 */ 421 rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg) 422 { 423 RT_ASSERT(dev != RT_NULL); 424 RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); 425 426 /* call device write interface */ 427 if (device_control != RT_NULL) 428 { 429 return device_control(dev, cmd, arg); 430 } 431 432 return -RT_ENOSYS; 433 } 434 RTM_EXPORT(rt_device_control); 435 436 /** 437 * This function will set the reception indication callback function. This callback function 438 * is invoked when this device receives data. 439 * 440 * @param dev the pointer of device driver structure 441 * @param rx_ind the indication callback function 442 * 443 * @return RT_EOK 444 */ 445 rt_err_t 446 rt_device_set_rx_indicate(rt_device_t dev, 447 rt_err_t (*rx_ind)(rt_device_t dev, rt_size_t size)) 448 { 449 RT_ASSERT(dev != RT_NULL); 450 RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); 451 452 dev->rx_indicate = rx_ind; 453 454 return RT_EOK; 455 } 456 RTM_EXPORT(rt_device_set_rx_indicate); 457 458 /** 459 * This function will set the indication callback function when device has 460 * written data to physical hardware. 461 * 462 * @param dev the pointer of device driver structure 463 * @param tx_done the indication callback function 464 * 465 * @return RT_EOK 466 */ 467 rt_err_t 468 rt_device_set_tx_complete(rt_device_t dev, 469 rt_err_t (*tx_done)(rt_device_t dev, void *buffer)) 470 { 471 RT_ASSERT(dev != RT_NULL); 472 RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); 473 474 dev->tx_complete = tx_done; 475 476 return RT_EOK; 477 } 478 RTM_EXPORT(rt_device_set_tx_complete); 479 480 #endif 481