root/trunk/libffado/src/libieee1394/ieee1394service.h

Revision 1660, 17.0 kB (checked in by jwoithe, 15 years ago)

ieee1394Service: new method allocateFixedIsoChannelGeneric() to allocate a specific channel number instead of scanning for the next available channel number. This functionality is needed for the RME devices.
RME: assign/detect iso channels to use and allocate required bandwidth.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Copyright (C) 2005-2008 by Daniel Wagner
3  * Copyright (C) 2005-2008 by Pieter Palmers
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 2 of the License, or
13  * (at your option) version 3 of the License.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #ifndef FFADO_IEEE1394SERVICE_H
26 #define FFADO_IEEE1394SERVICE_H
27
28 #include "fbtypes.h"
29 #include "libutil/Functors.h"
30 #include "libutil/Mutex.h"
31 #include "libutil/Thread.h"
32
33 #include "debugmodule/debugmodule.h"
34
35 #include "IEC61883.h"
36
37 #include <libraw1394/raw1394.h>
38 #include <pthread.h>
39
40 #include <vector>
41 #include <string>
42 #include <stdint.h>
43
44
45 #define MAX_FCP_BLOCK_SIZE_BYTES (512)
46 #define MAX_FCP_BLOCK_SIZE_QUADS (MAX_FCP_BLOCK_SIZE_BYTES / 4)
47
48 class IsoHandlerManager;
49 class CycleTimerHelper;
50
51 namespace Util {
52     class Watchdog;
53     class Configuration;
54 }
55
56 class Ieee1394Service : public IEC61883 {
57 public:
58     class ARMHandler;
59
60 public:
61     Ieee1394Service();
62     Ieee1394Service(bool rt, int prio);
63     ~Ieee1394Service();
64
65     bool initialize( int port );
66     bool setThreadParameters(bool rt, int priority);
67     Util::Watchdog *getWatchdog() {return m_pWatchdog;};
68
69    /**
70     * @brief get number of ports (firewire adapters) in this machine
71     *
72     * @return the number of ports
73     */
74     static int detectNbPorts();
75
76    /**
77     * @brief get port (adapter) id
78     *
79     * @return get port (adapter) id
80     */
81     int getPort()
82         { return m_port; }
83
84    /**
85     * @brief get port (adapter) name
86     *
87     * @return get port (adapter) name
88     */
89     std::string getPortName()
90         { return m_portName; };
91
92    /**
93     * @brief get number of nodes on the bus
94     *
95     * Since the root node always has
96     * the highest node ID, this number can be used to determine that ID (it's
97     * LOCAL_BUS|(count-1)).
98     *
99     * @return the number of nodes on the bus to which the port is connected.
100     * This value can change with every bus reset.
101     */
102     int getNodeCount();
103
104    /**
105     * @brief get the node id of the local node
106     *
107     * @note does not include the bus part (0xFFC0)
108     *
109     * @return the node id of the local node
110     * This value can change with every bus reset.
111     */
112     nodeid_t getLocalNodeId();
113
114     /**
115      * @brief get the most recent cycle timer value (in ticks)
116      *
117      * @note Uses the most appropriate method for getting the cycle timer
118      *       which is not necessarily a direct read (could be DLL)
119      */
120     uint32_t getCycleTimerTicks();
121
122     /**
123      * @brief get the most recent cycle timer value (in CTR format)
124      *
125      * @note Uses the most appropriate method for getting the cycle timer
126      *       which is not necessarily a direct read (could be DLL)
127      */
128     uint32_t getCycleTimer();
129
130     /**
131      * @brief get the cycle timer value for a specific time instant (in ticks)
132      *
133      * @note Uses the most appropriate method for getting the cycle timer
134      *       which is not necessarily a direct read (could be DLL)
135      */
136     uint32_t getCycleTimerTicks(uint64_t t);
137
138     /**
139      * @brief get the cycle timer value for a specific time instant (in CTR format)
140      *
141      * @note Uses the most appropriate method for getting the cycle timer
142      *       which is not necessarily a direct read (could be DLL)
143      */
144     uint32_t getCycleTimer(uint64_t t);
145
146     /**
147      * @brief get the system time for a specific cycle timer value (in ticks)
148      * @note thread safe
149      */
150     uint64_t getSystemTimeForCycleTimerTicks(uint32_t ticks);
151
152     /**
153      * @brief get the system time for a specific cycle timer value (in CTR format)
154      * @note thread safe
155      */
156     uint64_t getSystemTimeForCycleTimer(uint32_t ctr);
157
158     /**
159      * @brief read the cycle timer value from the controller (in CTR format)
160      *
161      * @note Uses a direct method to read the value from the controller
162      * @return true if successful
163      */
164     bool readCycleTimerReg(uint32_t *cycle_timer, uint64_t *local_time);
165
166     /**
167      * @brief provide the current system time
168      * @return
169      */
170     uint64_t getCurrentTimeAsUsecs();
171
172     /**
173      * @brief send async read request to a node and wait for response.
174      *
175      * This does the complete transaction and will return when it's finished.
176      *
177      * @param node target node (\todo needs 0xffc0 stuff)
178      * @param addr address to read from
179      * @param length amount of data to read in quadlets
180      * @param buffer pointer to buffer where data will be saved
181      *
182      * @return true on success or false on failure (sets errno)
183      */
184     bool read( fb_nodeid_t nodeId,
185            fb_nodeaddr_t addr,
186            size_t length,
187            fb_quadlet_t* buffer );
188
189     bool read_quadlet( fb_nodeid_t nodeId,
190                        fb_nodeaddr_t addr,
191                        fb_quadlet_t* buffer );
192
193     bool read_octlet( fb_nodeid_t nodeId,
194                       fb_nodeaddr_t addr,
195                       fb_octlet_t* buffer );
196
197     /**
198     * @brief send async write request to a node and wait for response.
199     *
200     * This does the complete transaction and will return when it's finished.
201     *
202     * @param node target node (\XXX needs 0xffc0 stuff)
203     * @param addr address to write to
204     * @param length amount of data to write in quadlets
205     * @param data pointer to data to be sent
206     *
207     * @return true on success or false on failure (sets errno)
208     */
209     bool write( fb_nodeid_t nodeId,
210         fb_nodeaddr_t addr,
211         size_t length,
212         fb_quadlet_t* data );
213
214     bool write_quadlet( fb_nodeid_t nodeId,
215                         fb_nodeaddr_t addr,
216                         fb_quadlet_t data );
217
218     bool write_octlet(  fb_nodeid_t nodeId,
219                         fb_nodeaddr_t addr,
220                         fb_octlet_t data );
221
222     /**
223      * @brief send 64-bit compare-swap lock request and wait for response.
224      *
225      * swaps the content of \ref addr with \ref swap_value , but only if
226      * the content of \ref addr equals \ref compare_with
227      *
228      * @note takes care of endiannes
229      *
230      * @param nodeId target node ID
231      * @param addr address within target node address space
232      * @param compare_with value to compare \ref addr with
233      * @param swap_value new value to put in \ref addr
234      * @param result the value (originally) in \ref addr
235      *
236      * @return true if succesful, false otherwise
237      */
238     bool lockCompareSwap64( fb_nodeid_t nodeId,
239                             fb_nodeaddr_t addr,
240                             fb_octlet_t  compare_value,
241                             fb_octlet_t  swap_value,
242                             fb_octlet_t* result );
243
244     /**
245      * initiate AV/C transaction
246      * @param nodeId
247      * @param buf
248      * @param len
249      * @param resp_len
250      * @return
251      */
252     fb_quadlet_t* transactionBlock( fb_nodeid_t nodeId,
253                                     fb_quadlet_t* buf,
254                                     int len,
255                                     unsigned int* resp_len );
256
257     /**
258      * close AV/C transaction.
259      * @param nodeId
260      * @param buf
261      * @param len
262      * @param resp_len
263      * @return
264      */
265     bool transactionBlockClose();
266
267     int getVerboseLevel();
268
269     bool addBusResetHandler( Util::Functor* functor );
270     bool remBusResetHandler( Util::Functor* functor );
271
272     void doBusReset();
273     bool waitForBusResetStormToEnd( int nb_tries, int sleep_time_ms );
274
275     /**
276      * @brief register an AddressRangeMapping Handler
277      * @param h pointer to the handler to register
278      *
279      * @return true on success or false on failure
280      **/
281
282     bool registerARMHandler( ARMHandler *h );
283
284     /**
285      * @brief unregister ARM range
286      * @param h pointer to the handler to unregister
287      * @return true if successful, false otherwise
288      */
289     bool unregisterARMHandler( ARMHandler *h );
290
291     nodeaddr_t findFreeARMBlock( nodeaddr_t start, size_t length, size_t step );
292
293     /**
294      * @brief get the current generation
295      *
296      * @return the current generation
297      **/
298     unsigned int getGeneration() {
299         Util::MutexLockHelper lock(*m_handle_lock);
300         return raw1394_get_generation( m_handle );
301     }
302
303     /**
304      * @brief update the current generation
305      *
306      * @return the current generation
307      **/
308     void updateGeneration() {
309         Util::MutexLockHelper lock(*m_handle_lock);
310         raw1394_update_generation( m_handle, getGeneration());
311     }
312
313     /**
314      * @brief sets the SPLIT_TIMEOUT_HI and SPLIT_TIMEOUT_LO CSR registers
315      *
316      * sets the SPLIT_TIMEOUT_HI and SPLIT_TIMEOUT_LO CSR registers on node
317      * nodeId such that the timeout is equal to timeout
318      *
319      * @param nodeId node to set CSR registers on
320      * @param timeout timeout in usecs
321      * @return true if successful
322      */
323     bool setSplitTimeoutUsecs(fb_nodeid_t nodeId, unsigned int timeout);
324
325     /**
326      * @brief gets the SPLIT_TIMEOUT_X timeout value
327      *
328      * gets the SPLIT_TIMEOUT_HI and SPLIT_TIMEOUT_LO CSR registers on node
329      * nodeId and recombine them into one usec value
330      *
331      * @param nodeId node to get CSR registers from
332      * @return timeout in usecs if successful, 0 else
333      */
334     int getSplitTimeoutUsecs(fb_nodeid_t nodeId);
335
336     /**
337      * @brief use the provided configuration for this service
338      *
339      * only update the config once, before init. not thread safe,
340      * and no effect when things are already running.
341      *
342      * @param c configuration to use
343      * @return bool if this config is ok.
344      */
345     bool useConfiguration(Util::Configuration *c);
346
347     Util::Configuration *getConfiguration() {return m_configuration;};
348
349     /**
350      * @brief enable or disable FCP response doublicate filtering
351      *
352      * this is use only for devices (e.g. edirol fa101) which have a
353      * buggy FCP implementation and send more then one FCP response
354      * for one request.
355      */
356     void setFCPResponseFiltering(bool enable);
357
358 // ISO channel stuff
359 public:
360     signed int getAvailableBandwidth();
361     signed int allocateIsoChannelGeneric(unsigned int bandwidth);
362     signed int allocateFixedIsoChannelGeneric(
363         unsigned int chan, unsigned int bandwidth);
364     signed int allocateIsoChannelCMP(nodeid_t xmit_node, int xmit_plug,
365                                      nodeid_t recv_node, int recv_plug);
366     bool freeIsoChannel(signed int channel);
367
368     IsoHandlerManager& getIsoHandlerManager() {return *m_pIsoManager;};
369 private:
370     enum EAllocType {
371         AllocFree = 0, // not allocated (by us)
372         AllocGeneric = 1, // allocated with generic functions
373         AllocCMP=2 // allocated with CMP
374     };
375
376     struct ChannelInfo {
377         int channel;
378         int bandwidth;
379         enum EAllocType alloctype;
380         nodeid_t xmit_node;
381         int xmit_plug;
382         nodeid_t recv_node;
383         int recv_plug;
384     };
385
386     // the info for the channels we manage
387     struct ChannelInfo m_channels[64];
388
389     bool unregisterIsoChannel(unsigned int c);
390     bool registerIsoChannel(unsigned int c, struct ChannelInfo cinfo);
391
392 public:
393 // FIXME: should be private, but is used to do the PCR control in GenericAVC::AvDevice
394     raw1394handle_t getHandle() {return m_handle;};
395
396 protected:
397     Util::Configuration     *m_configuration;
398
399 private:
400     // this class will create a new 1394 handle
401     // and a thread that will iterate it
402     class HelperThread : public Util::RunnableInterface
403     {
404     public:
405         HelperThread(Ieee1394Service &, std::string);
406         HelperThread(Ieee1394Service &, std::string, bool rt, int prio);
407         virtual ~HelperThread();
408
409         raw1394handle_t get1394Handle() {return m_handle;};
410         Ieee1394Service &get1394Service() {return m_parent;};
411
412         virtual bool Init();
413         virtual bool Execute();
414
415         void setThreadParameters(bool rt, int priority);
416
417         bool Start();
418         bool Stop();
419
420     private:
421         Ieee1394Service &m_parent;
422         std::string      m_name;
423         raw1394handle_t  m_handle;
424         Util::Thread &   m_thread;
425         bool             m_iterate;
426
427         DECLARE_DEBUG_MODULE_REFERENCE;
428     };
429
430     HelperThread *m_resetHelper;
431     HelperThread *m_armHelperNormal;
432     HelperThread *m_armHelperRealtime;
433
434 private: // unsorted
435     bool configurationUpdated();
436
437     void printBuffer( unsigned int level, size_t length, fb_quadlet_t* buffer ) const;
438     void printBufferBytes( unsigned int level, size_t length, byte_t* buffer ) const;
439
440     static int resetHandlerLowLevel( raw1394handle_t handle,
441                                      unsigned int generation );
442     bool resetHandler( unsigned int generation );
443
444     static int armHandlerLowLevel(raw1394handle_t handle, unsigned long arm_tag,
445                      byte_t request_type, unsigned int requested_length,
446                      void *data);
447     bool armHandler( unsigned long arm_tag,
448                      byte_t request_type, unsigned int requested_length,
449                      void *data);
450
451     raw1394handle_t m_handle;
452     Util::Mutex*    m_handle_lock;
453     raw1394handle_t m_util_handle;
454     int             m_port;
455     std::string     m_portName;
456
457     bool            m_realtime;
458     int             m_base_priority;
459
460     IsoHandlerManager*      m_pIsoManager;
461     CycleTimerHelper*       m_pCTRHelper;
462     bool                    m_have_new_ctr_read;
463
464     bool            m_filterFCPResponse;
465
466     // the RT watchdog
467     Util::Watchdog*     m_pWatchdog;
468
469     typedef std::vector< Util::Functor* > reset_handler_vec_t;
470     reset_handler_vec_t m_busResetHandlers;
471
472     // ARM stuff
473     arm_tag_handler_t m_default_arm_handler;
474
475     typedef std::vector< ARMHandler * > arm_handler_vec_t;
476     arm_handler_vec_t m_armHandlers;
477
478     // unprotected variants
479     bool writeNoLock( fb_nodeid_t nodeId,
480         fb_nodeaddr_t addr,
481         size_t length,
482         fb_quadlet_t* data );
483     bool readNoLock( fb_nodeid_t nodeId,
484            fb_nodeaddr_t addr,
485            size_t length,
486            fb_quadlet_t* buffer );
487
488     // FCP transaction support
489     static int _avc_fcp_handler(raw1394handle_t handle, nodeid_t nodeid,
490                                 int response, size_t length,
491                                 unsigned char *data);
492     int handleFcpResponse(nodeid_t nodeid,
493                           int response, size_t length,
494                           unsigned char *data);
495
496     enum eFcpStatus {
497         eFS_Empty,
498         eFS_Waiting,
499         eFS_Responded,
500         eFS_Error,
501     };
502
503     struct sFcpBlock {
504         enum eFcpStatus status;
505         nodeid_t target_nodeid;
506         unsigned int request_length;
507         quadlet_t request[MAX_FCP_BLOCK_SIZE_QUADS];
508         unsigned int response_length;
509         quadlet_t response[MAX_FCP_BLOCK_SIZE_QUADS];
510     };
511     struct sFcpBlock m_fcp_block;
512
513     bool doFcpTransaction();
514     bool doFcpTransactionTry();
515
516 public:
517     void setVerboseLevel(int l);
518     void show();
519 private:
520     DECLARE_DEBUG_MODULE;
521    
522 public:
523     /**
524     * @brief Class to handle AddressRangeMappings
525     *
526     * This class is intended to help with implementing
527     * address range mapping, i.e. implementing handlers
528     * that react to reads/writes of certain addresses
529     * in 1394 memory space
530     *
531     * see the _arm_ functions in raw1394.h for more insight
532     *
533     */
534
535     class ARMHandler {
536     public:
537         ARMHandler(Ieee1394Service &parent,
538                 nodeaddr_t start, size_t length,
539                 unsigned int access_rights,
540                 unsigned int notification_options,
541                 unsigned int client_transactions
542                 );
543    
544         virtual ~ARMHandler();
545    
546         virtual bool handleRead(struct raw1394_arm_request  *);
547         virtual bool handleWrite(struct raw1394_arm_request  *);
548         virtual bool handleLock(struct raw1394_arm_request  *);
549    
550         struct raw1394_arm_response *getResponse() {return &m_response;};
551    
552         nodeaddr_t getStart() {return m_start;};
553         size_t getLength() {return m_length;};
554         unsigned int getAccessRights() {return m_access_rights;};
555         unsigned int getNotificationOptions() {return m_notification_options;};
556         unsigned int getClientTransactions() {return m_client_transactions;};
557    
558         byte_t *getBuffer() {return m_buffer;};
559    
560     private:
561         Ieee1394Service &m_parent;
562         nodeaddr_t m_start;
563         size_t m_length;
564         unsigned int m_access_rights;
565         unsigned int m_notification_options;
566         unsigned int m_client_transactions;
567     protected:
568         byte_t *m_buffer;
569    
570         struct raw1394_arm_response m_response;
571        
572         void printBufferBytes( unsigned int level, size_t length, byte_t* buffer ) const;
573         void printRequest(struct raw1394_arm_request *arm_req);
574
575         DECLARE_DEBUG_MODULE_REFERENCE;
576    
577     };
578
579 };
580
581 #endif // FFADO_IEEE1394SERVICE_H
Note: See TracBrowser for help on using the browser.