device.c
1 /** 2 * @file 3 * Real-Time Driver Model for RTAI, device management 4 * 5 * @note Copyright (C) 2005 Jan Kiszka <jan.kiszka@web.de> 6 * @note Copyright (C) 2005 Joerg Langenberg <joerg.langenberg@gmx.net> 7 * 8 * with adaptions for RTAI by Paolo Mantegazza <mantegazza@aero.polimi.it> 9 * 10 * RTAI is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * RTAI is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with RTAI; if not, write to the Free Software Foundation, 22 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 23 */ 24 25 /*! 26 * @addtogroup driverapi 27 * @{ 28 */ 29 30 #include <linux/module.h> 31 #include <linux/delay.h> 32 33 #include "rtdm/internal.h" 34 35 #define SET_DEFAULT_OP(device, operation) \ 36 (device).operation##_rt = (void *)rtdm_no_support; \ 37 (device).operation##_nrt = (void *)rtdm_no_support 38 39 #define SET_DEFAULT_OP_IF_NULL(device, operation) \ 40 if (!(device).operation##_rt) \ 41 (device).operation##_rt = (void *)rtdm_no_support; \ 42 if (!(device).operation##_nrt) \ 43 (device).operation##_nrt = (void *)rtdm_no_support 44 45 #define ANY_HANDLER(device, operation) \ 46 ((device).operation##_rt || (device).operation##_nrt) 47 48 unsigned int devname_hashtab_size = DEF_DEVNAME_HASHTAB_SIZE; 49 unsigned int protocol_hashtab_size = DEF_PROTO_HASHTAB_SIZE; 50 module_param(devname_hashtab_size, uint, 0400); 51 module_param(protocol_hashtab_size, uint, 0400); 52 MODULE_PARM_DESC(devname_hashtab_size, 53 "Size of hash table for named devices (must be power of 2)"); 54 MODULE_PARM_DESC(protocol_hashtab_size, 55 "Size of hash table for protocol devices " 56 "(must be power of 2)"); 57 58 struct list_head *rtdm_named_devices; /* hash table */ 59 struct list_head *rtdm_protocol_devices; /* hash table */ 60 static int name_hashkey_mask; 61 static int proto_hashkey_mask; 62 63 int rtdm_apc; 64 EXPORT_SYMBOL(rtdm_apc); 65 66 struct semaphore nrt_dev_lock; 67 DEFINE_XNLOCK(rt_dev_lock); 68 69 #ifndef MODULE 70 int rtdm_initialised = 0; 71 #endif /* !MODULE */ 72 73 int rtdm_no_support(void) 74 { 75 return -ENOSYS; 76 } 77 78 int rtdm_select_bind_no_support(struct rtdm_dev_context *context, 79 struct xnselector *selector, 80 unsigned type, 81 unsigned index) 82 { 83 return -EBADF; 84 } 85 86 static inline int get_name_hash(const char *str, int limit, int hashkey_mask) 87 { 88 int hash = 0; 89 90 while (*str != 0) { 91 hash += *str++; 92 if (--limit == 0) 93 break; 94 } 95 return hash & hashkey_mask; 96 } 97 98 static inline int get_proto_hash(int protocol_family, int socket_type) 99 { 100 return protocol_family & proto_hashkey_mask; 101 } 102 103 static inline void rtdm_reference_device(struct rtdm_device *device) 104 { 105 atomic_inc(&device->reserved.refcount); 106 } 107 108 struct rtdm_device *get_named_device(const char *name) 109 { 110 struct list_head *entry; 111 struct rtdm_device *device; 112 int hashkey; 113 spl_t s; 114 115 hashkey = get_name_hash(name, RTDM_MAX_DEVNAME_LEN, name_hashkey_mask); 116 117 xnlock_get_irqsave(&rt_dev_lock, s); 118 119 list_for_each(entry, &rtdm_named_devices[hashkey]) { 120 device = list_entry(entry, struct rtdm_device, reserved.entry); 121 122 if (strcmp(name, device->device_name) == 0) { 123 rtdm_reference_device(device); 124 125 xnlock_put_irqrestore(&rt_dev_lock, s); 126 127 return device; 128 } 129 } 130 131 xnlock_put_irqrestore(&rt_dev_lock, s); 132 133 return NULL; 134 } 135 136 struct rtdm_device *get_protocol_device(int protocol_family, int socket_type) 137 { 138 struct list_head *entry; 139 struct rtdm_device *device; 140 int hashkey; 141 spl_t s; 142 143 hashkey = get_proto_hash(protocol_family, socket_type); 144 145 xnlock_get_irqsave(&rt_dev_lock, s); 146 147 list_for_each(entry, &rtdm_protocol_devices[hashkey]) { 148 device = list_entry(entry, struct rtdm_device, reserved.entry); 149 150 if ((device->protocol_family == protocol_family) && 151 (device->socket_type == socket_type)) { 152 rtdm_reference_device(device); 153 154 xnlock_put_irqrestore(&rt_dev_lock, s); 155 156 return device; 157 } 158 } 159 160 xnlock_put_irqrestore(&rt_dev_lock, s); 161 162 return NULL; 163 } 164 165 /*! 166 * @ingroup driverapi 167 * @defgroup devregister Device Registration Services 168 * @{ 169 */ 170 171 /** 172 * @brief Register a RTDM device 173 * 174 * @param[in] device Pointer to structure describing the new device. 175 * 176 * @return 0 is returned upon success. Otherwise: 177 * 178 * - -EINVAL is returned if the device structure contains invalid entries. 179 * Check kernel log in this case. 180 * 181 * - -ENOMEM is returned if the context for an exclusive device cannot be 182 * allocated. 183 * 184 * - -EEXIST is returned if the specified device name of protocol ID is 185 * already in use. 186 * 187 * - -EAGAIN is returned if some /proc entry cannot be created. 188 * 189 * Environments: 190 * 191 * This service can be called from: 192 * 193 * - Kernel module initialization/cleanup code 194 * 195 * Rescheduling: never. 196 */ 197 int rtdm_dev_register(struct rtdm_device *device) 198 { 199 int hashkey; 200 spl_t s; 201 struct list_head *entry; 202 struct rtdm_device *existing_dev; 203 int ret; 204 205 /* Catch unsuccessful initialisation */ 206 if (!rtdm_initialised) 207 return -ENOSYS; 208 209 /* Sanity check: structure version */ 210 RTAI_ASSERT(RTDM, device->struct_version == RTDM_DEVICE_STRUCT_VER, 211 xnlogerr("RTDM: invalid rtdm_device version (%d, " 212 "required %d)\n", device->struct_version, 213 RTDM_DEVICE_STRUCT_VER); 214 return -EINVAL;); 215 216 /* Sanity check: proc_name specified? */ 217 RTAI_ASSERT(RTDM, device->proc_name, 218 xnlogerr("RTDM: no /proc entry name specified\n"); 219 return -EINVAL;); 220 221 switch (device->device_flags & RTDM_DEVICE_TYPE_MASK) { 222 case RTDM_NAMED_DEVICE: 223 /* Sanity check: any open handler? */ 224 RTAI_ASSERT(RTDM, ANY_HANDLER(*device, open), 225 xnlogerr("RTDM: missing open handler\n"); 226 return -EINVAL;); 227 if (device->open_rt && 228 device->socket_rt != (void *)rtdm_no_support) 229 xnlogerr("RTDM: RT open handler is deprecated, " 230 "driver requires update.\n"); 231 SET_DEFAULT_OP_IF_NULL(*device, open); 232 SET_DEFAULT_OP(*device, socket); 233 break; 234 235 case RTDM_PROTOCOL_DEVICE: 236 /* Sanity check: any socket handler? */ 237 RTAI_ASSERT(RTDM, ANY_HANDLER(*device, socket), 238 xnlogerr("RTDM: missing socket handler\n"); 239 return -EINVAL;); 240 if (device->socket_rt && 241 device->socket_rt != (void *)rtdm_no_support) 242 xnlogerr("RTDM: RT socket creation handler is " 243 "deprecated, driver requires update.\n"); 244 SET_DEFAULT_OP_IF_NULL(*device, socket); 245 SET_DEFAULT_OP(*device, open); 246 break; 247 248 default: 249 return -EINVAL; 250 } 251 252 /* Sanity check: non-RT close handler? 253 * (Always required for forced cleanup) */ 254 if (!device->ops.close_nrt) { 255 xnlogerr("RTDM: missing non-RT close handler\n"); 256 return -EINVAL; 257 } 258 if (device->ops.close_rt && 259 device->ops.close_rt != (void *)rtdm_no_support) 260 xnlogerr("RTDM: RT close handler is deprecated, driver " 261 "requires update.\n"); 262 else 263 device->ops.close_rt = (void *)rtdm_no_support; 264 265 SET_DEFAULT_OP_IF_NULL(device->ops, ioctl); 266 SET_DEFAULT_OP_IF_NULL(device->ops, read); 267 SET_DEFAULT_OP_IF_NULL(device->ops, write); 268 SET_DEFAULT_OP_IF_NULL(device->ops, recvmsg); 269 SET_DEFAULT_OP_IF_NULL(device->ops, sendmsg); 270 if (!device->ops.select_bind) 271 device->ops.select_bind = rtdm_select_bind_no_support; 272 273 atomic_set(&device->reserved.refcount, 0); 274 device->reserved.exclusive_context = NULL; 275 276 if (device->device_flags & RTDM_EXCLUSIVE) { 277 device->reserved.exclusive_context = 278 kmalloc(sizeof(struct rtdm_dev_context) + 279 device->context_size, GFP_KERNEL); 280 if (!device->reserved.exclusive_context) { 281 xnlogerr("RTDM: no memory for exclusive context " 282 "(context size: %ld)\n", 283 (long)device->context_size); 284 return -ENOMEM; 285 } 286 /* mark exclusive context as unused */ 287 device->reserved.exclusive_context->device = NULL; 288 } 289 290 down(&nrt_dev_lock); 291 292 if ((device->device_flags & RTDM_DEVICE_TYPE_MASK) == RTDM_NAMED_DEVICE) { 293 trace_mark(xn_rtdm, nameddev_register, "device %p name %s " 294 "flags %d class %d sub_class %d profile_version %d " 295 "driver_version %d", device, device->device_name, 296 device->device_flags, device->device_class, 297 device->device_sub_class, device->profile_version, 298 device->driver_version); 299 300 hashkey = 301 get_name_hash(device->device_name, RTDM_MAX_DEVNAME_LEN, 302 name_hashkey_mask); 303 304 list_for_each(entry, &rtdm_named_devices[hashkey]) { 305 existing_dev = 306 list_entry(entry, struct rtdm_device, 307 reserved.entry); 308 if (strcmp(device->device_name, 309 existing_dev->device_name) == 0) { 310 ret = -EEXIST; 311 goto err; 312 } 313 } 314 315 ret = rtdm_proc_register_device(device); 316 if (ret) 317 goto err; 318 319 xnlock_get_irqsave(&rt_dev_lock, s); 320 list_add_tail(&device->reserved.entry, 321 &rtdm_named_devices[hashkey]); 322 xnlock_put_irqrestore(&rt_dev_lock, s); 323 324 up(&nrt_dev_lock); 325 } else { 326 trace_mark(xn_rtdm, protocol_register, "device %p " 327 "protocol_family %d socket_type %d flags %d " 328 "class %d sub_class %d profile_version %d " 329 "driver_version %d", device, 330 device->protocol_family, device->socket_type, 331 device->device_flags, device->device_class, 332 device->device_sub_class, device->profile_version, 333 device->driver_version); 334 335 hashkey = get_proto_hash(device->protocol_family, 336 device->socket_type); 337 338 list_for_each(entry, &rtdm_protocol_devices[hashkey]) { 339 existing_dev = 340 list_entry(entry, struct rtdm_device, 341 reserved.entry); 342 if ((device->protocol_family == 343 existing_dev->protocol_family) 344 && (device->socket_type == 345 existing_dev->socket_type)) { 346 xnlogerr("RTDM: protocol %u:%u already " 347 "exists\n", device->protocol_family, 348 device->socket_type); 349 ret = -EEXIST; 350 goto err; 351 } 352 } 353 354 ret = rtdm_proc_register_device(device); 355 if (ret) 356 goto err; 357 358 xnlock_get_irqsave(&rt_dev_lock, s); 359 list_add_tail(&device->reserved.entry, 360 &rtdm_protocol_devices[hashkey]); 361 xnlock_put_irqrestore(&rt_dev_lock, s); 362 363 up(&nrt_dev_lock); 364 } 365 return 0; 366 367 err: 368 up(&nrt_dev_lock); 369 if (device->reserved.exclusive_context) 370 kfree(device->reserved.exclusive_context); 371 return ret; 372 } 373 374 EXPORT_SYMBOL(rtdm_dev_register); 375 376 /** 377 * @brief Unregisters a RTDM device 378 * 379 * @param[in] device Pointer to structure describing the device to be 380 * unregistered. 381 * @param[in] poll_delay Polling delay in milliseconds to check repeatedly for 382 * open instances of @a device, or 0 for non-blocking mode. 383 * 384 * @return 0 is returned upon success. Otherwise: 385 * 386 * - -ENODEV is returned if the device was not registered. 387 * 388 * - -EAGAIN is returned if the device is busy with open instances and 0 has 389 * been passed for @a poll_delay. 390 * 391 * Environments: 392 * 393 * This service can be called from: 394 * 395 * - Kernel module initialization/cleanup code 396 * 397 * Rescheduling: never. 398 */ 399 int rtdm_dev_unregister(struct rtdm_device *device, unsigned int poll_delay) 400 { 401 spl_t s; 402 struct rtdm_device *reg_dev; 403 unsigned long warned = 0; 404 405 if (!rtdm_initialised) 406 return -ENOSYS; 407 408 if ((device->device_flags & RTDM_DEVICE_TYPE_MASK) == RTDM_NAMED_DEVICE) 409 reg_dev = get_named_device(device->device_name); 410 else 411 reg_dev = get_protocol_device(device->protocol_family, 412 device->socket_type); 413 if (!reg_dev) 414 return -ENODEV; 415 416 trace_mark(xn_rtdm, dev_unregister, "device %p poll_delay %u", 417 device, poll_delay); 418 419 down(&nrt_dev_lock); 420 xnlock_get_irqsave(&rt_dev_lock, s); 421 422 while (atomic_read(®_dev->reserved.refcount) > 1) { 423 xnlock_put_irqrestore(&rt_dev_lock, s); 424 up(&nrt_dev_lock); 425 426 if (!poll_delay) { 427 rtdm_dereference_device(reg_dev); 428 trace_mark(xn_rtdm, dev_busy, "device %p", device); 429 return -EAGAIN; 430 } 431 432 if (!__test_and_set_bit(0, &warned)) 433 xnlogwarn("RTDM: device %s still in use - waiting for " 434 "release...\n", reg_dev->device_name); 435 msleep(poll_delay); 436 trace_mark(xn_rtdm, dev_poll, "device %p", device); 437 438 down(&nrt_dev_lock); 439 xnlock_get_irqsave(&rt_dev_lock, s); 440 } 441 442 list_del(®_dev->reserved.entry); 443 444 xnlock_put_irqrestore(&rt_dev_lock, s); 445 446 rtdm_proc_unregister_device(device); 447 448 up(&nrt_dev_lock); 449 450 if (reg_dev->reserved.exclusive_context) 451 kfree(device->reserved.exclusive_context); 452 453 return 0; 454 } 455 456 EXPORT_SYMBOL(rtdm_dev_unregister); 457 /** @} */ 458 459 int __init rtdm_dev_init(void) 460 { 461 int err, i; 462 463 sema_init(&nrt_dev_lock, 1); 464 465 rtdm_apc = rthal_apc_alloc("deferred RTDM close", rtdm_apc_handler, 466 NULL); 467 if (rtdm_apc < 0) 468 return rtdm_apc; 469 470 name_hashkey_mask = devname_hashtab_size - 1; 471 proto_hashkey_mask = protocol_hashtab_size - 1; 472 if (((devname_hashtab_size & name_hashkey_mask) != 0) || 473 ((protocol_hashtab_size & proto_hashkey_mask) != 0)) { 474 err = -EINVAL; 475 goto err_out1; 476 } 477 478 rtdm_named_devices = (struct list_head *) 479 kmalloc(devname_hashtab_size * sizeof(struct list_head), 480 GFP_KERNEL); 481 if (!rtdm_named_devices) { 482 err = -ENOMEM; 483 goto err_out1; 484 } 485 486 for (i = 0; i < devname_hashtab_size; i++) 487 INIT_LIST_HEAD(&rtdm_named_devices[i]); 488 489 rtdm_protocol_devices = (struct list_head *) 490 kmalloc(protocol_hashtab_size * sizeof(struct list_head), 491 GFP_KERNEL); 492 if (!rtdm_protocol_devices) { 493 err = -ENOMEM; 494 goto err_out2; 495 } 496 497 for (i = 0; i < protocol_hashtab_size; i++) 498 INIT_LIST_HEAD(&rtdm_protocol_devices[i]); 499 500 return 0; 501 502 err_out2: 503 kfree(rtdm_named_devices); 504 505 err_out1: 506 rthal_apc_free(rtdm_apc); 507 508 return err; 509 } 510 511 void rtdm_dev_cleanup(void) 512 { 513 /* 514 * Note: no need to flush the cleanup_queue as no device is allowed 515 * to deregister as long as there are references. 516 */ 517 rthal_apc_free(rtdm_apc); 518 kfree(rtdm_named_devices); 519 kfree(rtdm_protocol_devices); 520 } 521 522 /*@}*/