firesat_1394.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. * FireDTV driver (formerly known as FireSAT)
  3. *
  4. * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
  5. * Copyright (C) 2007-2008 Ben Backx <ben@bbackx.com>
  6. * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. */
  13. #include <linux/device.h>
  14. #include <linux/errno.h>
  15. #include <linux/kernel.h>
  16. #include <linux/list.h>
  17. #include <linux/module.h>
  18. #include <linux/mutex.h>
  19. #include <linux/slab.h>
  20. #include <linux/spinlock.h>
  21. #include <linux/string.h>
  22. #include <linux/types.h>
  23. #include <dmxdev.h>
  24. #include <dvb_demux.h>
  25. #include <dvb_frontend.h>
  26. #include <dvbdev.h>
  27. #include <csr1212.h>
  28. #include <highlevel.h>
  29. #include <hosts.h>
  30. #include <ieee1394_hotplug.h>
  31. #include <nodemgr.h>
  32. #include "avc_api.h"
  33. #include "cmp.h"
  34. #include "firesat.h"
  35. #include "firesat-ci.h"
  36. #include "firesat-rc.h"
  37. #define MATCH_FLAGS IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
  38. IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION
  39. #define DIGITAL_EVERYWHERE_OUI 0x001287
  40. static struct ieee1394_device_id firesat_id_table[] = {
  41. {
  42. /* FloppyDTV S/CI and FloppyDTV S2 */
  43. .match_flags = MATCH_FLAGS,
  44. .vendor_id = DIGITAL_EVERYWHERE_OUI,
  45. .model_id = 0x000024,
  46. .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
  47. .version = AVC_SW_VERSION_ENTRY,
  48. },{
  49. /* FloppyDTV T/CI */
  50. .match_flags = MATCH_FLAGS,
  51. .vendor_id = DIGITAL_EVERYWHERE_OUI,
  52. .model_id = 0x000025,
  53. .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
  54. .version = AVC_SW_VERSION_ENTRY,
  55. },{
  56. /* FloppyDTV C/CI */
  57. .match_flags = MATCH_FLAGS,
  58. .vendor_id = DIGITAL_EVERYWHERE_OUI,
  59. .model_id = 0x000026,
  60. .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
  61. .version = AVC_SW_VERSION_ENTRY,
  62. },{
  63. /* FireDTV S/CI and FloppyDTV S2 */
  64. .match_flags = MATCH_FLAGS,
  65. .vendor_id = DIGITAL_EVERYWHERE_OUI,
  66. .model_id = 0x000034,
  67. .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
  68. .version = AVC_SW_VERSION_ENTRY,
  69. },{
  70. /* FireDTV T/CI */
  71. .match_flags = MATCH_FLAGS,
  72. .vendor_id = DIGITAL_EVERYWHERE_OUI,
  73. .model_id = 0x000035,
  74. .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
  75. .version = AVC_SW_VERSION_ENTRY,
  76. },{
  77. /* FireDTV C/CI */
  78. .match_flags = MATCH_FLAGS,
  79. .vendor_id = DIGITAL_EVERYWHERE_OUI,
  80. .model_id = 0x000036,
  81. .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
  82. .version = AVC_SW_VERSION_ENTRY,
  83. }, { }
  84. };
  85. MODULE_DEVICE_TABLE(ieee1394, firesat_id_table);
  86. /* list of all firesat devices */
  87. LIST_HEAD(firesat_list);
  88. DEFINE_SPINLOCK(firesat_list_lock);
  89. static void fcp_request(struct hpsb_host *host,
  90. int nodeid,
  91. int direction,
  92. int cts,
  93. u8 *data,
  94. size_t length)
  95. {
  96. struct firesat *firesat = NULL;
  97. struct firesat *firesat_entry;
  98. unsigned long flags;
  99. if (length > 0 && ((data[0] & 0xf0) >> 4) == 0) {
  100. spin_lock_irqsave(&firesat_list_lock, flags);
  101. list_for_each_entry(firesat_entry,&firesat_list,list) {
  102. if (firesat_entry->ud->ne->host == host &&
  103. firesat_entry->ud->ne->nodeid == nodeid &&
  104. (firesat_entry->subunit == (data[1]&0x7) ||
  105. (firesat_entry->subunit == 0 &&
  106. (data[1]&0x7) == 0x7))) {
  107. firesat=firesat_entry;
  108. break;
  109. }
  110. }
  111. spin_unlock_irqrestore(&firesat_list_lock, flags);
  112. if (firesat)
  113. avc_recv(firesat, data, length);
  114. }
  115. }
  116. const char *firedtv_model_names[] = {
  117. [FireSAT_UNKNOWN] = "unknown type",
  118. [FireSAT_DVB_S] = "FireDTV S/CI",
  119. [FireSAT_DVB_C] = "FireDTV C/CI",
  120. [FireSAT_DVB_T] = "FireDTV T/CI",
  121. [FireSAT_DVB_S2] = "FireDTV S2 ",
  122. };
  123. static int firesat_probe(struct device *dev)
  124. {
  125. struct unit_directory *ud =
  126. container_of(dev, struct unit_directory, device);
  127. struct firesat *firesat;
  128. unsigned long flags;
  129. int kv_len;
  130. void *kv_str;
  131. int i;
  132. int err = -ENOMEM;
  133. firesat = kzalloc(sizeof(*firesat), GFP_KERNEL);
  134. if (!firesat)
  135. return -ENOMEM;
  136. dev->driver_data = firesat;
  137. firesat->ud = ud;
  138. firesat->subunit = 0;
  139. firesat->isochannel = -1;
  140. firesat->tone = 0xff;
  141. firesat->voltage = 0xff;
  142. mutex_init(&firesat->avc_mutex);
  143. init_waitqueue_head(&firesat->avc_wait);
  144. firesat->avc_reply_received = true;
  145. mutex_init(&firesat->demux_mutex);
  146. INIT_WORK(&firesat->remote_ctrl_work, avc_remote_ctrl_work);
  147. /* Reading device model from ROM */
  148. kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t);
  149. kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
  150. for (i = ARRAY_SIZE(firedtv_model_names); --i;)
  151. if (strlen(firedtv_model_names[i]) <= kv_len &&
  152. strncmp(kv_str, firedtv_model_names[i], kv_len) == 0)
  153. break;
  154. firesat->type = i;
  155. /*
  156. * Work around a bug in udev's path_id script: Use the fw-host's dev
  157. * instead of the unit directory's dev as parent of the input device.
  158. */
  159. err = firesat_register_rc(firesat, dev->parent->parent);
  160. if (err)
  161. goto fail_free;
  162. INIT_LIST_HEAD(&firesat->list);
  163. spin_lock_irqsave(&firesat_list_lock, flags);
  164. list_add_tail(&firesat->list, &firesat_list);
  165. spin_unlock_irqrestore(&firesat_list_lock, flags);
  166. err = avc_identify_subunit(firesat);
  167. if (err)
  168. goto fail;
  169. err = firesat_dvbdev_init(firesat, dev);
  170. if (err)
  171. goto fail;
  172. avc_register_remote_control(firesat);
  173. return 0;
  174. fail:
  175. spin_lock_irqsave(&firesat_list_lock, flags);
  176. list_del(&firesat->list);
  177. spin_unlock_irqrestore(&firesat_list_lock, flags);
  178. firesat_unregister_rc(firesat);
  179. fail_free:
  180. kfree(firesat);
  181. return err;
  182. }
  183. static int firesat_remove(struct device *dev)
  184. {
  185. struct firesat *firesat = dev->driver_data;
  186. unsigned long flags;
  187. firesat_ca_release(firesat);
  188. dvb_unregister_frontend(&firesat->fe);
  189. dvb_net_release(&firesat->dvbnet);
  190. firesat->demux.dmx.close(&firesat->demux.dmx);
  191. firesat->demux.dmx.remove_frontend(&firesat->demux.dmx,
  192. &firesat->frontend);
  193. dvb_dmxdev_release(&firesat->dmxdev);
  194. dvb_dmx_release(&firesat->demux);
  195. dvb_unregister_adapter(&firesat->adapter);
  196. spin_lock_irqsave(&firesat_list_lock, flags);
  197. list_del(&firesat->list);
  198. spin_unlock_irqrestore(&firesat_list_lock, flags);
  199. cancel_work_sync(&firesat->remote_ctrl_work);
  200. firesat_unregister_rc(firesat);
  201. kfree(firesat);
  202. return 0;
  203. }
  204. static int firesat_update(struct unit_directory *ud)
  205. {
  206. struct firesat *firesat = ud->device.driver_data;
  207. if (firesat->isochannel >= 0)
  208. cmp_establish_pp_connection(firesat, firesat->subunit,
  209. firesat->isochannel);
  210. return 0;
  211. }
  212. static struct hpsb_protocol_driver firesat_driver = {
  213. .name = "firedtv",
  214. .id_table = firesat_id_table,
  215. .update = firesat_update,
  216. .driver = {
  217. //.name and .bus are filled in for us in more recent linux versions
  218. //.name = "FireSAT",
  219. //.bus = &ieee1394_bus_type,
  220. .probe = firesat_probe,
  221. .remove = firesat_remove,
  222. },
  223. };
  224. static struct hpsb_highlevel firesat_highlevel = {
  225. .name = "firedtv",
  226. .fcp_request = fcp_request,
  227. };
  228. static int __init firesat_init(void)
  229. {
  230. int ret;
  231. hpsb_register_highlevel(&firesat_highlevel);
  232. ret = hpsb_register_protocol(&firesat_driver);
  233. if (ret) {
  234. printk(KERN_ERR "firedtv: failed to register protocol\n");
  235. hpsb_unregister_highlevel(&firesat_highlevel);
  236. }
  237. return ret;
  238. }
  239. static void __exit firesat_exit(void)
  240. {
  241. hpsb_unregister_protocol(&firesat_driver);
  242. hpsb_unregister_highlevel(&firesat_highlevel);
  243. }
  244. module_init(firesat_init);
  245. module_exit(firesat_exit);
  246. MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
  247. MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
  248. MODULE_DESCRIPTION("FireDTV DVB Driver");
  249. MODULE_LICENSE("GPL");
  250. MODULE_SUPPORTED_DEVICE("FireDTV DVB");