blob: d1bafba615e4bf5e86b2bc806d4e51214395c9b5 [file] [log] [blame]
Henrik Kureliddf4846c2008-08-01 10:00:45 +02001/*
Stefan Richter612262a2008-08-26 00:17:30 +02002 * FireDTV driver (formerly known as FireSAT)
Henrik Kureliddf4846c2008-08-01 10:00:45 +02003 *
Stefan Richter612262a2008-08-26 00:17:30 +02004 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
Henrik Kureliddf4846c2008-08-01 10:00:45 +02006 *
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
Stefan Richter612262a2008-08-26 00:17:30 +020013#include <linux/kernel.h>
14#include <linux/mutex.h>
15#include <linux/types.h>
16
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080017#include <hosts.h>
Stefan Richter612262a2008-08-26 00:17:30 +020018#include <ieee1394.h>
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080019#include <ieee1394_core.h>
20#include <ieee1394_transactions.h>
Stefan Richter612262a2008-08-26 00:17:30 +020021#include <nodemgr.h>
22
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080023#include "avc_api.h"
Stefan Richter612262a2008-08-26 00:17:30 +020024#include "cmp.h"
25#include "firesat.h"
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080026
27typedef struct _OPCR
28{
Henrik Kureliddf4846c2008-08-01 10:00:45 +020029 __u8 PTPConnCount : 6 ; // Point to point connect. counter
30 __u8 BrConnCount : 1 ; // Broadcast connection counter
31 __u8 OnLine : 1 ; // On Line
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080032
Henrik Kureliddf4846c2008-08-01 10:00:45 +020033 __u8 ChNr : 6 ; // Channel number
34 __u8 Res : 2 ; // Reserved
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080035
Henrik Kureliddf4846c2008-08-01 10:00:45 +020036 __u8 PayloadHi : 2 ; // Payoad high bits
37 __u8 OvhdID : 4 ; // Overhead ID
38 __u8 DataRate : 2 ; // Data Rate
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080039
Henrik Kureliddf4846c2008-08-01 10:00:45 +020040 __u8 PayloadLo ; // Payoad low byte
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080041} OPCR ;
42
43#define FIRESAT_SPEED IEEE1394_SPEED_400
44
Stefan Richter612262a2008-08-26 00:17:30 +020045static int cmp_read(struct firesat *firesat, void *buf, u64 addr, size_t len)
46{
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080047 int ret;
Stefan Richter612262a2008-08-26 00:17:30 +020048
49 if (mutex_lock_interruptible(&firesat->avc_mutex))
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080050 return -EINTR;
51
Stefan Richter612262a2008-08-26 00:17:30 +020052 ret = hpsb_read(firesat->host, firesat->nodeentry->nodeid,
53 firesat->nodeentry->generation, addr, buf, len);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080054
Stefan Richter612262a2008-08-26 00:17:30 +020055 mutex_unlock(&firesat->avc_mutex);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080056 return ret;
57}
58
Stefan Richter612262a2008-08-26 00:17:30 +020059static int cmp_lock(struct firesat *firesat, quadlet_t *data, u64 addr,
60 quadlet_t arg, int ext_tcode)
61{
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080062 int ret;
Stefan Richter612262a2008-08-26 00:17:30 +020063
64 if (mutex_lock_interruptible(&firesat->avc_mutex))
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080065 return -EINTR;
66
Stefan Richter612262a2008-08-26 00:17:30 +020067 ret = hpsb_lock(firesat->host, firesat->nodeentry->nodeid,
68 firesat->nodeentry->generation,
69 addr, ext_tcode, data, arg);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080070
Stefan Richter612262a2008-08-26 00:17:30 +020071 mutex_unlock(&firesat->avc_mutex);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080072 return ret;
73}
74
75//try establishing a point-to-point connection (may be interrupted by a busreset
76int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int iso_channel) {
77 unsigned int BWU; //bandwidth to allocate
78
79 quadlet_t old_oPCR,test_oPCR = 0x0;
80 u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
81 int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
82
Henrik Kureliddf4846c2008-08-01 10:00:45 +020083/* printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid); */
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080084
85 if (result < 0) {
86 printk("%s: cannot read oPCR\n", __func__);
87 return result;
88 } else {
Henrik Kureliddf4846c2008-08-01 10:00:45 +020089/* printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR); */
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080090 do {
91 OPCR *hilf= (OPCR*) &test_oPCR;
92
93 if (!hilf->OnLine) {
94 printk("%s: Output offline; oPCR: %08x\n", __func__, test_oPCR);
95 return -EBUSY;
96 } else {
97 quadlet_t new_oPCR;
98
99 old_oPCR=test_oPCR;
100 if (hilf->PTPConnCount) {
101 if (hilf->ChNr != iso_channel) {
102 printk("%s: Output plug has already connection on channel %u; cannot change it to channel %u\n",__func__,hilf->ChNr,iso_channel);
103 return -EBUSY;
104 } else
105 printk(KERN_INFO "%s: Overlaying existing connection; connection counter was: %u\n",__func__, hilf->PTPConnCount);
106 BWU=0; //we allocate no bandwidth (is this necessary?)
107 } else {
108 hilf->ChNr=iso_channel;
109 hilf->DataRate=FIRESAT_SPEED;
110
111 hilf->OvhdID=0; //FIXME: that is for worst case -> optimize
112 BWU=hilf->OvhdID?hilf->OvhdID*32:512;
113 BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
114/* if (allocate_1394_resources(iso_channel,BWU))
115 {
116 cout << "Allocation of resources failed\n";
117 return -2;
118 }*/
119 }
120
121 hilf->PTPConnCount++;
122 new_oPCR=test_oPCR;
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200123/* printk(KERN_INFO "%s: trying compare_swap...\n",__func__); */
124/* printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR); */
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800125 result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
126
127 if (result < 0) {
128 printk("%s: cannot compare_swap oPCR\n",__func__);
129 return result;
130 }
131 if ((old_oPCR != test_oPCR) && (!((OPCR*) &old_oPCR)->PTPConnCount))
132 {
133 printk("%s: change of oPCR failed -> freeing resources\n",__func__);
134// hilf= (OPCR*) &new_oPCR;
135// unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
136// BWU += (hilf->Payload+3) * (2 << (3-hilf->DataRate));
137/* if (deallocate_1394_resources(iso_channel,BWU))
138 {
139
140 cout << "Deallocation of resources failed\n";
141 return -3;
142 }*/
143 }
144 }
145 }
146 while (old_oPCR != test_oPCR);
147 }
148 return 0;
149}
150
151//try breaking a point-to-point connection (may be interrupted by a busreset
152int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_channel) {
153 quadlet_t old_oPCR,test_oPCR;
154
155 u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
156 int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
157
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200158/* printk(KERN_INFO "%s\n",__func__); */
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800159
160 if (result < 0) {
161 printk("%s: cannot read oPCR\n", __func__);
162 return result;
163 } else {
164 do {
165 OPCR *hilf= (OPCR*) &test_oPCR;
166
167 if (!hilf->OnLine || !hilf->PTPConnCount || hilf->ChNr != iso_channel) {
168 printk("%s: Output plug does not have PtP-connection on that channel; oPCR: %08x\n", __func__, test_oPCR);
169 return -EINVAL;
170 } else {
171 quadlet_t new_oPCR;
172 old_oPCR=test_oPCR;
173 hilf->PTPConnCount--;
174 new_oPCR=test_oPCR;
175
176// printk(KERN_INFO "%s: trying compare_swap...\n", __func__);
177 result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
178 if (result < 0) {
179 printk("%s: cannot compare_swap oPCR\n",__func__);
180 return result;
181 }
182 }
183
184 } while (old_oPCR != test_oPCR);
185
186/* hilf = (OPCR*) &old_oPCR;
187 if (hilf->PTPConnCount == 1) { // if we were the last owner of this connection
188 cout << "deallocating 1394 resources\n";
189 unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
190 BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
191 if (deallocate_1394_resources(iso_channel,BWU))
192 {
193 cout << "Deallocation of resources failed\n";
194 return -3;
195 }
196 }*/
197 }
198 return 0;
199}