root/trunk/libffado/src/genericavc/stanton/scs.cpp

Revision 2802, 13.7 kB (checked in by jwoithe, 3 years ago)

Cosmetic: "Firewire" becomes "FireWire?".

Officially both the "F" and "W" were capitalised in the FireWire? name, so
reflect this throughout FFADO's source tree. This mostly affects comments.

This patch originated from pander on the ffado-devel mailing list. To
maintain consistency, the committed version has been expanded to include
files not originally included in the original patch.

Line 
1 /*
2  * Copyright (C) 2009 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free FireWire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "scs.h"
25
26 #include "libieee1394/configrom.h"
27 #include "libieee1394/ieee1394service.h"
28
29 #include "libutil/ByteSwap.h"
30 #include "libutil/Functors.h"
31
32 namespace GenericAVC {
33 namespace Stanton {
34
35 ScsDevice::ScsDevice( DeviceManager& d,
36                       ffado_smartptr<ConfigRom>( configRom ))
37 : GenericAVC::Device( d , configRom)
38 , m_hss1394handler( NULL )
39 {
40     debugOutput( DEBUG_LEVEL_VERBOSE, "Created GenericAVC::Stanton::ScsDevice (NodeID %d)\n",
41                  getConfigRom().getNodeId() );
42 }
43
44 ScsDevice::~ScsDevice()
45 {
46     if (m_hss1394handler) {
47         get1394Service().unregisterARMHandler(m_hss1394handler);
48         delete m_hss1394handler;
49         m_hss1394handler = NULL;
50     }
51 }
52
53 bool
54 ScsDevice::discover()
55 {
56 // HSS1394 is now being handled by an ALSA MIDI driver.  It is therefore
57 // not appropriate that FFADO install an ARM to receive these messages;
58 // doing so will clearly interfere with the other driver.
59 //    if(!initMessageHandler()) {
60 //        debugError("Could not initialize HSS1394 message handler\n");
61 //        return false;
62 //    }
63     return Device::discover();
64 }
65
66 bool
67 ScsDevice::initMessageHandler() {
68     fb_nodeaddr_t addr = HSS1394_BASE_ADDRESS;
69     quadlet_t cmdBuffer[2];
70
71     memset(cmdBuffer, 0, sizeof(cmdBuffer));
72     // read the current value present in the register, i.e. read-ping
73     if(!readRegBlock(addr, (quadlet_t *)cmdBuffer, 1) ) {
74         debugError("Could not read from addr 0x%012" PRIX64 "\n",  addr);
75     } else {
76         int version = cmdBuffer[0] & 0xFFFF;
77         debugOutput(DEBUG_LEVEL_VERBOSE, "Read Ping response: %08X, Version: %d\n", cmdBuffer[0], version);
78         if((cmdBuffer[0] >> 24 & 0xFF) != HSS1394_CMD_PING_RESPONSE) {
79             debugWarning("Bogus device response to ping! (%08X)\n", cmdBuffer[0]);
80         }
81     }
82
83     // do a write ping
84     memset(cmdBuffer, 0, sizeof(cmdBuffer));
85     cmdBuffer[0] |= HSS1394_CMD_PING << 24;
86
87     // execute the command
88     if(!writeRegBlock(addr, (quadlet_t *)cmdBuffer, 1)) {
89         debugError("Could not write to addr 0x%012" PRIX64 "\n",  addr);
90     } else {
91         debugOutput(DEBUG_LEVEL_VERBOSE, "Write Ping succeeded\n");
92     }
93
94     // get a notifier to handle device notifications
95     nodeaddr_t notify_address;
96     notify_address = get1394Service().findFreeARMBlock(
97                         HSS1394_RESPONSE_ADDRESS,
98                         HSS1394_MAX_PACKET_SIZE+1,
99                         HSS1394_MAX_PACKET_SIZE+1);
100
101     if (notify_address == 0xFFFFFFFFFFFFFFFFLLU) {
102         debugError("Could not find free ARM block for notification\n");
103         return false;
104     }
105
106     m_hss1394handler = new ScsDevice::HSS1394Handler(*this, notify_address);
107
108     if(!m_hss1394handler) {
109         debugError("Could not allocate notifier\n");
110         return false;
111     }
112
113     if (!get1394Service().registerARMHandler(m_hss1394handler)) {
114         debugError("Could not register HSS1394 handler\n");
115         delete m_hss1394handler;
116         m_hss1394handler = NULL;
117         return false;
118     }
119
120     // configure device to use the allocated ARM address for communication
121     // the address change command
122     cmdBuffer[0] = 0;
123     cmdBuffer[0] |= HSS1394_CMD_CHANGE_ADDRESS << 24;
124
125     // the address is the argument
126     cmdBuffer[0] |= (notify_address >> 32) & 0xFFFF;
127     cmdBuffer[1] = notify_address & 0xFFFFFFFF;
128
129     // execute the command
130     if(!writeRegBlock(addr, (quadlet_t *)cmdBuffer, 2)) {
131         debugError("Could not write to addr 0x%012" PRIX64 "\n", addr);
132         return false;
133     }
134
135     // request the device to echo something
136     cmdBuffer[0] = 0;
137     cmdBuffer[0] |= HSS1394_CMD_ECHO_AS_USER_DATA << 24;
138
139     // the address is the argument
140     cmdBuffer[0] |= 0x1234;
141     cmdBuffer[1] = 0x56789ABC;
142
143     // execute the command
144     if(!writeRegBlock(addr, (quadlet_t *)cmdBuffer, 2)) {
145         debugError("Could not write to addr 0x%012" PRIX64 "\n", addr);
146         return false;
147     }
148
149     return true;
150 }
151
152 bool
153 ScsDevice::writeHSS1394Message(enum eMessageType message_type, byte_t* buffer, size_t len) {
154     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,
155                 "Writing message type: %02X, length: %zd bytes\n",
156                 message_type, len);
157     size_t len_quadlets = len/4 + 1;
158
159     fb_nodeaddr_t addr = HSS1394_BASE_ADDRESS;
160
161     unsigned char tmpbuffer[len_quadlets*4];
162     tmpbuffer[0] = message_type;
163     memcpy(tmpbuffer+1, buffer, len);
164 //     memcpy(tmpbuffer, buffer, len);
165
166     quadlet_t *cmdBuffer = (quadlet_t *)tmpbuffer;
167
168     hexDump(tmpbuffer, len_quadlets*4);
169     // we have to cond-byte-swap this because the memory stuff is assumed to be
170     // in big-endian
171     byteSwapFromBus(cmdBuffer, len_quadlets);
172
173     // execute the command
174     if(!writeRegBlock(addr, (quadlet_t *)cmdBuffer, len_quadlets)) {
175         debugError("Could not write to addr 0x%012" PRIX64 "\n", addr);
176         return false;
177     }
178     return true;
179 }
180
181 bool
182 ScsDevice::readRegBlock(fb_nodeaddr_t addr, fb_quadlet_t *data, size_t length_quads, size_t blocksize_quads) {
183     debugOutput(DEBUG_LEVEL_VERBOSE,"Reading register 0x%016" PRIX64 ", length %zd quadlets, to %p\n",
184         addr, length_quads, data);
185
186     fb_nodeid_t nodeId = getNodeId() | 0xFFC0;
187     int quads_done = 0;
188     while(quads_done < (int)length_quads) {
189         fb_nodeaddr_t curr_addr = addr + quads_done*4;
190         fb_quadlet_t *curr_data = data + quads_done;
191         int quads_todo = length_quads - quads_done;
192         if (quads_todo > (int)blocksize_quads) {
193             debugOutput(DEBUG_LEVEL_VERBOSE, "Truncating read from %d to %zd quadlets\n", quads_todo, blocksize_quads);
194             quads_todo = blocksize_quads;
195         }
196         #ifdef DEBUG
197         if (quads_todo < 0) {
198             debugError("BUG: quads_todo < 0: %d\n", quads_todo);
199         }
200         #endif
201
202         debugOutput(DEBUG_LEVEL_VERBOSE, "reading addr: 0x%016" PRIX64 ", %d quads to %p\n", curr_addr, quads_todo, curr_data);
203         if(!get1394Service().read( nodeId, curr_addr, quads_todo, curr_data ) ) {
204             debugError("Could not read %d quadlets from node 0x%04X addr 0x%012" PRIX64 "\n", quads_todo, nodeId, curr_addr);
205             return false;
206         }
207
208         quads_done += quads_todo;
209     }
210     byteSwapFromBus(data, length_quads);
211     return true;
212 }
213
214 bool
215 ScsDevice::writeRegBlock(fb_nodeaddr_t addr, fb_quadlet_t *data, size_t length_quads, size_t blocksize_quads) {
216     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,
217                 "Writing register 0x%016" PRIX64 ", length: %zd quadlets, from %p\n",
218                 addr, length_quads, data);
219
220     fb_quadlet_t data_out[length_quads];
221     memcpy(data_out, data, length_quads*4);
222     byteSwapToBus(data_out, length_quads);
223
224     fb_nodeid_t nodeId = getNodeId() | 0xFFC0;
225     int quads_done = 0;
226     while(quads_done < (int)length_quads) {
227         fb_nodeaddr_t curr_addr = addr + quads_done*4;
228         fb_quadlet_t *curr_data = data_out + quads_done;
229         int quads_todo = length_quads - quads_done;
230         if (quads_todo > (int)blocksize_quads) {
231             debugOutput(DEBUG_LEVEL_VERBOSE, "Truncating write from %d to %zd quadlets\n", quads_todo, blocksize_quads);
232             quads_todo = blocksize_quads;
233         }
234         #ifdef DEBUG
235         if (quads_todo < 0) {
236             debugError("BUG: quads_todo < 0: %d\n", quads_todo);
237         }
238         #endif
239
240         debugOutput(DEBUG_LEVEL_VERBOSE, "writing addr: 0x%016" PRIX64 ", %d quads from %p\n", curr_addr, quads_todo, curr_data);
241         if(!get1394Service().write( nodeId, addr, quads_todo, curr_data ) ) {
242             debugError("Could not write %d quadlets to node 0x%04X addr 0x%012" PRIX64 "\n", quads_todo, nodeId, curr_addr);
243             return false;
244         }
245         quads_done += quads_todo;
246     }
247
248     return true;
249 }
250
251 void
252 ScsDevice::showDevice()
253 {
254     debugOutput(DEBUG_LEVEL_VERBOSE, "This is a GenericAVC::Stanton::ScsDevice\n");
255     GenericAVC::Device::showDevice();
256 }
257
258 // the incoming HSS1394 handler
259
260 ScsDevice::HSS1394Handler::HSS1394Handler(Device &d, nodeaddr_t start)
261  : ARMHandler(d.get1394Service(), start, HSS1394_MAX_PACKET_SIZE+1,
262               RAW1394_ARM_READ | RAW1394_ARM_WRITE | RAW1394_ARM_LOCK,
263               RAW1394_ARM_WRITE, 0)
264  , m_device(d)
265 {
266     // switch over the debug module to that of this device instead of the 1394 service
267     m_debugModule = d.m_debugModule;
268
269 }
270
271 ScsDevice::HSS1394Handler::~HSS1394Handler()
272 {
273 }
274
275 bool
276 ScsDevice::HSS1394Handler::handleRead(struct raw1394_arm_request *arm_req) {
277     debugWarning("Unexpected Read transaction received\n");
278     printRequest(arm_req);
279     return true;
280 }
281
282 bool
283 ScsDevice::HSS1394Handler::handleWrite(struct raw1394_arm_request *arm_req) {
284     debugOutput(DEBUG_LEVEL_VERBOSE, "HSS Write\n");
285     printRequest(arm_req);
286     size_t payload_len = 0;
287     enum eMessageType message_type = eMT_Undefined;
288
289     // extract the data
290     if(arm_req->buffer_length > 1) {
291         message_type = byteToMessageType(arm_req->buffer[0]);
292         payload_len = arm_req->buffer_length - 1;
293     } else {
294         debugWarning("Received empty message\n");
295         return false;
296     }
297
298     // figure out what handler to call
299     switch(message_type) {
300         case eMT_UserData:
301             for ( MessageHandlerVectorIterator it = m_userDataMessageHandlers.begin();
302                 it != m_userDataMessageHandlers.end();
303                 ++it )
304             {
305                 MessageFunctor* func = *it;
306                 debugOutput(DEBUG_LEVEL_VERBOSE, "Calling functor %p\n", func);
307                 ( *func )(arm_req->buffer + 1, payload_len);
308             }
309             break;
310         case eMT_DebugData:
311         case eMT_UserTagBase:
312         case eMT_UserTagTop:
313         case eMT_Reset:
314         case eMT_ChangeAddress:
315         case eMT_Ping:
316         case eMT_PingResponse:
317         case eMT_EchoAsUserData:
318         case eMT_Undefined:
319         default:
320             debugWarning("Unexpected Message of type: %02X\n", message_type);
321     }
322     return true;
323 }
324
325 bool
326 ScsDevice::HSS1394Handler::handleLock(struct raw1394_arm_request *arm_req) {
327     debugWarning("Unexpected Lock transaction received\n");
328     printRequest(arm_req);
329     return true;
330 }
331
332 bool
333 ScsDevice::HSS1394Handler::addMessageHandler(enum eMessageType message_type, MessageFunctor* functor)
334 {
335     debugOutput(DEBUG_LEVEL_VERBOSE, "Adding Message handler (%p) for message type %02X\n", functor, message_type);
336     // figure out what handler to call
337     switch(message_type) {
338         case eMT_UserData:
339             // FIXME: one handler can be added multiple times, is this what we want?
340             m_userDataMessageHandlers.push_back( functor );
341             return true;
342         case eMT_DebugData:
343         case eMT_UserTagBase:
344         case eMT_UserTagTop:
345         case eMT_Reset:
346         case eMT_ChangeAddress:
347         case eMT_Ping:
348         case eMT_PingResponse:
349         case eMT_EchoAsUserData:
350         case eMT_Undefined:
351         default:
352             debugError("Handlers not supported for messages of type: %02X\n", message_type);
353             return false;
354     }
355 }
356
357 bool
358 ScsDevice::HSS1394Handler::removeMessageHandler(enum eMessageType message_type, MessageFunctor* functor)
359 {
360     debugOutput(DEBUG_LEVEL_VERBOSE, "Removing Message handler (%p) for message type %02X\n", functor, message_type);
361     // figure out what handler to call
362     switch(message_type) {
363         case eMT_UserData:
364             // FIXME: one handler can be present multiple times, how do we handle this?
365             for ( MessageHandlerVectorIterator it = m_userDataMessageHandlers.begin();
366                 it != m_userDataMessageHandlers.end();
367                 ++it )
368             {
369                 if ( *it == functor ) {
370                     debugOutput(DEBUG_LEVEL_VERBOSE, " found\n");
371                     m_userDataMessageHandlers.erase( it );
372                     return true;
373                 }
374             }
375             debugOutput(DEBUG_LEVEL_VERBOSE, " not found\n");
376             return false;
377         case eMT_DebugData:
378         case eMT_UserTagBase:
379         case eMT_UserTagTop:
380         case eMT_Reset:
381         case eMT_ChangeAddress:
382         case eMT_Ping:
383         case eMT_PingResponse:
384         case eMT_EchoAsUserData:
385         case eMT_Undefined:
386         default:
387             debugError("Handlers not supported for messages of type: %02X\n", message_type);
388             return false;
389     }
390 }
391
392 enum ScsDevice::eMessageType
393 ScsDevice::HSS1394Handler::byteToMessageType(byte_t tag)
394 {
395     switch(tag) {
396         case HSS1394_CMD_USER_DATA:
397             return eMT_UserData;
398         case HSS1394_CMD_DEBUG_DATA:
399             return eMT_DebugData;
400         case HSS1394_CMD_USER_TAG_BASE:
401             return eMT_UserTagBase;
402         case HSS1394_CMD_USER_TAG_TOP:
403             return eMT_UserTagTop;
404         case HSS1394_CMD_RESET:
405             return eMT_Reset;
406         case HSS1394_CMD_CHANGE_ADDRESS:
407             return eMT_ChangeAddress;
408         case HSS1394_CMD_PING:
409             return eMT_Ping;
410         case HSS1394_CMD_PING_RESPONSE:
411             return eMT_PingResponse;
412         case HSS1394_CMD_ECHO_AS_USER_DATA:
413             return eMT_EchoAsUserData;
414         case HSS1394_CMD_UNDEFINED:
415         default:
416             return eMT_Undefined;
417     }
418 }
419
420 }
421 }
Note: See TracBrowser for help on using the browser.