diff options
Diffstat (limited to 'drivers/media/dvb/firesat/cmp.c')
-rw-r--r-- | drivers/media/dvb/firesat/cmp.c | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/drivers/media/dvb/firesat/cmp.c b/drivers/media/dvb/firesat/cmp.c new file mode 100644 index 000000000000..37b91f3f7ff1 --- /dev/null +++ b/drivers/media/dvb/firesat/cmp.c | |||
@@ -0,0 +1,230 @@ | |||
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 | } | ||