dahdi-sysfs.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. /* dahdi-sysfs.c
  2. *
  3. * Copyright (C) 2011-2012, Xorcom
  4. * Copyright (C) 2011-2012, Digium, Inc.
  5. *
  6. * All rights reserved.
  7. *
  8. */
  9. /*
  10. * See http://www.asterisk.org for more information about
  11. * the Asterisk project. Please do not directly contact
  12. * any of the maintainers of this project for assistance;
  13. * the project provides a web site, mailing lists and IRC
  14. * channels for your use.
  15. *
  16. * This program is free software, distributed under the terms of
  17. * the GNU General Public License Version 2 as published by the
  18. * Free Software Foundation. See the LICENSE file included with
  19. * this program for more details.
  20. */
  21. #include <linux/kernel.h>
  22. #include <linux/version.h>
  23. #define DAHDI_PRINK_MACROS_USE_debug
  24. #include <dahdi/kernel.h>
  25. #include <linux/device.h>
  26. #include <linux/slab.h>
  27. #include <linux/ctype.h>
  28. #include "dahdi.h"
  29. #include "dahdi-sysfs.h"
  30. static char *initdir;
  31. module_param(initdir, charp, 0444);
  32. MODULE_PARM_DESC(initdir,
  33. "deprecated, should use <tools_rootdir>/usr/share/dahdi");
  34. static char *tools_rootdir;
  35. module_param(tools_rootdir, charp, 0444);
  36. MODULE_PARM_DESC(tools_rootdir,
  37. "root directory of all tools paths (default /)");
  38. static int span_match(struct device *dev, struct device_driver *driver)
  39. {
  40. return 1;
  41. }
  42. static inline struct dahdi_span *dev_to_span(struct device *dev)
  43. {
  44. return dev_get_drvdata(dev);
  45. }
  46. #define SPAN_VAR_BLOCK \
  47. do { \
  48. DAHDI_ADD_UEVENT_VAR("DAHDI_TOOLS_ROOTDIR=%s", tools_rootdir); \
  49. DAHDI_ADD_UEVENT_VAR("DAHDI_INIT_DIR=%s/%s", tools_rootdir, \
  50. initdir); \
  51. DAHDI_ADD_UEVENT_VAR("SPAN_NUM=%d", span->spanno); \
  52. DAHDI_ADD_UEVENT_VAR("SPAN_NAME=%s", span->name); \
  53. } while (0)
  54. #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
  55. #define DAHDI_ADD_UEVENT_VAR(fmt, val...) \
  56. do { \
  57. int err = add_uevent_var(envp, num_envp, &i, \
  58. buffer, buffer_size, &len, \
  59. fmt, val); \
  60. if (err) \
  61. return err; \
  62. } while (0)
  63. static int span_uevent(struct device *dev, char **envp, int num_envp,
  64. char *buffer, int buffer_size)
  65. {
  66. struct dahdi_span *span;
  67. int i = 0;
  68. int len = 0;
  69. if (!dev)
  70. return -ENODEV;
  71. span = dev_to_span(dev);
  72. if (!span)
  73. return -ENODEV;
  74. dahdi_dbg(GENERAL, "SYFS dev_name=%s span=%s\n",
  75. dev_name(dev), span->name);
  76. SPAN_VAR_BLOCK;
  77. envp[i] = NULL;
  78. return 0;
  79. }
  80. #else
  81. #define DAHDI_ADD_UEVENT_VAR(fmt, val...) \
  82. do { \
  83. int err = add_uevent_var(kenv, fmt, val); \
  84. if (err) \
  85. return err; \
  86. } while (0)
  87. static int span_uevent(struct device *dev, struct kobj_uevent_env *kenv)
  88. {
  89. struct dahdi_span *span;
  90. if (!dev)
  91. return -ENODEV;
  92. span = dev_to_span(dev);
  93. if (!span)
  94. return -ENODEV;
  95. dahdi_dbg(GENERAL, "SYFS dev_name=%s span=%s\n",
  96. dev_name(dev), span->name);
  97. SPAN_VAR_BLOCK;
  98. return 0;
  99. }
  100. #endif
  101. #define span_attr(field, format_string) \
  102. static BUS_ATTR_READER(field##_show, dev, buf) \
  103. { \
  104. struct dahdi_span *span; \
  105. \
  106. span = dev_to_span(dev); \
  107. return sprintf(buf, format_string, span->field); \
  108. }
  109. span_attr(name, "%s\n");
  110. span_attr(desc, "%s\n");
  111. span_attr(alarms, "0x%x\n");
  112. span_attr(lbo, "%d\n");
  113. span_attr(syncsrc, "%d\n");
  114. static BUS_ATTR_READER(spantype_show, dev, buf)
  115. {
  116. struct dahdi_span *span;
  117. span = dev_to_span(dev);
  118. return sprintf(buf, "%s\n", dahdi_spantype2str(span->spantype));
  119. }
  120. static BUS_ATTR_READER(local_spanno_show, dev, buf)
  121. {
  122. struct dahdi_span *span;
  123. span = dev_to_span(dev);
  124. return sprintf(buf, "%d\n", local_spanno(span));
  125. }
  126. static BUS_ATTR_READER(is_digital_show, dev, buf)
  127. {
  128. struct dahdi_span *span;
  129. span = dev_to_span(dev);
  130. return sprintf(buf, "%d\n", dahdi_is_digital_span(span));
  131. }
  132. static BUS_ATTR_READER(is_sync_master_show, dev, buf)
  133. {
  134. struct dahdi_span *span;
  135. span = dev_to_span(dev);
  136. return sprintf(buf, "%d\n", dahdi_is_sync_master(span));
  137. }
  138. static BUS_ATTR_READER(basechan_show, dev, buf)
  139. {
  140. struct dahdi_span *span;
  141. span = dev_to_span(dev);
  142. if (!span->channels)
  143. return -ENODEV;
  144. return sprintf(buf, "%d\n", span->chans[0]->channo);
  145. }
  146. static BUS_ATTR_READER(channels_show, dev, buf)
  147. {
  148. struct dahdi_span *span;
  149. span = dev_to_span(dev);
  150. return sprintf(buf, "%d\n", span->channels);
  151. }
  152. static BUS_ATTR_READER(lineconfig_show, dev, buf)
  153. {
  154. struct dahdi_span *span;
  155. int len = 0;
  156. span = dev_to_span(dev);
  157. len += lineconfig_str(span->lineconfig, buf, 20);
  158. len += sprintf(buf + len, "\n");
  159. return len;
  160. }
  161. static BUS_ATTR_READER(linecompat_show, dev, buf)
  162. {
  163. struct dahdi_span *span;
  164. int bit;
  165. int len = 0;
  166. span = dev_to_span(dev);
  167. for (bit = 4; bit <= 12; bit++) {
  168. if (span->linecompat & (1 << bit)) {
  169. const char *name = dahdi_lineconfig_bit_name(bit);
  170. if (name)
  171. len += sprintf(buf + len, "%s ", name);
  172. }
  173. }
  174. /* chomp */
  175. while (len > 0 && isspace(buf[len - 1]))
  176. buf[--len] = '\0';
  177. len += sprintf(buf + len, "\n");
  178. return len;
  179. }
  180. static struct device_attribute span_dev_attrs[] = {
  181. __ATTR_RO(name),
  182. __ATTR_RO(desc),
  183. __ATTR_RO(spantype),
  184. __ATTR_RO(local_spanno),
  185. __ATTR_RO(alarms),
  186. __ATTR_RO(lbo),
  187. __ATTR_RO(syncsrc),
  188. __ATTR_RO(is_digital),
  189. __ATTR_RO(is_sync_master),
  190. __ATTR_RO(basechan),
  191. __ATTR_RO(channels),
  192. __ATTR_RO(lineconfig),
  193. __ATTR_RO(linecompat),
  194. __ATTR_NULL,
  195. };
  196. static ssize_t master_span_show(struct device_driver *driver, char *buf)
  197. {
  198. struct dahdi_span *s = get_master_span();
  199. return snprintf(buf, PAGE_SIZE, "%d\n", (s) ? s->spanno : 0);
  200. }
  201. static ssize_t master_span_store(struct device_driver *driver, const char *buf,
  202. size_t count)
  203. {
  204. int spanno;
  205. if (sscanf(buf, "%d", &spanno) != 1) {
  206. module_printk(KERN_ERR, "non-numeric input '%s'\n", buf);
  207. return -EINVAL;
  208. }
  209. set_master_span(spanno);
  210. return count;
  211. }
  212. #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
  213. static struct driver_attribute dahdi_attrs[] = {
  214. __ATTR(master_span, S_IRUGO | S_IWUSR, master_span_show,
  215. master_span_store),
  216. __ATTR_NULL,
  217. };
  218. #else
  219. static DRIVER_ATTR_RW(master_span);
  220. static struct attribute *dahdi_attrs[] = {
  221. &driver_attr_master_span.attr,
  222. NULL,
  223. };
  224. ATTRIBUTE_GROUPS(dahdi);
  225. #endif
  226. static struct bus_type spans_bus_type = {
  227. .name = "dahdi_spans",
  228. .match = span_match,
  229. .uevent = span_uevent,
  230. .dev_attrs = span_dev_attrs,
  231. #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
  232. .drv_attrs = dahdi_attrs,
  233. #else
  234. .drv_groups = dahdi_groups,
  235. #endif
  236. };
  237. static int span_probe(struct device *dev)
  238. {
  239. struct dahdi_span *span;
  240. span = dev_to_span(dev);
  241. span_dbg(DEVICES, span, "\n");
  242. return 0;
  243. }
  244. static int span_remove(struct device *dev)
  245. {
  246. struct dahdi_span *span;
  247. span = dev_to_span(dev);
  248. span_dbg(DEVICES, span, "\n");
  249. return 0;
  250. }
  251. static struct device_driver dahdi_driver = {
  252. .name = "generic_lowlevel",
  253. .bus = &spans_bus_type,
  254. .probe = span_probe,
  255. .remove = span_remove,
  256. .owner = THIS_MODULE
  257. };
  258. static void span_uevent_send(struct dahdi_span *span, enum kobject_action act)
  259. {
  260. struct kobject *kobj;
  261. kobj = &span->span_device->kobj;
  262. span_dbg(DEVICES, span, "SYFS dev_name=%s action=%d\n",
  263. dev_name(span->span_device), act);
  264. kobject_uevent(kobj, act);
  265. }
  266. static void span_release(struct device *dev)
  267. {
  268. dahdi_dbg(DEVICES, "%s: %s\n", __func__, dev_name(dev));
  269. }
  270. void span_sysfs_remove(struct dahdi_span *span)
  271. {
  272. struct device *span_device;
  273. int x;
  274. span_dbg(DEVICES, span, "\n");
  275. span_device = span->span_device;
  276. if (!span_device)
  277. return;
  278. for (x = 0; x < span->channels; x++)
  279. chan_sysfs_remove(span->chans[x]);
  280. if (!dev_get_drvdata(span_device))
  281. return;
  282. /* Grab an extra reference to the device since we'll still want it
  283. * after we've unregistered it */
  284. get_device(span_device);
  285. span_uevent_send(span, KOBJ_OFFLINE);
  286. sysfs_remove_link(&span_device->kobj, "ddev");
  287. device_unregister(span->span_device);
  288. dev_set_drvdata(span_device, NULL);
  289. span_device->parent = NULL;
  290. put_device(span_device);
  291. memset(&span->span_device, 0, sizeof(span->span_device));
  292. kfree(span->span_device);
  293. span->span_device = NULL;
  294. }
  295. int span_sysfs_create(struct dahdi_span *span)
  296. {
  297. struct device *span_device;
  298. int res = 0;
  299. int x;
  300. if (span->span_device) {
  301. WARN_ON(1);
  302. return -EEXIST;
  303. }
  304. span->span_device = kzalloc(sizeof(*span->span_device), GFP_KERNEL);
  305. if (!span->span_device)
  306. return -ENOMEM;
  307. span_device = span->span_device;
  308. span_dbg(DEVICES, span, "\n");
  309. span_device->bus = &spans_bus_type;
  310. span_device->parent = &span->parent->dev;
  311. dev_set_name(span_device, "span-%d", span->spanno);
  312. dev_set_drvdata(span_device, span);
  313. span_device->release = span_release;
  314. res = device_register(span_device);
  315. if (res) {
  316. span_err(span, "%s: device_register failed: %d\n", __func__,
  317. res);
  318. kfree(span->span_device);
  319. span->span_device = NULL;
  320. goto cleanup;
  321. }
  322. res = sysfs_create_link(&span_device->kobj, &span_device->parent->kobj,
  323. "ddev");
  324. if (res) {
  325. span_err(span, "%s: sysfs_create_link failed: %d\n", __func__,
  326. res);
  327. kfree(span->span_device);
  328. span->span_device = NULL;
  329. goto cleanup;
  330. }
  331. for (x = 0; x < span->channels; x++) {
  332. res = chan_sysfs_create(span->chans[x]);
  333. if (res)
  334. goto cleanup;
  335. }
  336. return 0;
  337. cleanup:
  338. span_sysfs_remove(span);
  339. return res;
  340. }
  341. /* Only used to flag that the device exists: */
  342. static struct {
  343. unsigned int clean_dahdi_driver:1;
  344. unsigned int clean_span_bus_type:1;
  345. unsigned int clean_device_bus:1;
  346. unsigned int clean_chardev:1;
  347. } should_cleanup;
  348. static inline struct dahdi_device *to_ddev(struct device *dev)
  349. {
  350. return container_of(dev, struct dahdi_device, dev);
  351. }
  352. #define DEVICE_VAR_BLOCK \
  353. do { \
  354. DAHDI_ADD_UEVENT_VAR("DAHDI_TOOLS_ROOTDIR=%s", tools_rootdir); \
  355. DAHDI_ADD_UEVENT_VAR("DAHDI_INIT_DIR=%s/%s", tools_rootdir, \
  356. initdir); \
  357. DAHDI_ADD_UEVENT_VAR("DAHDI_DEVICE_HWID=%s", \
  358. ddev->hardware_id); \
  359. DAHDI_ADD_UEVENT_VAR("DAHDI_DEVICE_LOCATION=%s", \
  360. ddev->location); \
  361. } while (0)
  362. #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
  363. #define DAHDI_ADD_UEVENT_VAR(fmt, val...) \
  364. do { \
  365. int err = add_uevent_var(envp, num_envp, &i, \
  366. buffer, buffer_size, &len, \
  367. fmt, val); \
  368. if (err) \
  369. return err; \
  370. } while (0)
  371. static int device_uevent(struct device *dev, char **envp, int num_envp,
  372. char *buffer, int buffer_size)
  373. {
  374. struct dahdi_device *ddev;
  375. int i = 0;
  376. int len = 0;
  377. if (!dev)
  378. return -ENODEV;
  379. ddev = to_ddev(dev);
  380. if (!ddev)
  381. return -ENODEV;
  382. dahdi_dbg(GENERAL, "SYFS dev_name=%s\n", dev_name(dev));
  383. DEVICE_VAR_BLOCK;
  384. envp[i] = NULL;
  385. return 0;
  386. }
  387. #else
  388. #define DAHDI_ADD_UEVENT_VAR(fmt, val...) \
  389. do { \
  390. int err = add_uevent_var(kenv, fmt, val); \
  391. if (err) \
  392. return err; \
  393. } while (0)
  394. static int device_uevent(struct device *dev, struct kobj_uevent_env *kenv)
  395. {
  396. struct dahdi_device *ddev;
  397. if (!dev)
  398. return -ENODEV;
  399. ddev = to_ddev(dev);
  400. if (!ddev)
  401. return -ENODEV;
  402. dahdi_dbg(GENERAL, "SYFS dev_name=%s\n", dev_name(dev));
  403. DEVICE_VAR_BLOCK;
  404. return 0;
  405. }
  406. #endif
  407. static ssize_t
  408. dahdi_device_manufacturer_show(struct device *dev,
  409. struct device_attribute *attr, char *buf)
  410. {
  411. struct dahdi_device *ddev = to_ddev(dev);
  412. return sprintf(buf, "%s\n", ddev->manufacturer);
  413. }
  414. static ssize_t
  415. dahdi_device_type_show(struct device *dev,
  416. struct device_attribute *attr, char *buf)
  417. {
  418. struct dahdi_device *ddev = to_ddev(dev);
  419. return sprintf(buf, "%s\n", ddev->devicetype);
  420. }
  421. static ssize_t
  422. dahdi_device_span_count_show(struct device *dev,
  423. struct device_attribute *attr, char *buf)
  424. {
  425. struct dahdi_device *ddev = to_ddev(dev);
  426. unsigned int count = 0;
  427. struct list_head *pos;
  428. list_for_each(pos, &ddev->spans)
  429. ++count;
  430. return sprintf(buf, "%d\n", count);
  431. }
  432. static ssize_t
  433. dahdi_device_hardware_id_show(struct device *dev,
  434. struct device_attribute *attr, char *buf)
  435. {
  436. struct dahdi_device *ddev = to_ddev(dev);
  437. return sprintf(buf, "%s\n",
  438. (ddev->hardware_id) ? ddev->hardware_id : "");
  439. }
  440. static ssize_t
  441. dahdi_device_location_show(struct device *dev,
  442. struct device_attribute *attr, char *buf)
  443. {
  444. struct dahdi_device *ddev = to_ddev(dev);
  445. return sprintf(buf, "%s\n",
  446. (ddev->location) ? ddev->location : "");
  447. }
  448. static ssize_t
  449. dahdi_device_auto_assign(struct device *dev, struct device_attribute *attr,
  450. const char *buf, size_t count)
  451. {
  452. struct dahdi_device *ddev = to_ddev(dev);
  453. dahdi_assign_device_spans(ddev);
  454. return count;
  455. }
  456. static ssize_t
  457. dahdi_device_assign_span(struct device *dev, struct device_attribute *attr,
  458. const char *buf, size_t count)
  459. {
  460. int ret;
  461. struct dahdi_span *span;
  462. unsigned int local_span_number;
  463. unsigned int desired_spanno;
  464. unsigned int desired_basechanno;
  465. struct dahdi_device *const ddev = to_ddev(dev);
  466. ret = sscanf(buf, "%u:%u:%u", &local_span_number, &desired_spanno,
  467. &desired_basechanno);
  468. if (ret != 3) {
  469. dev_notice(dev, "bad input (should be <num>:<num>:<num>)\n");
  470. return -EINVAL;
  471. }
  472. if (desired_spanno && !desired_basechanno) {
  473. dev_notice(dev, "Must set span number AND base chan number\n");
  474. return -EINVAL;
  475. }
  476. list_for_each_entry(span, &ddev->spans, device_node) {
  477. if (local_span_number == local_spanno(span)) {
  478. ret = dahdi_assign_span(span, desired_spanno,
  479. desired_basechanno, 1);
  480. return (ret) ? ret : count;
  481. }
  482. }
  483. dev_notice(dev, "no match for local span number %d\n",
  484. local_span_number);
  485. return -EINVAL;
  486. }
  487. static ssize_t
  488. dahdi_device_unassign_span(struct device *dev, struct device_attribute *attr,
  489. const char *buf, size_t count)
  490. {
  491. int ret;
  492. unsigned int local_span_number;
  493. struct dahdi_span *span;
  494. struct dahdi_device *const ddev = to_ddev(dev);
  495. ret = sscanf(buf, "%u", &local_span_number);
  496. if (ret != 1)
  497. return -EINVAL;
  498. ret = -ENODEV;
  499. list_for_each_entry(span, &ddev->spans, device_node) {
  500. if (local_span_number == local_spanno(span))
  501. ret = dahdi_unassign_span(span);
  502. }
  503. if (-ENODEV == ret) {
  504. if (printk_ratelimit()) {
  505. dev_info(dev, "'%d' is an invalid local span number.\n",
  506. local_span_number);
  507. }
  508. return -EINVAL;
  509. }
  510. return (ret < 0) ? ret : count;
  511. }
  512. static ssize_t
  513. dahdi_spantype_show(struct device *dev,
  514. struct device_attribute *attr, char *buf)
  515. {
  516. struct dahdi_device *ddev = to_ddev(dev);
  517. int count = 0;
  518. ssize_t total = 0;
  519. struct dahdi_span *span;
  520. /* TODO: Make sure this doesn't overflow the page. */
  521. list_for_each_entry(span, &ddev->spans, device_node) {
  522. count = sprintf(buf, "%d:%s\n",
  523. local_spanno(span), dahdi_spantype2str(span->spantype));
  524. buf += count;
  525. total += count;
  526. }
  527. return total;
  528. }
  529. static ssize_t
  530. dahdi_spantype_store(struct device *dev, struct device_attribute *attr,
  531. const char *buf, size_t count)
  532. {
  533. struct dahdi_device *const ddev = to_ddev(dev);
  534. int ret;
  535. struct dahdi_span *span = NULL;
  536. struct dahdi_span *cur;
  537. unsigned int local_span_number;
  538. char spantype_name[80];
  539. enum spantypes spantype;
  540. ret = sscanf(buf, "%u:%70s", &local_span_number, spantype_name);
  541. if (ret != 2) {
  542. dev_err(&ddev->dev, "Wrong input format: '%s'\n", buf);
  543. return -EINVAL;
  544. }
  545. spantype = dahdi_str2spantype(spantype_name);
  546. if (spantype == SPANTYPE_INVALID) {
  547. dev_err(&ddev->dev, "Invalid spantype: '%s'\n", buf);
  548. return -EINVAL;
  549. }
  550. list_for_each_entry(cur, &ddev->spans, device_node) {
  551. if (local_spanno(cur) == local_span_number) {
  552. span = cur;
  553. break;
  554. }
  555. }
  556. if (!span || (local_spanno(span) != local_span_number)) {
  557. module_printk(KERN_WARNING,
  558. "%d is not a valid local span number "
  559. "for this device.\n", local_span_number);
  560. return -EINVAL;
  561. }
  562. if (test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags)) {
  563. module_printk(KERN_WARNING, "Span %s is already assigned.\n",
  564. span->name);
  565. return -EINVAL;
  566. }
  567. if (!span->ops->set_spantype) {
  568. module_printk(KERN_WARNING, "Span %s does not support "
  569. "setting type.\n", span->name);
  570. return -EINVAL;
  571. }
  572. ret = span->ops->set_spantype(span, spantype);
  573. return (ret < 0) ? ret : count;
  574. }
  575. static ssize_t
  576. dahdi_registration_time_show(struct device *dev,
  577. struct device_attribute *attr, char *buf)
  578. {
  579. struct dahdi_device *ddev = to_ddev(dev);
  580. int count = 0;
  581. count += sprintf(buf, "%010ld.%09ld\n",
  582. ddev->registration_time.tv_sec,
  583. ddev->registration_time.tv_nsec);
  584. return count;
  585. }
  586. static struct device_attribute dahdi_device_attrs[] = {
  587. __ATTR(manufacturer, S_IRUGO, dahdi_device_manufacturer_show, NULL),
  588. __ATTR(type, S_IRUGO, dahdi_device_type_show, NULL),
  589. __ATTR(span_count, S_IRUGO, dahdi_device_span_count_show, NULL),
  590. __ATTR(hardware_id, S_IRUGO, dahdi_device_hardware_id_show, NULL),
  591. __ATTR(location, S_IRUGO, dahdi_device_location_show, NULL),
  592. __ATTR(auto_assign, S_IWUSR, NULL, dahdi_device_auto_assign),
  593. __ATTR(assign_span, S_IWUSR, NULL, dahdi_device_assign_span),
  594. __ATTR(unassign_span, S_IWUSR, NULL, dahdi_device_unassign_span),
  595. __ATTR(spantype, S_IWUSR | S_IRUGO, dahdi_spantype_show,
  596. dahdi_spantype_store),
  597. __ATTR(registration_time, S_IRUGO, dahdi_registration_time_show, NULL),
  598. __ATTR_NULL,
  599. };
  600. static struct bus_type dahdi_device_bus = {
  601. .name = "dahdi_devices",
  602. .uevent = device_uevent,
  603. .dev_attrs = dahdi_device_attrs,
  604. };
  605. static void dahdi_sysfs_cleanup(void)
  606. {
  607. dahdi_dbg(DEVICES, "SYSFS\n");
  608. if (should_cleanup.clean_dahdi_driver) {
  609. dahdi_dbg(DEVICES, "Unregister driver\n");
  610. driver_unregister(&dahdi_driver);
  611. should_cleanup.clean_dahdi_driver = 0;
  612. }
  613. if (should_cleanup.clean_span_bus_type) {
  614. dahdi_dbg(DEVICES, "Unregister span bus type\n");
  615. bus_unregister(&spans_bus_type);
  616. should_cleanup.clean_span_bus_type = 0;
  617. }
  618. dahdi_sysfs_chan_exit();
  619. if (should_cleanup.clean_chardev) {
  620. dahdi_dbg(DEVICES, "Unregister character device\n");
  621. unregister_chrdev(DAHDI_MAJOR, "dahdi");
  622. should_cleanup.clean_chardev = 0;
  623. }
  624. if (should_cleanup.clean_device_bus) {
  625. dahdi_dbg(DEVICES, "Unregister DAHDI device bus\n");
  626. bus_unregister(&dahdi_device_bus);
  627. should_cleanup.clean_device_bus = 0;
  628. }
  629. }
  630. static void dahdi_device_release(struct device *dev)
  631. {
  632. struct dahdi_device *ddev = container_of(dev, struct dahdi_device, dev);
  633. kfree(ddev);
  634. }
  635. /**
  636. * dahdi_sysfs_add_device - Add the dahdi_device into the sysfs hierarchy.
  637. * @ddev: The device to add.
  638. * @parent: The physical device that is implementing this device.
  639. *
  640. * By adding the dahdi_device to the sysfs hierarchy user space can control
  641. * how spans are numbered.
  642. *
  643. */
  644. int dahdi_sysfs_add_device(struct dahdi_device *ddev, struct device *parent)
  645. {
  646. int ret;
  647. struct device *const dev = &ddev->dev;
  648. const char *dn;
  649. dev->parent = parent;
  650. dev->bus = &dahdi_device_bus;
  651. dn = dev_name(dev);
  652. if (!dn || !*dn) {
  653. /* Invent default name based on parent */
  654. if (!parent)
  655. return -EINVAL;
  656. dev_set_name(dev, "%s:%s", parent->bus->name, dev_name(parent));
  657. }
  658. ret = device_add(dev);
  659. return ret;
  660. }
  661. void dahdi_sysfs_init_device(struct dahdi_device *ddev)
  662. {
  663. device_initialize(&ddev->dev);
  664. ddev->dev.release = dahdi_device_release;
  665. }
  666. void dahdi_sysfs_unregister_device(struct dahdi_device *ddev)
  667. {
  668. device_del(&ddev->dev);
  669. }
  670. int __init dahdi_sysfs_init(const struct file_operations *dahdi_fops)
  671. {
  672. int res = 0;
  673. dahdi_dbg(DEVICES, "Registering DAHDI device bus\n");
  674. /* Handle dahdi-tools paths (for udev environment) */
  675. if (tools_rootdir && initdir) {
  676. dahdi_err("Cannot use tools-rootdir and initdir parameters simultaneously\n");
  677. return -EINVAL;
  678. }
  679. if (initdir)
  680. pr_notice("dahdi: initdir is depracated -- prefer using \"tools_rootdir\" parameter\n");
  681. else
  682. initdir = "/usr/share/dahdi";
  683. if (!tools_rootdir)
  684. tools_rootdir = "";
  685. res = bus_register(&dahdi_device_bus);
  686. if (res)
  687. return res;
  688. should_cleanup.clean_device_bus = 1;
  689. dahdi_dbg(DEVICES,
  690. "Registering character device (major=%d)\n", DAHDI_MAJOR);
  691. res = register_chrdev(DAHDI_MAJOR, "dahdi", dahdi_fops);
  692. if (res) {
  693. module_printk(KERN_ERR,
  694. "Unable to register DAHDI character device "
  695. "handler on %d\n", DAHDI_MAJOR);
  696. return res;
  697. }
  698. should_cleanup.clean_chardev = 1;
  699. res = dahdi_sysfs_chan_init(dahdi_fops);
  700. if (res)
  701. goto cleanup;
  702. res = bus_register(&spans_bus_type);
  703. if (res) {
  704. dahdi_err("%s: bus_register(%s) failed. Error number %d",
  705. __func__, spans_bus_type.name, res);
  706. goto cleanup;
  707. }
  708. should_cleanup.clean_span_bus_type = 1;
  709. res = driver_register(&dahdi_driver);
  710. if (res) {
  711. dahdi_err("%s: driver_register(%s) failed. Error number %d",
  712. __func__, dahdi_driver.name, res);
  713. goto cleanup;
  714. }
  715. should_cleanup.clean_dahdi_driver = 1;
  716. module_printk(KERN_INFO, "Telephony Interface Registered on major %d\n",
  717. DAHDI_MAJOR);
  718. return 0;
  719. cleanup:
  720. dahdi_sysfs_cleanup();
  721. return res;
  722. }
  723. void dahdi_sysfs_exit(void)
  724. {
  725. dahdi_sysfs_cleanup();
  726. }