cmp.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. * FireDTV driver (formerly known as FireSAT)
  3. *
  4. * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
  5. * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/mutex.h>
  14. #include <linux/types.h>
  15. #include <hosts.h>
  16. #include <ieee1394.h>
  17. #include <ieee1394_core.h>
  18. #include <ieee1394_transactions.h>
  19. #include <nodemgr.h>
  20. #include "avc_api.h"
  21. #include "cmp.h"
  22. #include "firesat.h"
  23. typedef struct _OPCR
  24. {
  25. __u8 PTPConnCount : 6 ; // Point to point connect. counter
  26. __u8 BrConnCount : 1 ; // Broadcast connection counter
  27. __u8 OnLine : 1 ; // On Line
  28. __u8 ChNr : 6 ; // Channel number
  29. __u8 Res : 2 ; // Reserved
  30. __u8 PayloadHi : 2 ; // Payoad high bits
  31. __u8 OvhdID : 4 ; // Overhead ID
  32. __u8 DataRate : 2 ; // Data Rate
  33. __u8 PayloadLo ; // Payoad low byte
  34. } OPCR ;
  35. #define FIRESAT_SPEED IEEE1394_SPEED_400
  36. static int cmp_read(struct firesat *firesat, void *buf, u64 addr, size_t len)
  37. {
  38. int ret;
  39. if (mutex_lock_interruptible(&firesat->avc_mutex))
  40. return -EINTR;
  41. ret = hpsb_read(firesat->host, firesat->nodeentry->nodeid,
  42. firesat->nodeentry->generation, addr, buf, len);
  43. mutex_unlock(&firesat->avc_mutex);
  44. return ret;
  45. }
  46. static int cmp_lock(struct firesat *firesat, quadlet_t *data, u64 addr,
  47. quadlet_t arg, int ext_tcode)
  48. {
  49. int ret;
  50. if (mutex_lock_interruptible(&firesat->avc_mutex))
  51. return -EINTR;
  52. ret = hpsb_lock(firesat->host, firesat->nodeentry->nodeid,
  53. firesat->nodeentry->generation,
  54. addr, ext_tcode, data, arg);
  55. mutex_unlock(&firesat->avc_mutex);
  56. return ret;
  57. }
  58. //try establishing a point-to-point connection (may be interrupted by a busreset
  59. int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int iso_channel) {
  60. unsigned int BWU; //bandwidth to allocate
  61. quadlet_t old_oPCR,test_oPCR = 0x0;
  62. u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
  63. int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
  64. /* printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid); */
  65. if (result < 0) {
  66. printk("%s: cannot read oPCR\n", __func__);
  67. return result;
  68. } else {
  69. /* printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR); */
  70. do {
  71. OPCR *hilf= (OPCR*) &test_oPCR;
  72. if (!hilf->OnLine) {
  73. printk("%s: Output offline; oPCR: %08x\n", __func__, test_oPCR);
  74. return -EBUSY;
  75. } else {
  76. quadlet_t new_oPCR;
  77. old_oPCR=test_oPCR;
  78. if (hilf->PTPConnCount) {
  79. if (hilf->ChNr != iso_channel) {
  80. printk("%s: Output plug has already connection on channel %u; cannot change it to channel %u\n",__func__,hilf->ChNr,iso_channel);
  81. return -EBUSY;
  82. } else
  83. printk(KERN_INFO "%s: Overlaying existing connection; connection counter was: %u\n",__func__, hilf->PTPConnCount);
  84. BWU=0; //we allocate no bandwidth (is this necessary?)
  85. } else {
  86. hilf->ChNr=iso_channel;
  87. hilf->DataRate=FIRESAT_SPEED;
  88. hilf->OvhdID=0; //FIXME: that is for worst case -> optimize
  89. BWU=hilf->OvhdID?hilf->OvhdID*32:512;
  90. BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
  91. /* if (allocate_1394_resources(iso_channel,BWU))
  92. {
  93. cout << "Allocation of resources failed\n";
  94. return -2;
  95. }*/
  96. }
  97. hilf->PTPConnCount++;
  98. new_oPCR=test_oPCR;
  99. /* printk(KERN_INFO "%s: trying compare_swap...\n",__func__); */
  100. /* printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR); */
  101. result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
  102. if (result < 0) {
  103. printk("%s: cannot compare_swap oPCR\n",__func__);
  104. return result;
  105. }
  106. if ((old_oPCR != test_oPCR) && (!((OPCR*) &old_oPCR)->PTPConnCount))
  107. {
  108. printk("%s: change of oPCR failed -> freeing resources\n",__func__);
  109. // hilf= (OPCR*) &new_oPCR;
  110. // unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
  111. // BWU += (hilf->Payload+3) * (2 << (3-hilf->DataRate));
  112. /* if (deallocate_1394_resources(iso_channel,BWU))
  113. {
  114. cout << "Deallocation of resources failed\n";
  115. return -3;
  116. }*/
  117. }
  118. }
  119. }
  120. while (old_oPCR != test_oPCR);
  121. }
  122. return 0;
  123. }
  124. //try breaking a point-to-point connection (may be interrupted by a busreset
  125. int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_channel) {
  126. quadlet_t old_oPCR,test_oPCR;
  127. u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
  128. int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
  129. /* printk(KERN_INFO "%s\n",__func__); */
  130. if (result < 0) {
  131. printk("%s: cannot read oPCR\n", __func__);
  132. return result;
  133. } else {
  134. do {
  135. OPCR *hilf= (OPCR*) &test_oPCR;
  136. if (!hilf->OnLine || !hilf->PTPConnCount || hilf->ChNr != iso_channel) {
  137. printk("%s: Output plug does not have PtP-connection on that channel; oPCR: %08x\n", __func__, test_oPCR);
  138. return -EINVAL;
  139. } else {
  140. quadlet_t new_oPCR;
  141. old_oPCR=test_oPCR;
  142. hilf->PTPConnCount--;
  143. new_oPCR=test_oPCR;
  144. // printk(KERN_INFO "%s: trying compare_swap...\n", __func__);
  145. result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
  146. if (result < 0) {
  147. printk("%s: cannot compare_swap oPCR\n",__func__);
  148. return result;
  149. }
  150. }
  151. } while (old_oPCR != test_oPCR);
  152. /* hilf = (OPCR*) &old_oPCR;
  153. if (hilf->PTPConnCount == 1) { // if we were the last owner of this connection
  154. cout << "deallocating 1394 resources\n";
  155. unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
  156. BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
  157. if (deallocate_1394_resources(iso_channel,BWU))
  158. {
  159. cout << "Deallocation of resources failed\n";
  160. return -3;
  161. }
  162. }*/
  163. }
  164. return 0;
  165. }