| 1172 | |
---|
| 1173 | |
---|
| 1174 | // ISOHANDLER |
---|
| 1175 | |
---|
| 1176 | /* the C callbacks */ |
---|
| 1177 | enum raw1394_iso_disposition |
---|
| 1178 | IsoHandlerManager::IsoHandler::iso_transmit_handler(raw1394handle_t handle, |
---|
| 1179 | unsigned char *data, unsigned int *length, |
---|
| 1180 | unsigned char *tag, unsigned char *sy, |
---|
| 1181 | int cycle, unsigned int dropped1) { |
---|
| 1182 | |
---|
| 1183 | IsoHandler *xmitHandler = static_cast<IsoHandler *>(raw1394_get_userdata(handle)); |
---|
| 1184 | assert(xmitHandler); |
---|
| 1185 | unsigned int skipped = (dropped1 & 0xFFFF0000) >> 16; |
---|
| 1186 | unsigned int dropped = dropped1 & 0xFFFF; |
---|
| 1187 | return xmitHandler->getPacket(data, length, tag, sy, cycle, dropped, skipped); |
---|
| 1188 | } |
---|
| 1189 | |
---|
| 1190 | enum raw1394_iso_disposition |
---|
| 1191 | IsoHandlerManager::IsoHandler::iso_receive_handler(raw1394handle_t handle, unsigned char *data, |
---|
| 1192 | unsigned int length, unsigned char channel, |
---|
| 1193 | unsigned char tag, unsigned char sy, unsigned int cycle, |
---|
| 1194 | unsigned int dropped) { |
---|
| 1195 | |
---|
| 1196 | IsoHandler *recvHandler = static_cast<IsoHandler *>(raw1394_get_userdata(handle)); |
---|
| 1197 | assert(recvHandler); |
---|
| 1198 | |
---|
| 1199 | return recvHandler->putPacket(data, length, channel, tag, sy, cycle, dropped); |
---|
| 1200 | } |
---|
| 1201 | |
---|
| 1202 | IsoHandlerManager::IsoHandler::IsoHandler(IsoHandlerManager& manager, enum EHandlerType t) |
---|
| 1203 | : m_manager( manager ) |
---|
| 1204 | , m_type ( t ) |
---|
| 1205 | , m_handle( NULL ) |
---|
| 1206 | , m_buf_packets( 400 ) |
---|
| 1207 | , m_max_packet_size( 1024 ) |
---|
| 1208 | , m_irq_interval( -1 ) |
---|
| 1209 | , m_last_cycle( -1 ) |
---|
| 1210 | , m_last_now( 0xFFFFFFFF ) |
---|
| 1211 | , m_last_packet_handled_at( 0xFFFFFFFF ) |
---|
| 1212 | , m_receive_mode ( RAW1394_DMA_PACKET_PER_BUFFER ) |
---|
| 1213 | , m_Client( 0 ) |
---|
| 1214 | , m_speed( RAW1394_ISO_SPEED_400 ) |
---|
| 1215 | , m_State( eHS_Stopped ) |
---|
| 1216 | , m_NextState( eHS_Stopped ) |
---|
| 1217 | , m_switch_on_cycle(0) |
---|
| 1218 | #ifdef DEBUG |
---|
| 1219 | , m_packets ( 0 ) |
---|
| 1220 | , m_dropped( 0 ) |
---|
| 1221 | , m_skipped( 0 ) |
---|
| 1222 | , m_min_ahead( 7999 ) |
---|
| 1223 | #endif |
---|
| 1224 | { |
---|
| 1225 | } |
---|
| 1226 | |
---|
| 1227 | IsoHandlerManager::IsoHandler::IsoHandler(IsoHandlerManager& manager, enum EHandlerType t, |
---|
| 1228 | unsigned int buf_packets, unsigned int max_packet_size, int irq) |
---|
| 1229 | : m_manager( manager ) |
---|
| 1230 | , m_type ( t ) |
---|
| 1231 | , m_handle( NULL ) |
---|
| 1232 | , m_buf_packets( buf_packets ) |
---|
| 1233 | , m_max_packet_size( max_packet_size ) |
---|
| 1234 | , m_irq_interval( irq ) |
---|
| 1235 | , m_last_cycle( -1 ) |
---|
| 1236 | , m_last_now( 0xFFFFFFFF ) |
---|
| 1237 | , m_last_packet_handled_at( 0xFFFFFFFF ) |
---|
| 1238 | , m_receive_mode ( RAW1394_DMA_PACKET_PER_BUFFER ) |
---|
| 1239 | , m_Client( 0 ) |
---|
| 1240 | , m_speed( RAW1394_ISO_SPEED_400 ) |
---|
| 1241 | , m_State( eHS_Stopped ) |
---|
| 1242 | , m_NextState( eHS_Stopped ) |
---|
| 1243 | , m_switch_on_cycle(0) |
---|
| 1244 | #ifdef DEBUG |
---|
| 1245 | , m_packets ( 0 ) |
---|
| 1246 | , m_dropped( 0 ) |
---|
| 1247 | , m_skipped( 0 ) |
---|
| 1248 | , m_min_ahead( 7999 ) |
---|
| 1249 | #endif |
---|
| 1250 | { |
---|
| 1251 | } |
---|
| 1252 | |
---|
| 1253 | IsoHandlerManager::IsoHandler::IsoHandler(IsoHandlerManager& manager, enum EHandlerType t, unsigned int buf_packets, |
---|
| 1254 | unsigned int max_packet_size, int irq, |
---|
| 1255 | enum raw1394_iso_speed speed) |
---|
| 1256 | : m_manager( manager ) |
---|
| 1257 | , m_type ( t ) |
---|
| 1258 | , m_handle( NULL ) |
---|
| 1259 | , m_buf_packets( buf_packets ) |
---|
| 1260 | , m_max_packet_size( max_packet_size ) |
---|
| 1261 | , m_irq_interval( irq ) |
---|
| 1262 | , m_last_cycle( -1 ) |
---|
| 1263 | , m_last_now( 0xFFFFFFFF ) |
---|
| 1264 | , m_last_packet_handled_at( 0xFFFFFFFF ) |
---|
| 1265 | , m_receive_mode ( RAW1394_DMA_PACKET_PER_BUFFER ) |
---|
| 1266 | , m_Client( 0 ) |
---|
| 1267 | , m_speed( speed ) |
---|
| 1268 | , m_State( eHS_Stopped ) |
---|
| 1269 | , m_NextState( eHS_Stopped ) |
---|
| 1270 | , m_switch_on_cycle(0) |
---|
| 1271 | #ifdef DEBUG |
---|
| 1272 | , m_packets( 0 ) |
---|
| 1273 | , m_dropped( 0 ) |
---|
| 1274 | , m_skipped( 0 ) |
---|
| 1275 | , m_min_ahead( 7999 ) |
---|
| 1276 | #endif |
---|
| 1277 | { |
---|
| 1278 | } |
---|
| 1279 | |
---|
| 1280 | IsoHandlerManager::IsoHandler::~IsoHandler() { |
---|
| 1281 | // Don't call until libraw1394's raw1394_new_handle() function has been |
---|
| 1282 | // fixed to correctly initialise the iso_packet_infos field. Bug is |
---|
| 1283 | // confirmed present in libraw1394 1.2.1. In any case, |
---|
| 1284 | // raw1394_destroy_handle() will do any iso system shutdown required. |
---|
| 1285 | // raw1394_iso_shutdown(m_handle); |
---|
| 1286 | if(m_handle) { |
---|
| 1287 | if (m_State == eHS_Running) { |
---|
| 1288 | debugError("BUG: Handler still running!\n"); |
---|
| 1289 | disable(); |
---|
| 1290 | } |
---|
| 1291 | } |
---|
| 1292 | } |
---|
| 1293 | |
---|
| 1294 | bool |
---|
| 1295 | IsoHandlerManager::IsoHandler::canIterateClient() |
---|
| 1296 | { |
---|
| 1297 | debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "checking...\n"); |
---|
| 1298 | if(m_Client) { |
---|
| 1299 | bool result; |
---|
| 1300 | |
---|
| 1301 | if (m_type == eHT_Receive) { |
---|
| 1302 | result = m_Client->canProducePacket(); |
---|
| 1303 | } else { |
---|
| 1304 | result = m_Client->canConsumePacket(); |
---|
| 1305 | } |
---|
| 1306 | debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, " returns %d\n", result); |
---|
| 1307 | return result && (m_State != eHS_Error); |
---|
| 1308 | } else { |
---|
| 1309 | debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, " no client\n"); |
---|
| 1310 | } |
---|
| 1311 | return false; |
---|
| 1312 | } |
---|
| 1313 | |
---|
| 1314 | bool |
---|
| 1315 | IsoHandlerManager::IsoHandler::iterate() { |
---|
| 1316 | return iterate(m_manager.get1394Service().getCycleTimer()); |
---|
| 1317 | } |
---|
| 1318 | |
---|
| 1319 | bool |
---|
| 1320 | IsoHandlerManager::IsoHandler::iterate(uint32_t cycle_timer_now) { |
---|
| 1321 | debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "(%p, %s) Iterating ISO handler at %08X...\n", |
---|
| 1322 | this, getTypeString(), cycle_timer_now); |
---|
| 1323 | m_last_now = cycle_timer_now; |
---|
| 1324 | if(m_State == eHS_Running) { |
---|
| 1325 | assert(m_handle); |
---|
| 1326 | |
---|
| 1327 | #if ISOHANDLER_FLUSH_BEFORE_ITERATE |
---|
| 1328 | // this flushes all packets received since the poll() returned |
---|
| 1329 | // from kernel to userspace such that they are processed by this |
---|
| 1330 | // iterate. Doing so might result in lower latency capability |
---|
| 1331 | // and/or better reliability |
---|
| 1332 | if(m_type == eHT_Receive) { |
---|
| 1333 | raw1394_iso_recv_flush(m_handle); |
---|
| 1334 | } |
---|
| 1335 | #endif |
---|
| 1336 | |
---|
| 1337 | if(raw1394_loop_iterate(m_handle)) { |
---|
| 1338 | debugError( "IsoHandler (%p): Failed to iterate handler: %s\n", |
---|
| 1339 | this, strerror(errno)); |
---|
| 1340 | return false; |
---|
| 1341 | } |
---|
| 1342 | debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "(%p, %s) done interating ISO handler...\n", |
---|
| 1343 | this, getTypeString()); |
---|
| 1344 | return true; |
---|
| 1345 | } else { |
---|
| 1346 | debugOutput(DEBUG_LEVEL_VERBOSE, "(%p, %s) Not iterating a non-running handler...\n", |
---|
| 1347 | this, getTypeString()); |
---|
| 1348 | return false; |
---|
| 1349 | } |
---|
| 1350 | } |
---|
| 1351 | |
---|
| 1352 | /** |
---|
| 1353 | * Bus reset handler |
---|
| 1354 | * |
---|
| 1355 | * @return ? |
---|
| 1356 | */ |
---|
| 1357 | |
---|
| 1358 | bool |
---|
| 1359 | IsoHandlerManager::IsoHandler::handleBusReset() |
---|
| 1360 | { |
---|
| 1361 | debugOutput( DEBUG_LEVEL_NORMAL, "bus reset...\n"); |
---|
| 1362 | m_last_packet_handled_at = 0xFFFFFFFF; |
---|
| 1363 | |
---|
| 1364 | #define CSR_CYCLE_TIME 0x200 |
---|
| 1365 | #define CSR_REGISTER_BASE 0xfffff0000000ULL |
---|
| 1366 | // do a simple read on ourself in order to update the internal structures |
---|
| 1367 | // this avoids read failures after a bus reset |
---|
| 1368 | quadlet_t buf=0; |
---|
| 1369 | raw1394_read(m_handle, raw1394_get_local_id(m_handle), |
---|
| 1370 | CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf); |
---|
| 1371 | |
---|
| 1372 | return m_Client->handleBusReset(); |
---|
| 1373 | } |
---|
| 1374 | |
---|
| 1375 | /** |
---|
| 1376 | * Call this if you find out that this handler has died for some |
---|
| 1377 | * external reason. |
---|
| 1378 | */ |
---|
| 1379 | void |
---|
| 1380 | IsoHandlerManager::IsoHandler::notifyOfDeath() |
---|
| 1381 | { |
---|
| 1382 | m_State = eHS_Error; |
---|
| 1383 | m_NextState = eHS_Error; |
---|
| 1384 | |
---|
| 1385 | // notify the client of the fact that we have died |
---|
| 1386 | m_Client->handlerDied(); |
---|
| 1387 | |
---|
| 1388 | // wake ourselves up |
---|
| 1389 | if(m_handle) raw1394_wake_up(m_handle); |
---|
| 1390 | } |
---|
| 1391 | |
---|
| 1392 | void IsoHandlerManager::IsoHandler::dumpInfo() |
---|
| 1393 | { |
---|
| 1394 | int channel=-1; |
---|
| 1395 | if (m_Client) channel=m_Client->getChannel(); |
---|
| 1396 | |
---|
| 1397 | debugOutputShort( DEBUG_LEVEL_NORMAL, " Handler type................: %s\n", |
---|
| 1398 | getTypeString()); |
---|
| 1399 | debugOutputShort( DEBUG_LEVEL_NORMAL, " Port, Channel...............: %2d, %2d\n", |
---|
| 1400 | m_manager.get1394Service().getPort(), channel); |
---|
| 1401 | debugOutputShort( DEBUG_LEVEL_NORMAL, " Buffer, MaxPacketSize, IRQ..: %4d, %4d, %4d\n", |
---|
| 1402 | m_buf_packets, m_max_packet_size, m_irq_interval); |
---|
| 1403 | if (this->getType() == eHT_Transmit) { |
---|
| 1404 | debugOutputShort( DEBUG_LEVEL_NORMAL, " Speed ..................: %2d\n", |
---|
| 1405 | m_speed); |
---|
| 1406 | #ifdef DEBUG |
---|
| 1407 | debugOutputShort( DEBUG_LEVEL_NORMAL, " Min ISOXMT bufferfill : %04d\n", m_min_ahead); |
---|
| 1408 | #endif |
---|
| 1409 | } |
---|
| 1410 | #ifdef DEBUG |
---|
| 1411 | debugOutputShort( DEBUG_LEVEL_NORMAL, " Last cycle, dropped.........: %4d, %4u, %4u\n", |
---|
| 1412 | m_last_cycle, m_dropped, m_skipped); |
---|
| 1413 | #endif |
---|
| 1414 | |
---|
| 1415 | } |
---|
| 1416 | |
---|
| 1417 | void IsoHandlerManager::IsoHandler::setVerboseLevel(int l) |
---|
| 1418 | { |
---|
| 1419 | setDebugLevel(l); |
---|
| 1420 | debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l ); |
---|
| 1421 | } |
---|
| 1422 | |
---|
| 1423 | bool IsoHandlerManager::IsoHandler::registerStream(StreamProcessor *stream) |
---|
| 1424 | { |
---|
| 1425 | assert(stream); |
---|
| 1426 | debugOutput( DEBUG_LEVEL_VERBOSE, "registering stream (%p)\n", stream); |
---|
| 1427 | |
---|
| 1428 | if (m_Client) { |
---|
| 1429 | debugFatal( "Generic IsoHandlers can have only one client\n"); |
---|
| 1430 | return false; |
---|
| 1431 | } |
---|
| 1432 | m_Client=stream; |
---|
| 1433 | return true; |
---|
| 1434 | } |
---|
| 1435 | |
---|
| 1436 | bool IsoHandlerManager::IsoHandler::unregisterStream(StreamProcessor *stream) |
---|
| 1437 | { |
---|
| 1438 | assert(stream); |
---|
| 1439 | debugOutput( DEBUG_LEVEL_VERBOSE, "unregistering stream (%p)\n", stream); |
---|
| 1440 | |
---|
| 1441 | if(stream != m_Client) { |
---|
| 1442 | debugFatal( "no client registered\n"); |
---|
| 1443 | return false; |
---|
| 1444 | } |
---|
| 1445 | m_Client=0; |
---|
| 1446 | return true; |
---|
| 1447 | } |
---|
| 1448 | |
---|
| 1449 | // ISO packet interface |
---|
| 1450 | enum raw1394_iso_disposition IsoHandlerManager::IsoHandler::putPacket( |
---|
| 1451 | unsigned char *data, unsigned int length, |
---|
| 1452 | unsigned char channel, unsigned char tag, unsigned char sy, |
---|
| 1453 | unsigned int cycle, unsigned int dropped) { |
---|
| 1454 | // keep track of dropped cycles |
---|
| 1455 | int dropped_cycles = 0; |
---|
| 1456 | if (m_last_cycle != (int)cycle && m_last_cycle != -1) { |
---|
| 1457 | dropped_cycles = diffCycles(cycle, m_last_cycle) - 1; |
---|
| 1458 | #ifdef DEBUG |
---|
| 1459 | if (dropped_cycles < 0) { |
---|
| 1460 | debugWarning("(%p) dropped < 1 (%d), cycle: %d, last_cycle: %d, dropped: %d\n", |
---|
| 1461 | this, dropped_cycles, cycle, m_last_cycle, dropped); |
---|
| 1462 | } |
---|
| 1463 | if (dropped_cycles > 0) { |
---|
| 1464 | debugOutput(DEBUG_LEVEL_VERBOSE, |
---|
| 1465 | "(%p) dropped %d packets on cycle %u, 'dropped'=%u, cycle=%d, m_last_cycle=%d\n", |
---|
| 1466 | this, dropped_cycles, cycle, dropped, cycle, m_last_cycle); |
---|
| 1467 | m_dropped += dropped_cycles; |
---|
| 1468 | } |
---|
| 1469 | #endif |
---|
| 1470 | } |
---|
| 1471 | m_last_cycle = cycle; |
---|
| 1472 | |
---|
| 1473 | // the m_last_now value is set when the iterate() function is called. |
---|
| 1474 | uint32_t now_cycles = CYCLE_TIMER_GET_CYCLES(m_last_now); |
---|
| 1475 | |
---|
| 1476 | // two cases can occur: |
---|
| 1477 | // (1) this packet has been received before iterate() was called (normal case). |
---|
| 1478 | // (2) this packet has been received after iterate() was called. |
---|
| 1479 | // happens when the kernel flushes more packets while we are already processing. |
---|
| 1480 | // |
---|
| 1481 | // In case (1) now_cycles is a small number of cycles larger than cycle. In |
---|
| 1482 | // case (2) now_cycles is a small number of cycles smaller than cycle. |
---|
| 1483 | // hence abs(diffCycles(now_cycles, cycles)) has to be 'small' |
---|
| 1484 | |
---|
| 1485 | // we can calculate the time of arrival for this packet as |
---|
| 1486 | // 'now' + diffCycles(cycles, now_cycles) * TICKS_PER_CYCLE |
---|
| 1487 | // in its properly wrapped version |
---|
| 1488 | int64_t diff_cycles = diffCycles(cycle, now_cycles); |
---|
| 1489 | int64_t tmp = CYCLE_TIMER_TO_TICKS(m_last_now); |
---|
| 1490 | tmp += diff_cycles * (int64_t)TICKS_PER_CYCLE; |
---|
| 1491 | uint64_t pkt_ctr_ticks = wrapAtMinMaxTicks(tmp); |
---|
| 1492 | uint32_t pkt_ctr = TICKS_TO_CYCLE_TIMER(pkt_ctr_ticks); |
---|
| 1493 | #ifdef DEBUG |
---|
| 1494 | if( (now_cycles < cycle) |
---|
| 1495 | && diffCycles(now_cycles, cycle) < 0 |
---|
| 1496 | // ignore this on dropped cycles, since it's normal |
---|
| 1497 | // that now is ahead on the received packets (as we miss packets) |
---|
| 1498 | && dropped_cycles == 0) |
---|
| 1499 | { |
---|
| 1500 | debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Special non-unwrapping happened\n"); |
---|
| 1501 | } |
---|
| 1502 | #endif |
---|
| 1503 | |
---|
| 1504 | #if ISOHANDLER_CHECK_CTR_RECONSTRUCTION |
---|
| 1505 | // add a seconds field |
---|
| 1506 | uint32_t now = m_manager.get1394Service().getCycleTimer(); |
---|
| 1507 | uint32_t now_secs_ref = CYCLE_TIMER_GET_SECS(now); |
---|
| 1508 | // causality results in the fact that 'now' is always after 'cycle' |
---|
| 1509 | // or at best, equal (if this handler was called within 125us after |
---|
| 1510 | // the packet was on the wire). |
---|
| 1511 | if(CYCLE_TIMER_GET_CYCLES(now) < cycle) { |
---|
| 1512 | // the cycle field has wrapped, substract one second |
---|
| 1513 | if(now_secs_ref == 0) { |
---|
| 1514 | now_secs_ref = 127; |
---|
| 1515 | } else { |
---|
| 1516 | now_secs_ref -= 1; |
---|
| 1517 | } |
---|
| 1518 | } |
---|
| 1519 | uint32_t pkt_ctr_ref = cycle << 12; |
---|
| 1520 | pkt_ctr_ref |= (now_secs_ref & 0x7F) << 25; |
---|
| 1521 | |
---|
| 1522 | if((pkt_ctr & ~0x0FFFL) != pkt_ctr_ref) { |
---|
| 1523 | debugWarning("reconstructed CTR counter discrepancy\n"); |
---|
| 1524 | debugWarning(" ingredients: %X, %X, %X, %X, %X, %d, %ld, %ld, %"PRId64"\n", |
---|
| 1525 | cycle, pkt_ctr_ref, pkt_ctr, |
---|
| 1526 | now, m_last_now, now_secs_ref, |
---|
| 1527 | (long int)CYCLE_TIMER_GET_SECS(now), |
---|
| 1528 | (long int)CYCLE_TIMER_GET_SECS(m_last_now), |
---|
| 1529 | tmp); |
---|
| 1530 | debugWarning(" diffcy = %"PRId64" \n", diff_cycles); |
---|
| 1531 | } |
---|
| 1532 | #endif |
---|
| 1533 | m_last_packet_handled_at = pkt_ctr; |
---|
| 1534 | |
---|
| 1535 | // leave the offset field (for now?) |
---|
| 1536 | |
---|
| 1537 | debugOutputExtreme(DEBUG_LEVEL_ULTRA_VERBOSE, |
---|
| 1538 | "received packet: length=%d, channel=%d, cycle=%d, at %08X\n", |
---|
| 1539 | length, channel, cycle, pkt_ctr); |
---|
| 1540 | m_packets++; |
---|
| 1541 | #ifdef DEBUG |
---|
| 1542 | if (length > m_max_packet_size) { |
---|
| 1543 | debugWarning("(%p, %s) packet too large: len=%u max=%u\n", |
---|
| 1544 | this, getTypeString(), length, m_max_packet_size); |
---|
| 1545 | } |
---|
| 1546 | if(m_last_cycle == -1) { |
---|
| 1547 | debugOutput(DEBUG_LEVEL_VERBOSE, "Handler for %s SP %p is alive (cycle = %u)\n", getTypeString(), this, cycle); |
---|
| 1548 | } |
---|
| 1549 | #endif |
---|
| 1550 | |
---|
| 1551 | // iterate the client if required |
---|
| 1552 | if(m_Client) |
---|
| 1553 | return m_Client->putPacket(data, length, channel, tag, sy, pkt_ctr, dropped_cycles); |
---|
| 1554 | |
---|
| 1555 | return RAW1394_ISO_OK; |
---|
| 1556 | } |
---|
| 1557 | |
---|
| 1558 | enum raw1394_iso_disposition |
---|
| 1559 | IsoHandlerManager::IsoHandler::getPacket(unsigned char *data, unsigned int *length, |
---|
| 1560 | unsigned char *tag, unsigned char *sy, |
---|
| 1561 | int cycle, unsigned int dropped, unsigned int skipped) { |
---|
| 1562 | |
---|
| 1563 | uint32_t pkt_ctr; |
---|
| 1564 | if (cycle < 0) { |
---|
| 1565 | // mark invalid |
---|
| 1566 | pkt_ctr = 0xFFFFFFFF; |
---|
| 1567 | } else { |
---|
| 1568 | // the m_last_now value is set when the iterate() function is called. |
---|
| 1569 | uint32_t now_cycles = CYCLE_TIMER_GET_CYCLES(m_last_now); |
---|
| 1570 | |
---|
| 1571 | // two cases can occur: |
---|
| 1572 | // (1) this packet has been received before iterate() was called (normal case). |
---|
| 1573 | // (2) this packet has been received after iterate() was called. |
---|
| 1574 | // happens when the kernel flushes more packets while we are already processing. |
---|
| 1575 | // |
---|
| 1576 | // In case (1) now_cycles is a small number of cycles larger than cycle. In |
---|
| 1577 | // case (2) now_cycles is a small number of cycles smaller than cycle. |
---|
| 1578 | // hence abs(diffCycles(now_cycles, cycles)) has to be 'small' |
---|
| 1579 | |
---|
| 1580 | // we can calculate the time of arrival for this packet as |
---|
| 1581 | // 'now' + diffCycles(cycles, now_cycles) * TICKS_PER_CYCLE |
---|
| 1582 | // in its properly wrapped version |
---|
| 1583 | int64_t diff_cycles = diffCycles(cycle, now_cycles); |
---|
| 1584 | int64_t tmp = CYCLE_TIMER_TO_TICKS(m_last_now); |
---|
| 1585 | tmp += diff_cycles * (int64_t)TICKS_PER_CYCLE; |
---|
| 1586 | uint64_t pkt_ctr_ticks = wrapAtMinMaxTicks(tmp); |
---|
| 1587 | pkt_ctr = TICKS_TO_CYCLE_TIMER(pkt_ctr_ticks); |
---|
| 1588 | |
---|
| 1589 | #if ISOHANDLER_CHECK_CTR_RECONSTRUCTION |
---|
| 1590 | // add a seconds field |
---|
| 1591 | uint32_t now = m_manager.get1394Service().getCycleTimer(); |
---|
| 1592 | uint32_t now_secs_ref = CYCLE_TIMER_GET_SECS(now); |
---|
| 1593 | // causality results in the fact that 'now' is always after 'cycle' |
---|
| 1594 | if(CYCLE_TIMER_GET_CYCLES(now) > (unsigned int)cycle) { |
---|
| 1595 | // the cycle field has wrapped, add one second |
---|
| 1596 | now_secs_ref += 1; |
---|
| 1597 | // no need for this: |
---|
| 1598 | if(now_secs_ref == 128) { |
---|
| 1599 | now_secs_ref = 0; |
---|
| 1600 | } |
---|
| 1601 | } |
---|
| 1602 | uint32_t pkt_ctr_ref = cycle << 12; |
---|
| 1603 | pkt_ctr_ref |= (now_secs_ref & 0x7F) << 25; |
---|
| 1604 | |
---|
| 1605 | if(((pkt_ctr & ~0x0FFFL) != pkt_ctr_ref) && (m_packets > m_buf_packets)) { |
---|
| 1606 | debugWarning("reconstructed CTR counter discrepancy\n"); |
---|
| 1607 | debugWarning(" ingredients: %X, %X, %X, %X, %X, %d, %ld, %ld, %"PRId64"\n", |
---|
| 1608 | cycle, pkt_ctr_ref, pkt_ctr, |
---|
| 1609 | now, m_last_now, now_secs_ref, |
---|
| 1610 | (long int)CYCLE_TIMER_GET_SECS(now), |
---|
| 1611 | (long int)CYCLE_TIMER_GET_SECS(m_last_now), |
---|
| 1612 | tmp); |
---|
| 1613 | debugWarning(" diffcy = %"PRId64" \n", diff_cycles); |
---|
| 1614 | } |
---|
| 1615 | #endif |
---|
| 1616 | } |
---|
| 1617 | if (m_packets < m_buf_packets) { // these are still prebuffer packets |
---|
| 1618 | m_last_packet_handled_at = 0xFFFFFFFF; |
---|
| 1619 | } else { |
---|
| 1620 | m_last_packet_handled_at = pkt_ctr; |
---|
| 1621 | } |
---|
| 1622 | debugOutputExtreme(DEBUG_LEVEL_ULTRA_VERBOSE, |
---|
| 1623 | "sending packet: length=%d, cycle=%d, at %08X\n", |
---|
| 1624 | *length, cycle, pkt_ctr); |
---|
| 1625 | |
---|
| 1626 | m_packets++; |
---|
| 1627 | |
---|
| 1628 | #ifdef DEBUG |
---|
| 1629 | if(m_last_cycle == -1) { |
---|
| 1630 | debugOutput(DEBUG_LEVEL_VERBOSE, "Handler for %s SP %p is alive (cycle = %d)\n", getTypeString(), this, cycle); |
---|
| 1631 | } |
---|
| 1632 | #endif |
---|
| 1633 | |
---|
| 1634 | // keep track of dropped cycles |
---|
| 1635 | int dropped_cycles = 0; |
---|
| 1636 | if (m_last_cycle != cycle && m_last_cycle != -1) { |
---|
| 1637 | dropped_cycles = diffCycles(cycle, m_last_cycle) - 1; |
---|
| 1638 | // correct for skipped packets |
---|
| 1639 | // since those are not dropped, but only delayed |
---|
| 1640 | dropped_cycles -= skipped; |
---|
| 1641 | |
---|
| 1642 | #ifdef DEBUG |
---|
| 1643 | if(skipped) { |
---|
| 1644 | debugOutput(DEBUG_LEVEL_VERY_VERBOSE, |
---|
| 1645 | "(%p) skipped %d cycles, cycle: %d, last_cycle: %d, dropped: %d\n", |
---|
| 1646 | this, skipped, cycle, m_last_cycle, dropped); |
---|
| 1647 | m_skipped += skipped; |
---|
| 1648 | } |
---|
| 1649 | if (dropped_cycles < 0) { |
---|
| 1650 | debugWarning("(%p) dropped < 1 (%d), cycle: %d, last_cycle: %d, dropped: %d, skipped: %d\n", |
---|
| 1651 | this, dropped_cycles, cycle, m_last_cycle, dropped, skipped); |
---|
| 1652 | } |
---|
| 1653 | if (dropped_cycles > 0) { |
---|
| 1654 | debugOutput(DEBUG_LEVEL_VERBOSE, |
---|
| 1655 | "(%p) dropped %d packets on cycle %u (last_cycle=%u, dropped=%d, skipped: %d)\n", |
---|
| 1656 | this, dropped_cycles, cycle, m_last_cycle, dropped, skipped); |
---|
| 1657 | m_dropped += dropped_cycles - skipped; |
---|
| 1658 | } |
---|
| 1659 | #endif |
---|
| 1660 | } |
---|
| 1661 | if (cycle >= 0) { |
---|
| 1662 | m_last_cycle = cycle; |
---|
| 1663 | |
---|
| 1664 | #ifdef DEBUG |
---|
| 1665 | /* int ahead = diffCycles(cycle, now_cycles); |
---|
| 1666 | if (ahead < m_min_ahead) m_min_ahead = ahead; |
---|
| 1667 | */ |
---|
| 1668 | #endif |
---|
| 1669 | } |
---|
| 1670 | |
---|
| 1671 | #ifdef DEBUG |
---|
| 1672 | if (dropped > 0) { |
---|
| 1673 | debugOutput(DEBUG_LEVEL_VERBOSE, |
---|
| 1674 | "(%p) OHCI issue on cycle %u (dropped_cycles=%d, last_cycle=%u, dropped=%d, skipped: %d)\n", |
---|
| 1675 | this, cycle, dropped_cycles, m_last_cycle, dropped, skipped); |
---|
| 1676 | } |
---|
| 1677 | #endif |
---|
| 1678 | |
---|
| 1679 | if(m_Client) { |
---|
| 1680 | enum raw1394_iso_disposition retval; |
---|
| 1681 | retval = m_Client->getPacket(data, length, tag, sy, pkt_ctr, dropped_cycles, skipped, m_max_packet_size); |
---|
| 1682 | #ifdef DEBUG |
---|
| 1683 | if (*length > m_max_packet_size) { |
---|
| 1684 | debugWarning("(%p, %s) packet too large: len=%u max=%u\n", |
---|
| 1685 | this, getTypeString(), *length, m_max_packet_size); |
---|
| 1686 | } |
---|
| 1687 | #endif |
---|
| 1688 | return retval; |
---|
| 1689 | } |
---|
| 1690 | |
---|
| 1691 | *tag = 0; |
---|
| 1692 | *sy = 0; |
---|
| 1693 | *length = 0; |
---|
| 1694 | return RAW1394_ISO_OK; |
---|
| 1695 | } |
---|
| 1696 | |
---|
| 1697 | bool |
---|
| 1698 | IsoHandlerManager::IsoHandler::enable(int cycle) |
---|
| 1699 | { |
---|
| 1700 | debugOutput( DEBUG_LEVEL_VERBOSE, "start on cycle %d\n", cycle); |
---|
| 1701 | |
---|
| 1702 | // check the state |
---|
| 1703 | if(m_State != eHS_Stopped) { |
---|
| 1704 | debugError("Incorrect state, expected eHS_Stopped, got %d\n",(int)m_State); |
---|
| 1705 | return false; |
---|
| 1706 | } |
---|
| 1707 | |
---|
| 1708 | assert(m_handle == NULL); |
---|
| 1709 | |
---|
| 1710 | // create a handle for the ISO traffic |
---|
| 1711 | m_handle = raw1394_new_handle_on_port( m_manager.get1394Service().getPort() ); |
---|
| 1712 | if ( !m_handle ) { |
---|
| 1713 | if ( !errno ) { |
---|
| 1714 | debugError("libraw1394 not compatible\n"); |
---|
| 1715 | } else { |
---|
| 1716 | debugError("Could not get 1394 handle: %s\n", strerror(errno) ); |
---|
| 1717 | debugError("Are ieee1394 and raw1394 drivers loaded?\n"); |
---|
| 1718 | } |
---|
| 1719 | return false; |
---|
| 1720 | } |
---|
| 1721 | raw1394_set_userdata(m_handle, static_cast<void *>(this)); |
---|
| 1722 | |
---|
| 1723 | // prepare the handler, allocate the resources |
---|
| 1724 | debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing iso handler (%p, client=%p)\n", this, m_Client); |
---|
| 1725 | dumpInfo(); |
---|
| 1726 | if (getType() == eHT_Receive) { |
---|
| 1727 | if(raw1394_iso_recv_init(m_handle, |
---|
| 1728 | iso_receive_handler, |
---|
| 1729 | m_buf_packets, |
---|
| 1730 | m_max_packet_size, |
---|
| 1731 | m_Client->getChannel(), |
---|
| 1732 | m_receive_mode, |
---|
| 1733 | m_irq_interval)) { |
---|
| 1734 | debugFatal("Could not do receive initialization (PACKET_PER_BUFFER)!\n" ); |
---|
| 1735 | debugFatal(" %s\n",strerror(errno)); |
---|
| 1736 | return false; |
---|
| 1737 | } |
---|
| 1738 | |
---|
| 1739 | if(raw1394_iso_recv_start(m_handle, cycle, -1, 0)) { |
---|
| 1740 | debugFatal("Could not start receive handler (%s)\n",strerror(errno)); |
---|
| 1741 | dumpInfo(); |
---|
| 1742 | return false; |
---|
| 1743 | } |
---|
| 1744 | } else { |
---|
| 1745 | if(raw1394_iso_xmit_init(m_handle, |
---|
| 1746 | iso_transmit_handler, |
---|
| 1747 | m_buf_packets, |
---|
| 1748 | m_max_packet_size, |
---|
| 1749 | m_Client->getChannel(), |
---|
| 1750 | m_speed, |
---|
| 1751 | m_irq_interval)) { |
---|
| 1752 | debugFatal("Could not do xmit initialisation!\n" ); |
---|
| 1753 | return false; |
---|
| 1754 | } |
---|
| 1755 | |
---|
| 1756 | if(raw1394_iso_xmit_start(m_handle, cycle, 0)) { |
---|
| 1757 | debugFatal("Could not start xmit handler (%s)\n", strerror(errno)); |
---|
| 1758 | dumpInfo(); |
---|
| 1759 | return false; |
---|
| 1760 | } |
---|
| 1761 | } |
---|
| 1762 | |
---|
| 1763 | #ifdef DEBUG |
---|
| 1764 | m_min_ahead = 7999; |
---|
| 1765 | #endif |
---|
| 1766 | |
---|
| 1767 | m_packets = 0; |
---|
| 1768 | |
---|
| 1769 | // indicate that the first iterate() still has to occur. |
---|
| 1770 | m_last_now = 0xFFFFFFFF; |
---|
| 1771 | m_last_packet_handled_at = 0xFFFFFFFF; |
---|
| 1772 | |
---|
| 1773 | m_State = eHS_Running; |
---|
| 1774 | m_NextState = eHS_Running; |
---|
| 1775 | return true; |
---|
| 1776 | } |
---|
| 1777 | |
---|
| 1778 | bool |
---|
| 1779 | IsoHandlerManager::IsoHandler::disable() |
---|
| 1780 | { |
---|
| 1781 | debugOutput( DEBUG_LEVEL_VERBOSE, "(%p, %s) enter...\n", |
---|
| 1782 | this, (m_type==eHT_Receive?"Receive":"Transmit")); |
---|
| 1783 | |
---|
| 1784 | // check state |
---|
| 1785 | if(m_State != eHS_Running) { |
---|
| 1786 | debugError("Incorrect state, expected eHS_Running, got %d\n",(int)m_State); |
---|
| 1787 | return false; |
---|
| 1788 | } |
---|
| 1789 | |
---|
| 1790 | assert(m_handle != NULL); |
---|
| 1791 | |
---|
| 1792 | debugOutput( DEBUG_LEVEL_VERBOSE, "(%p, %s) wake up handle...\n", |
---|
| 1793 | this, (m_type==eHT_Receive?"Receive":"Transmit")); |
---|
| 1794 | |
---|
| 1795 | // wake up any waiting reads/polls |
---|
| 1796 | raw1394_wake_up(m_handle); |
---|
| 1797 | |
---|
| 1798 | // this is put here to try and avoid the |
---|
| 1799 | // Runaway context problem |
---|
| 1800 | // don't know if it will help though. |
---|
| 1801 | /* if(m_State != eHS_Error) { // if the handler is dead, this might block forever |
---|
| 1802 | raw1394_iso_xmit_sync(m_handle); |
---|
| 1803 | }*/ |
---|
| 1804 | debugOutput( DEBUG_LEVEL_VERBOSE, "(%p, %s) stop...\n", |
---|
| 1805 | this, (m_type==eHT_Receive?"Receive":"Transmit")); |
---|
| 1806 | // stop iso traffic |
---|
| 1807 | raw1394_iso_stop(m_handle); |
---|
| 1808 | // deallocate resources |
---|
| 1809 | |
---|
| 1810 | // Don't call until libraw1394's raw1394_new_handle() function has been |
---|
| 1811 | // fixed to correctly initialise the iso_packet_infos field. Bug is |
---|
| 1812 | // confirmed present in libraw1394 1.2.1. |
---|
| 1813 | raw1394_iso_shutdown(m_handle); |
---|
| 1814 | |
---|
| 1815 | raw1394_destroy_handle(m_handle); |
---|
| 1816 | m_handle = NULL; |
---|
| 1817 | |
---|
| 1818 | m_State = eHS_Stopped; |
---|
| 1819 | m_NextState = eHS_Stopped; |
---|
| 1820 | return true; |
---|
| 1821 | } |
---|
| 1822 | |
---|
| 1823 | // functions to request enable or disable at the next opportunity |
---|
| 1824 | bool |
---|
| 1825 | IsoHandlerManager::IsoHandler::requestEnable(int cycle) |
---|
| 1826 | { |
---|
| 1827 | if (m_State == eHS_Running) { |
---|
| 1828 | debugError("Enable requested on enabled stream\n"); |
---|
| 1829 | return false; |
---|
| 1830 | } |
---|
| 1831 | if (m_State != eHS_Stopped) { |
---|
| 1832 | debugError("Enable requested on stream with state: %d\n", m_State); |
---|
| 1833 | return false; |
---|
| 1834 | } |
---|
| 1835 | m_NextState = eHS_Running; |
---|
| 1836 | return true; |
---|
| 1837 | } |
---|
| 1838 | |
---|
| 1839 | bool |
---|
| 1840 | IsoHandlerManager::IsoHandler::requestDisable() |
---|
| 1841 | { |
---|
| 1842 | if (m_State == eHS_Stopped) { |
---|
| 1843 | debugError("Disable requested on disabled stream\n"); |
---|
| 1844 | return false; |
---|
| 1845 | } |
---|
| 1846 | if (m_State != eHS_Running) { |
---|
| 1847 | debugError("Disable requested on stream with state=%d\n", m_State); |
---|
| 1848 | return false; |
---|
| 1849 | } |
---|
| 1850 | m_NextState = eHS_Stopped; |
---|
| 1851 | return true; |
---|
| 1852 | } |
---|
| 1853 | |
---|
| 1854 | void |
---|
| 1855 | IsoHandlerManager::IsoHandler::updateState() |
---|
| 1856 | { |
---|
| 1857 | // execute state changes requested |
---|
| 1858 | if(m_State != m_NextState) { |
---|
| 1859 | debugOutput(DEBUG_LEVEL_VERBOSE, "(%p) handler needs state update from %d => %d\n", this, m_State, m_NextState); |
---|
| 1860 | if(m_State == eHS_Stopped && m_NextState == eHS_Running) { |
---|
| 1861 | debugOutput(DEBUG_LEVEL_VERBOSE, "handler has to be enabled\n"); |
---|
| 1862 | enable(m_switch_on_cycle); |
---|
| 1863 | } else if(m_State == eHS_Running && m_NextState == eHS_Stopped) { |
---|
| 1864 | debugOutput(DEBUG_LEVEL_VERBOSE, "handler has to be disabled\n"); |
---|
| 1865 | disable(); |
---|
| 1866 | } else { |
---|
| 1867 | debugError("Unknown state transition\n"); |
---|
| 1868 | } |
---|
| 1869 | } |
---|
| 1870 | } |
---|
| 1871 | |
---|
| 1872 | /** |
---|
| 1873 | * @brief convert a EHandlerType to a string |
---|
| 1874 | * @param t the type |
---|
| 1875 | * @return a char * describing the state |
---|
| 1876 | */ |
---|
| 1877 | const char * |
---|
| 1878 | IsoHandlerManager::IsoHandler::eHTToString(enum EHandlerType t) { |
---|
| 1879 | switch (t) { |
---|
| 1880 | case eHT_Receive: return "Receive"; |
---|
| 1881 | case eHT_Transmit: return "Transmit"; |
---|
| 1882 | default: return "error: unknown type"; |
---|
| 1883 | } |
---|
| 1884 | } |
---|