1 /*****************************************************************************
2 * asi.c: support for Computer Modules ASI cards
3 *****************************************************************************
4 * Copyright (C) 2004, 2009 VideoLAN
5 * $Id: asi.c 9 2007-03-15 16:58:05Z cmassiot $
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
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) any later version.
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.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
30 #include <sys/types.h>
35 #include <sys/ioctl.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
41 #include <bitstream/common.h>
48 * The problem with hardware filtering is that on startup, when you only
49 * set a filter on PID 0, it can take a very long time for a large buffer
50 * (typically ~100 TS packets) to fill up. And the buffer size cannot be
51 * adjusted afer startup. --Meuuh
53 #undef USE_HARDWARE_FILTERING
55 /*****************************************************************************
57 *****************************************************************************/
58 #define ASI_DEVICE "/dev/asirx%u"
59 #define ASI_TIMESTAMPS_FILE "/sys/class/asi/asirx%u/timestamps"
60 #define ASI_BUFSIZE_FILE "/sys/class/asi/asirx%u/bufsize"
61 #define ASI_LOCK_TIMEOUT 5000000 /* 5 s */
65 static uint8_t p_pid_filter
[8192 / 8];
66 static mtime_t i_last_packet
= 0;
68 /*****************************************************************************
70 *****************************************************************************/
73 static int ReadULSysfs( const char *psz_fmt
, unsigned int i_link
)
75 char psz_file
[MAXLEN
], psz_data
[MAXLEN
];
81 snprintf( psz_file
, sizeof(psz_file
), psz_fmt
, i_link
);
82 psz_file
[sizeof(psz_file
) - 1] = '\0';
84 if ( (i_fd
= open( psz_file
, O_RDONLY
)) < 0 )
87 i_ret
= read( i_fd
, psz_data
, sizeof(psz_data
) );
93 i_data
= strtoul( psz_data
, &psz_tmp
, 0 );
94 if ( *psz_tmp
!= '\n' )
100 static ssize_t
WriteULSysfs( const char *psz_fmt
, unsigned int i_link
,
103 char psz_file
[MAXLEN
], psz_data
[MAXLEN
];
107 snprintf( psz_file
, sizeof(psz_file
), psz_fmt
, i_link
);
108 psz_file
[sizeof(psz_file
) - 1] = '\0';
110 snprintf( psz_data
, sizeof(psz_data
), "%u\n", i_buf
);
111 psz_file
[sizeof(psz_data
) - 1] = '\0';
113 if ( (i_fd
= open( psz_file
, O_WRONLY
)) < 0 )
116 i_ret
= write( i_fd
, psz_data
, strlen(psz_data
) + 1 );
121 /*****************************************************************************
123 *****************************************************************************/
124 void asi_Open( void )
126 char psz_dev
[MAXLEN
];
128 /* No timestamp - we wouldn't know what to do with them */
129 if ( WriteULSysfs( ASI_TIMESTAMPS_FILE
, i_asi_adapter
, 0 ) < 0 )
131 msg_Err( NULL
, "couldn't write file " ASI_TIMESTAMPS_FILE
,
136 if ( (i_bufsize
= ReadULSysfs( ASI_BUFSIZE_FILE
, i_asi_adapter
)) < 0 )
138 msg_Err( NULL
, "couldn't read file " ASI_BUFSIZE_FILE
, i_asi_adapter
);
142 if ( i_bufsize
% TS_SIZE
)
144 msg_Err( NULL
, ASI_BUFSIZE_FILE
" must be a multiple of 188",
149 snprintf( psz_dev
, sizeof(psz_dev
), ASI_DEVICE
, i_asi_adapter
);
150 psz_dev
[sizeof(psz_dev
) - 1] = '\0';
151 if ( (i_handle
= open( psz_dev
, O_RDONLY
, 0 )) < 0 )
153 msg_Err( NULL
, "couldn't open device " ASI_DEVICE
" (%s)",
154 i_asi_adapter
, strerror(errno
) );
158 #ifdef USE_HARDWARE_FILTERING
159 memset( p_pid_filter
, 0x0, sizeof(p_pid_filter
) );
161 memset( p_pid_filter
, 0xff, sizeof(p_pid_filter
) );
162 p_pid_filter
[8191 / 8] &= ~(0x01 << (8191 % 8)); /* padding */
164 if ( ioctl( i_handle
, ASI_IOC_RXSETPF
, p_pid_filter
) < 0 )
166 msg_Warn( NULL
, "couldn't filter padding" );
172 /*****************************************************************************
173 * asi_Read : read packets from the device
174 *****************************************************************************/
175 block_t
*asi_Read( mtime_t i_poll_timeout
)
181 pfd
.events
= POLLIN
| POLLPRI
;
183 i_ret
= poll( &pfd
, 1, (i_poll_timeout
+ 999) / 1000 );
185 i_wallclock
= mdate();
190 msg_Err( NULL
, "couldn't poll from device " ASI_DEVICE
" (%s)",
191 i_asi_adapter
, strerror(errno
) );
195 if ( (pfd
.revents
& POLLPRI
) )
199 if ( ioctl(i_handle
, ASI_IOC_RXGETEVENTS
, &i_val
) < 0 )
200 msg_Err( NULL
, "couldn't RXGETEVENTS (%s)", strerror(errno
) );
203 if ( i_val
& ASI_EVENT_RX_BUFFER
)
204 msg_Warn( NULL
, "driver receive buffer queue overrun" );
205 if ( i_val
& ASI_EVENT_RX_FIFO
)
206 msg_Warn( NULL
, "onboard receive FIFO overrun" );
207 if ( i_val
& ASI_EVENT_RX_CARRIER
)
208 msg_Warn( NULL
, "carrier status change" );
209 if ( i_val
& ASI_EVENT_RX_LOS
)
210 msg_Warn( NULL
, "loss of packet synchronization" );
211 if ( i_val
& ASI_EVENT_RX_AOS
)
212 msg_Warn( NULL
, "acquisition of packet synchronization" );
213 if ( i_val
& ASI_EVENT_RX_DATA
)
214 msg_Warn( NULL
, "receive data status change" );
218 if ( (pfd
.revents
& POLLIN
) )
220 struct iovec p_iov
[i_bufsize
/ TS_SIZE
];
221 block_t
*p_ts
, **pp_current
= &p_ts
;
224 if ( !i_last_packet
)
226 switch (i_print_type
) {
228 printf("<STATUS type=\"lock\" status=\"1\"/>\n");
231 printf("frontend has acquired lock\n" );
234 i_last_packet
= i_wallclock
;
236 for ( i
= 0; i
< i_bufsize
/ TS_SIZE
; i
++ )
238 *pp_current
= block_New();
239 p_iov
[i
].iov_base
= (*pp_current
)->p_ts
;
240 p_iov
[i
].iov_len
= TS_SIZE
;
241 pp_current
= &(*pp_current
)->p_next
;
244 if ( (i_len
= readv(i_handle
, p_iov
, i_bufsize
/ TS_SIZE
)) < 0 )
246 msg_Err( NULL
, "couldn't read from device " ASI_DEVICE
" (%s)",
247 i_asi_adapter
, strerror(errno
) );
253 while ( i_len
&& *pp_current
)
255 pp_current
= &(*pp_current
)->p_next
;
260 msg_Dbg( NULL
, "partial buffer received" );
261 block_DeleteChain( *pp_current
);
266 else if ( i_last_packet
&& i_last_packet
+ ASI_LOCK_TIMEOUT
< i_wallclock
)
268 switch (i_print_type
) {
270 printf("<STATUS type=\"lock\" status=\"0\"/>\n");
273 printf("frontend has lost lock\n" );
281 /*****************************************************************************
283 *****************************************************************************/
284 int asi_SetFilter( uint16_t i_pid
)
286 #ifdef USE_HARDWARE_FILTERING
287 p_pid_filter
[ i_pid
/ 8 ] |= (0x01 << (i_pid
% 8));
288 if ( ioctl( i_handle
, ASI_IOC_RXSETPF
, p_pid_filter
) < 0 )
289 msg_Warn( NULL
, "couldn't add filter on PID %u", i_pid
);
297 /*****************************************************************************
298 * asi_UnsetFilter: normally never called
299 *****************************************************************************/
300 void asi_UnsetFilter( int i_fd
, uint16_t i_pid
)
302 #ifdef USE_HARDWARE_FILTERING
303 p_pid_filter
[ i_pid
/ 8 ] &= ~(0x01 << (i_pid
% 8));
304 if ( ioctl( i_handle
, ASI_IOC_RXSETPF
, p_pid_filter
) < 0 )
305 msg_Warn( NULL
, "couldn't remove filter on PID %u", i_pid
);
309 /*****************************************************************************
311 *****************************************************************************/
312 void asi_Reset( void )
314 msg_Warn( NULL
, "asi_Reset() do nothing" );