* dvbiscovery.sh: NIT can take longer than 15s. * dvbiscovery_dvb-s.conf: Change...
[dvblast.git] / asi.c
blob5c19305eed2254173cea27b05bfad6857a3dde41
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <stdbool.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <sys/uio.h>
34 #include <sys/poll.h>
35 #include <sys/ioctl.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <errno.h>
41 #include <bitstream/common.h>
43 #include "asi.h"
45 #include "dvblast.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 /*****************************************************************************
56 * Local declarations
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 */
63 static int i_handle;
64 static int i_bufsize;
65 static uint8_t p_pid_filter[8192 / 8];
66 static mtime_t i_last_packet = 0;
68 /*****************************************************************************
69 * Local helpers
70 *****************************************************************************/
71 #define MAXLEN 256
73 static int ReadULSysfs( const char *psz_fmt, unsigned int i_link )
75 char psz_file[MAXLEN], psz_data[MAXLEN];
76 char *psz_tmp;
77 int i_fd;
78 ssize_t i_ret;
79 unsigned int i_data;
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 )
85 return i_fd;
87 i_ret = read( i_fd, psz_data, sizeof(psz_data) );
88 close( i_fd );
90 if ( i_ret < 0 )
91 return i_ret;
93 i_data = strtoul( psz_data, &psz_tmp, 0 );
94 if ( *psz_tmp != '\n' )
95 return -1;
97 return i_data;
100 static ssize_t WriteULSysfs( const char *psz_fmt, unsigned int i_link,
101 unsigned int i_buf )
103 char psz_file[MAXLEN], psz_data[MAXLEN];
104 int i_fd;
105 ssize_t i_ret;
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 )
114 return i_fd;
116 i_ret = write( i_fd, psz_data, strlen(psz_data) + 1 );
117 close( i_fd );
118 return i_ret;
121 /*****************************************************************************
122 * asi_Open
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,
132 i_asi_adapter );
133 exit(EXIT_FAILURE);
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 );
139 exit(EXIT_FAILURE);
142 if ( i_bufsize % TS_SIZE )
144 msg_Err( NULL, ASI_BUFSIZE_FILE " must be a multiple of 188",
145 i_asi_adapter );
146 exit(EXIT_FAILURE);
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) );
155 exit(EXIT_FAILURE);
158 #ifdef USE_HARDWARE_FILTERING
159 memset( p_pid_filter, 0x0, sizeof(p_pid_filter) );
160 #else
161 memset( p_pid_filter, 0xff, sizeof(p_pid_filter) );
162 p_pid_filter[8191 / 8] &= ~(0x01 << (8191 % 8)); /* padding */
163 #endif
164 if ( ioctl( i_handle, ASI_IOC_RXSETPF, p_pid_filter ) < 0 )
166 msg_Warn( NULL, "couldn't filter padding" );
169 fsync( i_handle );
172 /*****************************************************************************
173 * asi_Read : read packets from the device
174 *****************************************************************************/
175 block_t *asi_Read( mtime_t i_poll_timeout )
177 struct pollfd pfd;
178 int i_ret;
180 pfd.fd = i_handle;
181 pfd.events = POLLIN | POLLPRI;
183 i_ret = poll( &pfd, 1, (i_poll_timeout + 999) / 1000 );
185 i_wallclock = mdate();
187 if ( i_ret < 0 )
189 if( errno != EINTR )
190 msg_Err( NULL, "couldn't poll from device " ASI_DEVICE " (%s)",
191 i_asi_adapter, strerror(errno) );
192 return NULL;
195 if ( (pfd.revents & POLLPRI) )
197 unsigned int i_val;
199 if ( ioctl(i_handle, ASI_IOC_RXGETEVENTS, &i_val) < 0 )
200 msg_Err( NULL, "couldn't RXGETEVENTS (%s)", strerror(errno) );
201 else
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;
222 int i, i_len;
224 if ( !i_last_packet )
226 switch (i_print_type) {
227 case PRINT_XML:
228 printf("<STATUS type=\"lock\" status=\"1\"/>\n");
229 break;
230 default:
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) );
248 i_len = 0;
250 i_len /= TS_SIZE;
252 pp_current = &p_ts;
253 while ( i_len && *pp_current )
255 pp_current = &(*pp_current)->p_next;
256 i_len--;
259 if ( *pp_current )
260 msg_Dbg( NULL, "partial buffer received" );
261 block_DeleteChain( *pp_current );
262 *pp_current = NULL;
264 return p_ts;
266 else if ( i_last_packet && i_last_packet + ASI_LOCK_TIMEOUT < i_wallclock )
268 switch (i_print_type) {
269 case PRINT_XML:
270 printf("<STATUS type=\"lock\" status=\"0\"/>\n");
271 break;
272 default:
273 printf("frontend has lost lock\n" );
275 i_last_packet = 0;
278 return NULL;
281 /*****************************************************************************
282 * asi_SetFilter
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 );
291 return 1;
292 #else
293 return -1;
294 #endif
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 );
306 #endif
309 /*****************************************************************************
310 * asi_Reset
311 *****************************************************************************/
312 void asi_Reset( void )
314 msg_Warn( NULL, "asi_Reset() do nothing" );