/* * Thunderbolt Cactus Ridge driver - capabilities lookup * * Copyright (c) 2014 Andreas Noever */ #include #include #include "tb.h" struct tb_cap_any { union { struct tb_cap_basic basic; struct tb_cap_extended_short extended_short; struct tb_cap_extended_long extended_long; }; } __packed; static bool tb_cap_is_basic(struct tb_cap_any *cap) { /* basic.cap is u8. This checks only the lower 8 bit of cap. */ return cap->basic.cap != 5; } static bool tb_cap_is_long(struct tb_cap_any *cap) { return !tb_cap_is_basic(cap) && cap->extended_short.next == 0 && cap->extended_short.length == 0; } static enum tb_cap tb_cap(struct tb_cap_any *cap) { if (tb_cap_is_basic(cap)) return cap->basic.cap; else /* extended_short/long have cap at the same offset. */ return cap->extended_short.cap; } static u32 tb_cap_next(struct tb_cap_any *cap, u32 offset) { int next; if (offset == 1) { /* * The first pointer is part of the switch header and always * a simple pointer. */ next = cap->basic.next; } else { /* * Somehow Intel decided to use 3 different types of capability * headers. It is not like anyone could have predicted that * single byte offsets are not enough... */ if (tb_cap_is_basic(cap)) next = cap->basic.next; else if (!tb_cap_is_long(cap)) next = cap->extended_short.next; else next = cap->extended_long.next; } /* * "Hey, we could terminate some capability lists with a null offset * and others with a pointer to the last element." - "Great idea!" */ if (next == offset) return 0; return next; } /** * tb_find_cap() - find a capability * * Return: Returns a positive offset if the capability was found and 0 if not. * Returns an error code on failure. */ int tb_find_cap(struct tb_port *port, enum tb_cfg_space space, enum tb_cap cap) { u32 offset = 1; struct tb_cap_any header; int res; int retries = 10; while (retries--) { res = tb_port_read(port, &header, space, offset, 1); if (res) { /* Intel needs some help with linked lists. */ if (space == TB_CFG_PORT && offset == 0xa && port->config.type == TB_TYPE_DP_HDMI_OUT) { offset = 0x39; continue; } return res; } if (offset != 1) { if (tb_cap(&header) == cap) return offset; if (tb_cap_is_long(&header)) { /* tb_cap_extended_long is 2 dwords */ res = tb_port_read(port, &header, space, offset, 2); if (res) return res; } } offset = tb_cap_next(&header, offset); if (!offset) return 0; } tb_port_WARN(port, "run out of retries while looking for cap %#x in config space %d, last offset: %#x\n", cap, space, offset); return -EIO; } e='search'/>
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@s-opensource.com>2016-12-15 08:38:35 -0200
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2016-12-15 08:38:35 -0200
commit65390ea01ce678379da32b01f39fcfac4903f256 (patch)
tree7f849d66121533c331cf61136b124218d87cbf86 /include/trace
parente7aa8c2eb11ba69b1b69099c3c7bd6be3087b0ba (diff)
parentd183e4efcae8d88a2f252e546978658ca6d273cc (diff)
Merge branch 'patchwork' into v4l_for_linus
* patchwork: (496 commits) [media] v4l: tvp5150: Add missing break in set control handler [media] v4l: tvp5150: Don't inline the tvp5150_selmux() function [media] v4l: tvp5150: Compile tvp5150_link_setup out if !CONFIG_MEDIA_CONTROLLER [media] em28xx: don't store usb_device at struct em28xx [media] em28xx: use usb_interface for dev_foo() calls [media] em28xx: don't change the device's name [media] mn88472: fix chip id check on probe [media] mn88473: fix chip id check on probe [media] lirc: fix error paths in lirc_cdev_add() [media] s5p-mfc: Add support for MFC v8 available in Exynos 5433 SoCs [media] s5p-mfc: Rework clock handling [media] s5p-mfc: Don't keep clock prepared all the time [media] s5p-mfc: Kill all IS_ERR_OR_NULL in clocks management code [media] s5p-mfc: Remove dead conditional code [media] s5p-mfc: Ensure that clock is disabled before turning power off [media] s5p-mfc: Remove special clock rate management [media] s5p-mfc: Use printk_ratelimited for reporting ioctl errors [media] s5p-mfc: Set DMA_ATTR_ALLOC_SINGLE_PAGES [media] vivid: Set color_enc on HSV formats [media] v4l2-tpg: Init hv_enc field with a valid value ...
Diffstat (limited to 'include/trace')