#!/bin/sh

set -e

# This is a nasty kluge, but it seems to work. Better check the output when
# upgrading to a new release of the nvidia driver, though.

# Whenever a PCI ID is supported by both nvidia and nvidia_legacy, it is only
# listed for nvidia, as long as nvidia_legacy is *after* nvidia in the
# parameter list.

[ -n "$1" ] || {
  echo "USAGE: $0 path/to/nv/nv-kernel.o nvidia \\" >&2
  echo "    path/to/nv-legacy/nv-kernel.o nvidia_legacy [...]" >&2
  exit 1
}

echo "# Listing generated by nvidia_supported. Do not edit manually."

device_ids() {
  local filename="$1"

  local list_prev="$(mktemp)"
  local list_cur="$(mktemp)"

  # Find the symbols of the .rodata section...
  objdump --section=.rodata --syms "$filename" |
  sed -nr '/SYMBOL TABLE/,/^$/ {
    s/^([0-9a-f]+)\s+l\s+O\s+\S+\s+([0-9a-f]+)\s+\S+.*/\1 \2/p
  }' |
  while read start length; do
    objdump --section=.rodata --full-contents \
      --start-address="0x$start" \
      --stop-address="$((0x$start+0x$length))" "$filename" |
    sed -nr 's/^ [0-9a-f]+ ([0-9a-f]{2})([0-9a-f]{2}).*/\2\1/p' |
    sort | uniq | grep -vx "0000" >"$list_cur"

    # The consistent thing between different releases has been that there are
    # two subsequent symbols with the same PCI ID list near the beginning. Find
    # them.
    if [ -s "$list_prev" -a -s "$list_cur" ] &&
       cmp -s "$list_prev" "$list_cur"; then
      cat "$list_cur"
      break
    fi

    cp "$list_cur" "$list_prev"
  done

  rm -f "$list_prev" "$list_cur"
}

seen_ids=' '

while [ -n "$1" ]; do
  filename="$1"; shift
  modname="$1";  shift

  orig_ids="$(device_ids "$filename")"
  if [ -z "$orig_ids" ]; then
    echo "WARNING: No IDs were found from $filename" >&2
  fi

  for id in $orig_ids; do
    case "$seen_ids" in
      *" $id "*)
        # Already seen the ID.
        ;;
      *)
        # Not seen it yet.
        seen_ids="${seen_ids}${id} "

        printf "alias pci:v%08Xd%08Xsv*sd*bc03sc*i* %s\n" \
          0x10de "0x$id" "$modname"
        ;;
    esac
  done
done | sort

# vim:set et sw=2 sts=2:
