DVB: add firesat driver
[linux-2.6-block.git] / drivers / media / dvb / firesat / cmp.c
1 #include "cmp.h"
2 #include <ieee1394.h>
3 #include <nodemgr.h>
4 #include <highlevel.h>
5 #include <ohci1394.h>
6 #include <hosts.h>
7 #include <ieee1394_core.h>
8 #include <ieee1394_transactions.h>
9 #include "avc_api.h"
10
11 typedef struct _OPCR
12 {
13         BYTE PTPConnCount    : 6 ; // Point to point connect. counter
14         BYTE BrConnCount     : 1 ; // Broadcast connection counter
15         BYTE OnLine          : 1 ; // On Line
16
17         BYTE ChNr            : 6 ; // Channel number
18         BYTE Res             : 2 ; // Reserved
19
20         BYTE PayloadHi       : 2 ; // Payoad high bits
21         BYTE OvhdID          : 4 ; // Overhead ID
22         BYTE DataRate        : 2 ; // Data Rate
23
24         BYTE PayloadLo           ; // Payoad low byte
25 } OPCR ;
26
27 #define FIRESAT_SPEED IEEE1394_SPEED_400
28
29 /* hpsb_lock is being removed from the kernel-source,
30  * therefor we define our own 'firesat_hpsb_lock'*/
31
32 int send_packet_and_wait(struct hpsb_packet *packet);
33
34 int firesat_hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
35                 u64 addr, int extcode, quadlet_t * data, quadlet_t arg) {
36
37         struct hpsb_packet *packet;
38         int retval = 0;
39
40         BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
41
42         packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
43         if (!packet)
44                 return -ENOMEM;
45
46         packet->generation = generation;
47         retval = send_packet_and_wait(packet);
48         if (retval < 0)
49                 goto hpsb_lock_fail;
50
51         retval = hpsb_packet_success(packet);
52
53         if (retval == 0) {
54                 *data = packet->data[0];
55         }
56
57         hpsb_lock_fail:
58         hpsb_free_tlabel(packet);
59         hpsb_free_packet(packet);
60
61         return retval;
62 }
63
64
65 static int cmp_read(struct firesat *firesat, void *buffer, u64 addr, size_t length) {
66         int ret;
67         if(down_interruptible(&firesat->avc_sem))
68                 return -EINTR;
69
70         ret = hpsb_read(firesat->host, firesat->nodeentry->nodeid, firesat->nodeentry->generation,
71                 addr, buffer, length);
72
73         up(&firesat->avc_sem);
74         return ret;
75 }
76
77 static int cmp_lock(struct firesat *firesat, quadlet_t *data, u64 addr, quadlet_t arg, int ext_tcode) {
78         int ret;
79         if(down_interruptible(&firesat->avc_sem))
80                 return -EINTR;
81
82         ret = firesat_hpsb_lock(firesat->host, firesat->nodeentry->nodeid, firesat->nodeentry->generation,
83                 addr, ext_tcode, data, arg);
84
85         up(&firesat->avc_sem);
86         return ret;
87 }
88
89 //try establishing a point-to-point connection (may be interrupted by a busreset
90 int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int iso_channel) {
91         unsigned int BWU; //bandwidth to allocate
92
93         quadlet_t old_oPCR,test_oPCR = 0x0;
94         u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
95         int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
96
97         printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid);
98
99         if (result < 0) {
100                 printk("%s: cannot read oPCR\n", __func__);
101                 return result;
102         } else {
103                 printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR);
104                 do {
105                         OPCR *hilf= (OPCR*) &test_oPCR;
106
107                         if (!hilf->OnLine) {
108                                 printk("%s: Output offline; oPCR: %08x\n", __func__, test_oPCR);
109                                 return -EBUSY;
110                         } else {
111                                 quadlet_t new_oPCR;
112
113                                 old_oPCR=test_oPCR;
114                                 if (hilf->PTPConnCount) {
115                                         if (hilf->ChNr != iso_channel) {
116                                                 printk("%s: Output plug has already connection on channel %u; cannot change it to channel %u\n",__func__,hilf->ChNr,iso_channel);
117                                                 return -EBUSY;
118                                         } else
119                                                 printk(KERN_INFO "%s: Overlaying existing connection; connection counter was: %u\n",__func__, hilf->PTPConnCount);
120                                         BWU=0; //we allocate no bandwidth (is this necessary?)
121                                 } else {
122                                         hilf->ChNr=iso_channel;
123                                         hilf->DataRate=FIRESAT_SPEED;
124
125                                         hilf->OvhdID=0;      //FIXME: that is for worst case -> optimize
126                                         BWU=hilf->OvhdID?hilf->OvhdID*32:512;
127                                         BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
128 /*                                      if (allocate_1394_resources(iso_channel,BWU))
129                                         {
130                                                 cout << "Allocation of resources failed\n";
131                                                 return -2;
132                                         }*/
133                                 }
134
135                                 hilf->PTPConnCount++;
136                                 new_oPCR=test_oPCR;
137                                 printk(KERN_INFO "%s: trying compare_swap...\n",__func__);
138                                 printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR);
139                                 result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
140
141                                 if (result < 0) {
142                                         printk("%s: cannot compare_swap oPCR\n",__func__);
143                                         return result;
144                                 }
145                                 if ((old_oPCR != test_oPCR) && (!((OPCR*) &old_oPCR)->PTPConnCount))
146                                 {
147                                         printk("%s: change of oPCR failed -> freeing resources\n",__func__);
148 //                                      hilf= (OPCR*) &new_oPCR;
149 //                                      unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
150 //                                      BWU += (hilf->Payload+3) * (2 << (3-hilf->DataRate));
151 /*                                      if (deallocate_1394_resources(iso_channel,BWU))
152                                         {
153
154                                                 cout << "Deallocation of resources failed\n";
155                                                 return -3;
156                                         }*/
157                                 }
158                         }
159                 }
160                 while (old_oPCR != test_oPCR);
161         }
162         return 0;
163 }
164
165 //try breaking a point-to-point connection (may be interrupted by a busreset
166 int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_channel) {
167         quadlet_t old_oPCR,test_oPCR;
168
169         u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
170         int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
171
172         printk(KERN_INFO "%s\n",__func__);
173
174         if (result < 0) {
175                 printk("%s: cannot read oPCR\n", __func__);
176                 return result;
177         } else {
178                 do {
179                         OPCR *hilf= (OPCR*) &test_oPCR;
180
181                         if (!hilf->OnLine || !hilf->PTPConnCount || hilf->ChNr != iso_channel) {
182                                 printk("%s: Output plug does not have PtP-connection on that channel; oPCR: %08x\n", __func__, test_oPCR);
183                                 return -EINVAL;
184                         } else {
185                                 quadlet_t new_oPCR;
186                                 old_oPCR=test_oPCR;
187                                 hilf->PTPConnCount--;
188                                 new_oPCR=test_oPCR;
189
190 //                              printk(KERN_INFO "%s: trying compare_swap...\n", __func__);
191                                 result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
192                                 if (result < 0) {
193                                         printk("%s: cannot compare_swap oPCR\n",__func__);
194                                         return result;
195                                 }
196                         }
197
198                 } while (old_oPCR != test_oPCR);
199
200 /*              hilf = (OPCR*) &old_oPCR;
201                 if (hilf->PTPConnCount == 1) { // if we were the last owner of this connection
202                         cout << "deallocating 1394 resources\n";
203                         unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
204                         BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
205                         if (deallocate_1394_resources(iso_channel,BWU))
206                         {
207                                 cout << "Deallocation of resources failed\n";
208                                 return -3;
209                         }
210                 }*/
211     }
212         return 0;
213 }
214
215 static void complete_packet(void *data) {
216         complete((struct completion *) data);
217 }
218
219 int send_packet_and_wait(struct hpsb_packet *packet) {
220         struct completion done;
221         int retval;
222
223         init_completion(&done);
224         hpsb_set_packet_complete_task(packet, complete_packet, &done);
225         retval = hpsb_send_packet(packet);
226         if (retval == 0)
227                 wait_for_completion(&done);
228
229         return retval;
230 }