firesat: update isochronous interface, add CI support
[wandboard.git] / drivers / media / dvb / firesat / cmp.c
bloba1291caa0674af2f2b52000791a189fd0688b13b
1 /*
2 * FireSAT DVB driver
4 * Copyright (c) ?
5 * Copyright (c) 2008 Henrik Kurelid <henrik@kurelid.se>
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.
13 #include "cmp.h"
14 #include <ieee1394.h>
15 #include <nodemgr.h>
16 #include <highlevel.h>
17 #include <ohci1394.h>
18 #include <hosts.h>
19 #include <ieee1394_core.h>
20 #include <ieee1394_transactions.h>
21 #include "avc_api.h"
23 typedef struct _OPCR
25 __u8 PTPConnCount : 6 ; // Point to point connect. counter
26 __u8 BrConnCount : 1 ; // Broadcast connection counter
27 __u8 OnLine : 1 ; // On Line
29 __u8 ChNr : 6 ; // Channel number
30 __u8 Res : 2 ; // Reserved
32 __u8 PayloadHi : 2 ; // Payoad high bits
33 __u8 OvhdID : 4 ; // Overhead ID
34 __u8 DataRate : 2 ; // Data Rate
36 __u8 PayloadLo ; // Payoad low byte
37 } OPCR ;
39 #define FIRESAT_SPEED IEEE1394_SPEED_400
41 /* hpsb_lock is being removed from the kernel-source,
42 * therefor we define our own 'firesat_hpsb_lock'*/
44 int send_packet_and_wait(struct hpsb_packet *packet);
46 int firesat_hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
47 u64 addr, int extcode, quadlet_t * data, quadlet_t arg) {
49 struct hpsb_packet *packet;
50 int retval = 0;
52 BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
54 packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
55 if (!packet)
56 return -ENOMEM;
58 packet->generation = generation;
59 retval = send_packet_and_wait(packet);
60 if (retval < 0)
61 goto hpsb_lock_fail;
63 retval = hpsb_packet_success(packet);
65 if (retval == 0) {
66 *data = packet->data[0];
69 hpsb_lock_fail:
70 hpsb_free_tlabel(packet);
71 hpsb_free_packet(packet);
73 return retval;
77 static int cmp_read(struct firesat *firesat, void *buffer, u64 addr, size_t length) {
78 int ret;
79 if(down_interruptible(&firesat->avc_sem))
80 return -EINTR;
82 ret = hpsb_read(firesat->host, firesat->nodeentry->nodeid, firesat->nodeentry->generation,
83 addr, buffer, length);
85 up(&firesat->avc_sem);
86 return ret;
89 static int cmp_lock(struct firesat *firesat, quadlet_t *data, u64 addr, quadlet_t arg, int ext_tcode) {
90 int ret;
91 if(down_interruptible(&firesat->avc_sem))
92 return -EINTR;
94 ret = firesat_hpsb_lock(firesat->host, firesat->nodeentry->nodeid, firesat->nodeentry->generation,
95 addr, ext_tcode, data, arg);
97 up(&firesat->avc_sem);
98 return ret;
101 //try establishing a point-to-point connection (may be interrupted by a busreset
102 int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int iso_channel) {
103 unsigned int BWU; //bandwidth to allocate
105 quadlet_t old_oPCR,test_oPCR = 0x0;
106 u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
107 int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
109 /* printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid); */
111 if (result < 0) {
112 printk("%s: cannot read oPCR\n", __func__);
113 return result;
114 } else {
115 /* printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR); */
116 do {
117 OPCR *hilf= (OPCR*) &test_oPCR;
119 if (!hilf->OnLine) {
120 printk("%s: Output offline; oPCR: %08x\n", __func__, test_oPCR);
121 return -EBUSY;
122 } else {
123 quadlet_t new_oPCR;
125 old_oPCR=test_oPCR;
126 if (hilf->PTPConnCount) {
127 if (hilf->ChNr != iso_channel) {
128 printk("%s: Output plug has already connection on channel %u; cannot change it to channel %u\n",__func__,hilf->ChNr,iso_channel);
129 return -EBUSY;
130 } else
131 printk(KERN_INFO "%s: Overlaying existing connection; connection counter was: %u\n",__func__, hilf->PTPConnCount);
132 BWU=0; //we allocate no bandwidth (is this necessary?)
133 } else {
134 hilf->ChNr=iso_channel;
135 hilf->DataRate=FIRESAT_SPEED;
137 hilf->OvhdID=0; //FIXME: that is for worst case -> optimize
138 BWU=hilf->OvhdID?hilf->OvhdID*32:512;
139 BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
140 /* if (allocate_1394_resources(iso_channel,BWU))
142 cout << "Allocation of resources failed\n";
143 return -2;
147 hilf->PTPConnCount++;
148 new_oPCR=test_oPCR;
149 /* printk(KERN_INFO "%s: trying compare_swap...\n",__func__); */
150 /* printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR); */
151 result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
153 if (result < 0) {
154 printk("%s: cannot compare_swap oPCR\n",__func__);
155 return result;
157 if ((old_oPCR != test_oPCR) && (!((OPCR*) &old_oPCR)->PTPConnCount))
159 printk("%s: change of oPCR failed -> freeing resources\n",__func__);
160 // hilf= (OPCR*) &new_oPCR;
161 // unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
162 // BWU += (hilf->Payload+3) * (2 << (3-hilf->DataRate));
163 /* if (deallocate_1394_resources(iso_channel,BWU))
166 cout << "Deallocation of resources failed\n";
167 return -3;
172 while (old_oPCR != test_oPCR);
174 return 0;
177 //try breaking a point-to-point connection (may be interrupted by a busreset
178 int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_channel) {
179 quadlet_t old_oPCR,test_oPCR;
181 u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
182 int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
184 /* printk(KERN_INFO "%s\n",__func__); */
186 if (result < 0) {
187 printk("%s: cannot read oPCR\n", __func__);
188 return result;
189 } else {
190 do {
191 OPCR *hilf= (OPCR*) &test_oPCR;
193 if (!hilf->OnLine || !hilf->PTPConnCount || hilf->ChNr != iso_channel) {
194 printk("%s: Output plug does not have PtP-connection on that channel; oPCR: %08x\n", __func__, test_oPCR);
195 return -EINVAL;
196 } else {
197 quadlet_t new_oPCR;
198 old_oPCR=test_oPCR;
199 hilf->PTPConnCount--;
200 new_oPCR=test_oPCR;
202 // printk(KERN_INFO "%s: trying compare_swap...\n", __func__);
203 result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
204 if (result < 0) {
205 printk("%s: cannot compare_swap oPCR\n",__func__);
206 return result;
210 } while (old_oPCR != test_oPCR);
212 /* hilf = (OPCR*) &old_oPCR;
213 if (hilf->PTPConnCount == 1) { // if we were the last owner of this connection
214 cout << "deallocating 1394 resources\n";
215 unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
216 BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
217 if (deallocate_1394_resources(iso_channel,BWU))
219 cout << "Deallocation of resources failed\n";
220 return -3;
224 return 0;
227 static void complete_packet(void *data) {
228 complete((struct completion *) data);
231 int send_packet_and_wait(struct hpsb_packet *packet) {
232 struct completion done;
233 int retval;
235 init_completion(&done);
236 hpsb_set_packet_complete_task(packet, complete_packet, &done);
237 retval = hpsb_send_packet(packet);
238 if (retval == 0)
239 wait_for_completion(&done);
241 return retval;