diff options
| author | Dave Airlie <airlied@redhat.com> | 2014-10-20 02:31:53 -0400 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2014-12-08 18:56:49 -0500 |
| commit | b0ee9e7fa5b461a91f24d1d03b10c6bf162c86f9 (patch) | |
| tree | dd12f04f8e18574f134a66bd8ceb93fbf5109606 /drivers/gpu | |
| parent | 6f134d7bb4347ab4c66ef123efb838fedb54186f (diff) | |
drm/fb: add support for tiled monitor configurations. (v2)
This adds fbdev/con support for tiled monitors, so that we
only set a mode on the correct half of the monitor, or
span the two halves if needed.
v2: remove unneeded ERROR, fix | vs ||
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 121 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_fbdev.c | 24 |
2 files changed, 122 insertions, 23 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index a467460f2aa6..52ce26d6b4fb 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
| @@ -1000,19 +1000,21 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, | |||
| 1000 | crtc_count = 0; | 1000 | crtc_count = 0; |
| 1001 | for (i = 0; i < fb_helper->crtc_count; i++) { | 1001 | for (i = 0; i < fb_helper->crtc_count; i++) { |
| 1002 | struct drm_display_mode *desired_mode; | 1002 | struct drm_display_mode *desired_mode; |
| 1003 | int x, y; | ||
| 1003 | desired_mode = fb_helper->crtc_info[i].desired_mode; | 1004 | desired_mode = fb_helper->crtc_info[i].desired_mode; |
| 1004 | 1005 | x = fb_helper->crtc_info[i].x; | |
| 1006 | y = fb_helper->crtc_info[i].y; | ||
| 1005 | if (desired_mode) { | 1007 | if (desired_mode) { |
| 1006 | if (gamma_size == 0) | 1008 | if (gamma_size == 0) |
| 1007 | gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; | 1009 | gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; |
| 1008 | if (desired_mode->hdisplay < sizes.fb_width) | 1010 | if (desired_mode->hdisplay + x < sizes.fb_width) |
| 1009 | sizes.fb_width = desired_mode->hdisplay; | 1011 | sizes.fb_width = desired_mode->hdisplay + x; |
| 1010 | if (desired_mode->vdisplay < sizes.fb_height) | 1012 | if (desired_mode->vdisplay + y < sizes.fb_height) |
| 1011 | sizes.fb_height = desired_mode->vdisplay; | 1013 | sizes.fb_height = desired_mode->vdisplay + y; |
| 1012 | if (desired_mode->hdisplay > sizes.surface_width) | 1014 | if (desired_mode->hdisplay + x > sizes.surface_width) |
| 1013 | sizes.surface_width = desired_mode->hdisplay; | 1015 | sizes.surface_width = desired_mode->hdisplay + x; |
| 1014 | if (desired_mode->vdisplay > sizes.surface_height) | 1016 | if (desired_mode->vdisplay + y > sizes.surface_height) |
| 1015 | sizes.surface_height = desired_mode->vdisplay; | 1017 | sizes.surface_height = desired_mode->vdisplay + y; |
| 1016 | crtc_count++; | 1018 | crtc_count++; |
| 1017 | } | 1019 | } |
| 1018 | } | 1020 | } |
| @@ -1312,6 +1314,7 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper, | |||
| 1312 | 1314 | ||
| 1313 | static bool drm_target_cloned(struct drm_fb_helper *fb_helper, | 1315 | static bool drm_target_cloned(struct drm_fb_helper *fb_helper, |
| 1314 | struct drm_display_mode **modes, | 1316 | struct drm_display_mode **modes, |
| 1317 | struct drm_fb_offset *offsets, | ||
| 1315 | bool *enabled, int width, int height) | 1318 | bool *enabled, int width, int height) |
| 1316 | { | 1319 | { |
| 1317 | int count, i, j; | 1320 | int count, i, j; |
| @@ -1383,27 +1386,88 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper, | |||
| 1383 | return false; | 1386 | return false; |
| 1384 | } | 1387 | } |
| 1385 | 1388 | ||
| 1389 | static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper, | ||
| 1390 | struct drm_display_mode **modes, | ||
| 1391 | struct drm_fb_offset *offsets, | ||
| 1392 | int idx, | ||
| 1393 | int h_idx, int v_idx) | ||
| 1394 | { | ||
| 1395 | struct drm_fb_helper_connector *fb_helper_conn; | ||
| 1396 | int i; | ||
| 1397 | int hoffset = 0, voffset = 0; | ||
| 1398 | |||
| 1399 | for (i = 0; i < fb_helper->connector_count; i++) { | ||
| 1400 | fb_helper_conn = fb_helper->connector_info[i]; | ||
| 1401 | if (!fb_helper_conn->connector->has_tile) | ||
| 1402 | continue; | ||
| 1403 | |||
| 1404 | if (!modes[i] && (h_idx || v_idx)) { | ||
| 1405 | DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i, | ||
| 1406 | fb_helper_conn->connector->base.id); | ||
| 1407 | continue; | ||
| 1408 | } | ||
| 1409 | if (fb_helper_conn->connector->tile_h_loc < h_idx) | ||
| 1410 | hoffset += modes[i]->hdisplay; | ||
| 1411 | |||
| 1412 | if (fb_helper_conn->connector->tile_v_loc < v_idx) | ||
| 1413 | voffset += modes[i]->vdisplay; | ||
| 1414 | } | ||
| 1415 | offsets[idx].x = hoffset; | ||
| 1416 | offsets[idx].y = voffset; | ||
| 1417 | DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx); | ||
| 1418 | return 0; | ||
| 1419 | } | ||
| 1420 | |||
| 1386 | static bool drm_target_preferred(struct drm_fb_helper *fb_helper, | 1421 | static bool drm_target_preferred(struct drm_fb_helper *fb_helper, |
| 1387 | struct drm_display_mode **modes, | 1422 | struct drm_display_mode **modes, |
| 1423 | struct drm_fb_offset *offsets, | ||
| 1388 | bool *enabled, int width, int height) | 1424 | bool *enabled, int width, int height) |
| 1389 | { | 1425 | { |
| 1390 | struct drm_fb_helper_connector *fb_helper_conn; | 1426 | struct drm_fb_helper_connector *fb_helper_conn; |
| 1391 | int i; | 1427 | int i; |
| 1392 | 1428 | uint64_t conn_configured = 0, mask; | |
| 1429 | int tile_pass = 0; | ||
| 1430 | mask = (1 << fb_helper->connector_count) - 1; | ||
| 1431 | retry: | ||
| 1393 | for (i = 0; i < fb_helper->connector_count; i++) { | 1432 | for (i = 0; i < fb_helper->connector_count; i++) { |
| 1394 | fb_helper_conn = fb_helper->connector_info[i]; | 1433 | fb_helper_conn = fb_helper->connector_info[i]; |
| 1395 | 1434 | ||
| 1396 | if (enabled[i] == false) | 1435 | if (conn_configured & (1 << i)) |
| 1436 | continue; | ||
| 1437 | |||
| 1438 | if (enabled[i] == false) { | ||
| 1439 | conn_configured |= (1 << i); | ||
| 1440 | continue; | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | /* first pass over all the untiled connectors */ | ||
| 1444 | if (tile_pass == 0 && fb_helper_conn->connector->has_tile) | ||
| 1397 | continue; | 1445 | continue; |
| 1398 | 1446 | ||
| 1447 | if (tile_pass == 1) { | ||
| 1448 | if (fb_helper_conn->connector->tile_h_loc != 0 || | ||
| 1449 | fb_helper_conn->connector->tile_v_loc != 0) | ||
| 1450 | continue; | ||
| 1451 | |||
| 1452 | } else { | ||
| 1453 | if (fb_helper_conn->connector->tile_h_loc != tile_pass -1 && | ||
| 1454 | fb_helper_conn->connector->tile_v_loc != tile_pass - 1) | ||
| 1455 | /* if this tile_pass doesn't cover any of the tiles - keep going */ | ||
| 1456 | continue; | ||
| 1457 | |||
| 1458 | /* find the tile offsets for this pass - need | ||
| 1459 | to find all tiles left and above */ | ||
| 1460 | drm_get_tile_offsets(fb_helper, modes, offsets, | ||
| 1461 | i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc); | ||
| 1462 | } | ||
| 1399 | DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", | 1463 | DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", |
| 1400 | fb_helper_conn->connector->base.id); | 1464 | fb_helper_conn->connector->base.id); |
| 1401 | 1465 | ||
| 1402 | /* got for command line mode first */ | 1466 | /* got for command line mode first */ |
| 1403 | modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); | 1467 | modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); |
| 1404 | if (!modes[i]) { | 1468 | if (!modes[i]) { |
| 1405 | DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", | 1469 | DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n", |
| 1406 | fb_helper_conn->connector->base.id); | 1470 | fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0); |
| 1407 | modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height); | 1471 | modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height); |
| 1408 | } | 1472 | } |
| 1409 | /* No preferred modes, pick one off the list */ | 1473 | /* No preferred modes, pick one off the list */ |
| @@ -1413,6 +1477,12 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper, | |||
| 1413 | } | 1477 | } |
| 1414 | DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : | 1478 | DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : |
| 1415 | "none"); | 1479 | "none"); |
| 1480 | conn_configured |= (1 << i); | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | if ((conn_configured & mask) != mask) { | ||
| 1484 | tile_pass++; | ||
| 1485 | goto retry; | ||
| 1416 | } | 1486 | } |
| 1417 | return true; | 1487 | return true; |
| 1418 | } | 1488 | } |
| @@ -1502,6 +1572,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
| 1502 | struct drm_device *dev = fb_helper->dev; | 1572 | struct drm_device *dev = fb_helper->dev; |
| 1503 | struct drm_fb_helper_crtc **crtcs; | 1573 | struct drm_fb_helper_crtc **crtcs; |
| 1504 | struct drm_display_mode **modes; | 1574 | struct drm_display_mode **modes; |
| 1575 | struct drm_fb_offset *offsets; | ||
| 1505 | struct drm_mode_set *modeset; | 1576 | struct drm_mode_set *modeset; |
| 1506 | bool *enabled; | 1577 | bool *enabled; |
| 1507 | int width, height; | 1578 | int width, height; |
| @@ -1516,9 +1587,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
| 1516 | sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); | 1587 | sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); |
| 1517 | modes = kcalloc(dev->mode_config.num_connector, | 1588 | modes = kcalloc(dev->mode_config.num_connector, |
| 1518 | sizeof(struct drm_display_mode *), GFP_KERNEL); | 1589 | sizeof(struct drm_display_mode *), GFP_KERNEL); |
| 1590 | offsets = kcalloc(dev->mode_config.num_connector, | ||
| 1591 | sizeof(struct drm_fb_offset), GFP_KERNEL); | ||
| 1519 | enabled = kcalloc(dev->mode_config.num_connector, | 1592 | enabled = kcalloc(dev->mode_config.num_connector, |
| 1520 | sizeof(bool), GFP_KERNEL); | 1593 | sizeof(bool), GFP_KERNEL); |
| 1521 | if (!crtcs || !modes || !enabled) { | 1594 | if (!crtcs || !modes || !enabled || !offsets) { |
| 1522 | DRM_ERROR("Memory allocation failed\n"); | 1595 | DRM_ERROR("Memory allocation failed\n"); |
| 1523 | goto out; | 1596 | goto out; |
| 1524 | } | 1597 | } |
| @@ -1528,14 +1601,16 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
| 1528 | 1601 | ||
| 1529 | if (!(fb_helper->funcs->initial_config && | 1602 | if (!(fb_helper->funcs->initial_config && |
| 1530 | fb_helper->funcs->initial_config(fb_helper, crtcs, modes, | 1603 | fb_helper->funcs->initial_config(fb_helper, crtcs, modes, |
| 1604 | offsets, | ||
| 1531 | enabled, width, height))) { | 1605 | enabled, width, height))) { |
| 1532 | memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0])); | 1606 | memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0])); |
| 1533 | memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0])); | 1607 | memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0])); |
| 1608 | memset(offsets, 0, dev->mode_config.num_connector*sizeof(offsets[0])); | ||
| 1534 | 1609 | ||
| 1535 | if (!drm_target_cloned(fb_helper, | 1610 | if (!drm_target_cloned(fb_helper, modes, offsets, |
| 1536 | modes, enabled, width, height) && | 1611 | enabled, width, height) && |
| 1537 | !drm_target_preferred(fb_helper, | 1612 | !drm_target_preferred(fb_helper, modes, offsets, |
| 1538 | modes, enabled, width, height)) | 1613 | enabled, width, height)) |
| 1539 | DRM_ERROR("Unable to find initial modes\n"); | 1614 | DRM_ERROR("Unable to find initial modes\n"); |
| 1540 | 1615 | ||
| 1541 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", | 1616 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", |
| @@ -1555,18 +1630,23 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
| 1555 | for (i = 0; i < fb_helper->connector_count; i++) { | 1630 | for (i = 0; i < fb_helper->connector_count; i++) { |
| 1556 | struct drm_display_mode *mode = modes[i]; | 1631 | struct drm_display_mode *mode = modes[i]; |
| 1557 | struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; | 1632 | struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; |
| 1633 | struct drm_fb_offset *offset = &offsets[i]; | ||
| 1558 | modeset = &fb_crtc->mode_set; | 1634 | modeset = &fb_crtc->mode_set; |
| 1559 | 1635 | ||
| 1560 | if (mode && fb_crtc) { | 1636 | if (mode && fb_crtc) { |
| 1561 | DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", | 1637 | DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n", |
| 1562 | mode->name, fb_crtc->mode_set.crtc->base.id); | 1638 | mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y); |
| 1563 | fb_crtc->desired_mode = mode; | 1639 | fb_crtc->desired_mode = mode; |
| 1640 | fb_crtc->x = offset->x; | ||
| 1641 | fb_crtc->y = offset->y; | ||
| 1564 | if (modeset->mode) | 1642 | if (modeset->mode) |
| 1565 | drm_mode_destroy(dev, modeset->mode); | 1643 | drm_mode_destroy(dev, modeset->mode); |
| 1566 | modeset->mode = drm_mode_duplicate(dev, | 1644 | modeset->mode = drm_mode_duplicate(dev, |
| 1567 | fb_crtc->desired_mode); | 1645 | fb_crtc->desired_mode); |
| 1568 | modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; | 1646 | modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; |
| 1569 | modeset->fb = fb_helper->fb; | 1647 | modeset->fb = fb_helper->fb; |
| 1648 | modeset->x = offset->x; | ||
| 1649 | modeset->y = offset->y; | ||
| 1570 | } | 1650 | } |
| 1571 | } | 1651 | } |
| 1572 | 1652 | ||
| @@ -1583,6 +1663,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
| 1583 | out: | 1663 | out: |
| 1584 | kfree(crtcs); | 1664 | kfree(crtcs); |
| 1585 | kfree(modes); | 1665 | kfree(modes); |
| 1666 | kfree(offsets); | ||
| 1586 | kfree(enabled); | 1667 | kfree(enabled); |
| 1587 | } | 1668 | } |
| 1588 | 1669 | ||
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index f2183b554cbc..850cf7d6578c 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c | |||
| @@ -324,6 +324,7 @@ intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc) | |||
| 324 | static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | 324 | static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, |
| 325 | struct drm_fb_helper_crtc **crtcs, | 325 | struct drm_fb_helper_crtc **crtcs, |
| 326 | struct drm_display_mode **modes, | 326 | struct drm_display_mode **modes, |
| 327 | struct drm_fb_offset *offsets, | ||
| 327 | bool *enabled, int width, int height) | 328 | bool *enabled, int width, int height) |
| 328 | { | 329 | { |
| 329 | struct drm_device *dev = fb_helper->dev; | 330 | struct drm_device *dev = fb_helper->dev; |
| @@ -332,6 +333,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
| 332 | bool fallback = true; | 333 | bool fallback = true; |
| 333 | int num_connectors_enabled = 0; | 334 | int num_connectors_enabled = 0; |
| 334 | int num_connectors_detected = 0; | 335 | int num_connectors_detected = 0; |
| 336 | uint64_t conn_configured = 0, mask; | ||
| 337 | int pass = 0; | ||
| 335 | 338 | ||
| 336 | save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), | 339 | save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), |
| 337 | GFP_KERNEL); | 340 | GFP_KERNEL); |
| @@ -339,7 +342,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
| 339 | return false; | 342 | return false; |
| 340 | 343 | ||
| 341 | memcpy(save_enabled, enabled, dev->mode_config.num_connector); | 344 | memcpy(save_enabled, enabled, dev->mode_config.num_connector); |
| 342 | 345 | mask = (1 << fb_helper->connector_count) - 1; | |
| 346 | retry: | ||
| 343 | for (i = 0; i < fb_helper->connector_count; i++) { | 347 | for (i = 0; i < fb_helper->connector_count; i++) { |
| 344 | struct drm_fb_helper_connector *fb_conn; | 348 | struct drm_fb_helper_connector *fb_conn; |
| 345 | struct drm_connector *connector; | 349 | struct drm_connector *connector; |
| @@ -349,12 +353,19 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
| 349 | fb_conn = fb_helper->connector_info[i]; | 353 | fb_conn = fb_helper->connector_info[i]; |
| 350 | connector = fb_conn->connector; | 354 | connector = fb_conn->connector; |
| 351 | 355 | ||
| 356 | if (conn_configured & (1 << i)) | ||
| 357 | continue; | ||
| 358 | |||
| 359 | if (pass == 0 && !connector->has_tile) | ||
| 360 | continue; | ||
| 361 | |||
| 352 | if (connector->status == connector_status_connected) | 362 | if (connector->status == connector_status_connected) |
| 353 | num_connectors_detected++; | 363 | num_connectors_detected++; |
| 354 | 364 | ||
| 355 | if (!enabled[i]) { | 365 | if (!enabled[i]) { |
| 356 | DRM_DEBUG_KMS("connector %s not enabled, skipping\n", | 366 | DRM_DEBUG_KMS("connector %s not enabled, skipping\n", |
| 357 | connector->name); | 367 | connector->name); |
| 368 | conn_configured |= (1 << i); | ||
| 358 | continue; | 369 | continue; |
| 359 | } | 370 | } |
| 360 | 371 | ||
| @@ -373,6 +384,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
| 373 | DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n", | 384 | DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n", |
| 374 | connector->name); | 385 | connector->name); |
| 375 | enabled[i] = false; | 386 | enabled[i] = false; |
| 387 | conn_configured |= (1 << i); | ||
| 376 | continue; | 388 | continue; |
| 377 | } | 389 | } |
| 378 | 390 | ||
| @@ -400,8 +412,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
| 400 | 412 | ||
| 401 | /* try for preferred next */ | 413 | /* try for preferred next */ |
| 402 | if (!modes[i]) { | 414 | if (!modes[i]) { |
| 403 | DRM_DEBUG_KMS("looking for preferred mode on connector %s\n", | 415 | DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n", |
| 404 | connector->name); | 416 | connector->name, connector->has_tile); |
| 405 | modes[i] = drm_has_preferred_mode(fb_conn, width, | 417 | modes[i] = drm_has_preferred_mode(fb_conn, width, |
| 406 | height); | 418 | height); |
| 407 | } | 419 | } |
| @@ -444,6 +456,12 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
| 444 | modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :""); | 456 | modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :""); |
| 445 | 457 | ||
| 446 | fallback = false; | 458 | fallback = false; |
| 459 | conn_configured |= (1 << i); | ||
| 460 | } | ||
| 461 | |||
| 462 | if ((conn_configured & mask) != mask) { | ||
| 463 | pass++; | ||
| 464 | goto retry; | ||
| 447 | } | 465 | } |
| 448 | 466 | ||
| 449 | /* | 467 | /* |
