#!/usr/bin/perl -w

# (c) 2007 Jan-Marek Glogowski <glogow@fbihome.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

use strict;
use warnings;

use Config::IniFiles;

print << "EOF";
/**
 * This file was generated from the ini files of
 *
EOF

open( VERSION, "<../Version.txt" ) || die( "Couldn't open ../Version.txt: $!\n" );
while( <VERSION> ) {
  print " * $_";
}
close( VERSION );

print << "EOF";
 **/

#ifndef PATCH_SIGMATEL_DELL_H
#define PATCH_SIGMATEL_DELL_H

EOF

my $cfg = Config::IniFiles->new( -file => 'Sthda.ini' );

my @models = $cfg->Parameters( 'Models' );

my %subini_models;
my %subini_enum; # ini -> enum
my %enum_subini; # enum -> ini

# Map to nid "hash" to alsa table names
my %nid_function_map = (
	'0x080x090x0d0x0e0x0f0x100x110x12' => '9200',
	'0x0a0x0b0x0c0x0d0x0e0x0f0x140x160x170x180x210x22' => '9205',
	'0x0a0x0b0x0c0x0d0x0e0x0f0x100x110x150x1b' => '922x',
);

# Parse models in main driver.ini
foreach my $model (@models)
{
	next if( 'DEFAULT' eq $model );

	my $arrayref;
	my $subini = $cfg->val( 'Models', $model );
	if( ! exists $subini_models{ $subini } ) {
		my @tmparray = ();
		$subini_models{ $subini } = \@tmparray;
	}
	$arrayref = $subini_models{ $subini };

	if( $model =~ m/VEN_(....)&DEV_(....)&SUBSYS_(....)(....)$/ ) {
		my %id = ();
		$id{ 'vendor' } = lc( $1 );
		$id{ 'device' } = lc( $2 );
		$id{ 'subvendor' } = lc( $3 );
		$id{ 'subdevice' } = lc( $4 );
		push( @$arrayref, \%id );
	}
}

# Generate enum from INI values of models
foreach my $ini (sort keys %subini_models) {
	my $enum;
	if( $ini =~ /^92XX(..)-(.)\.INI/i ) { 
		$enum = "STAC_92XX_DELL_${1}${2}";
	}
	elsif( $ini =~ /^NOM_(..)-(.)\.INI/i ) {
		$enum = "STAC_92XX_DELL_NOM_${1}${2}";
	}
	else { next; }
	$subini_enum{ $ini } = $enum;
	$enum_subini{ $enum } = $ini;
}

my %nid_configs;

# Open sub INIs to get pins
foreach my $ini (sort keys %subini_models) {
	my $subcfg = Config::IniFiles->new( -file => $ini, -allowsingles => 1 );
	if( ! defined $subcfg ) {
		print( "Error reading '$ini'\n" . join( "\n  ", @Config::IniFiles::errors ) . "\n" );
		next;
	}
	my @sections = $subcfg->Sections();
	my %pins;

	# Extract pins
	foreach my $section (@sections) {
		if( $section =~ /^HKR\\Settings\\pin\\(.*)$/i ) {
			my $pin = lc( "0x$1" );
			my $confval = $subcfg->val( $section, 'CfgDflt' );
			$confval =~ s/^ *//;
			$confval =~ s/ *$//;
			if( $confval =~ /^dword: (0x.{8})$/ ) {
				$pins{ $pin } = lc( $1 );
			}
			else { print( "Error: '$confval'\n" ); }
		}
	}

	if( 0 == scalar keys %pins ) {
		print( "Couln't extract pin config from '$ini'\n" );
		next;
	}

	# Generate nid tables - catches dups
	my $nids_hash = join( '', sort keys %pins );
	my $model_config;
	if( ! exists $nid_configs{ $nids_hash } ) {
		my %new_config = ();
		$nid_configs{ $nids_hash } = \%new_config;
		my $nid_name = lc( $subini_enum{ $ini } );
		if( exists $nid_function_map{ $nids_hash } ) {
			$nid_name = "stac" . $nid_function_map{ $nids_hash };
			$new_config{ 'DEFAULT' } = $nids_hash;
		}
		else { $new_config{ 'DEFAULT' } = $nid_name; }
		print( "// perl nid hash: $nids_hash\n" );
		print( "// matches to: $nid_name\n" );
		print( "static hda_nid_t " . $nid_name 
			. '_pin_nids[' . scalar keys( %pins ) . '] = {' );
		my $i = 0;
		for my $pin (sort keys %pins) {
			print( "\n\t" ) if( 0 == $i % 5 );
			print( "$pin,       " );
			$i++;
		}
		print( "\n};\n\n" );
	}

	$model_config = $nid_configs{ $nids_hash };
	my @config = map( $pins{ $_ }, sort keys %pins );

	# If nid "hash" matches alsa table rename enums
	if( exists $nid_function_map{ $nids_hash } ) {
		my $enum = $subini_enum{ $ini };
		my $name = uc( $nid_function_map{ $nids_hash } );
		$enum =~ s/^STAC_92XX/STAC_$name/;
		$subini_enum{ $ini } = $enum;
		$enum_subini{ $enum } = $ini;
	}
	$model_config->{ $subini_enum{ $ini } } = \@config; 
}

# Write pin configs for all models
foreach my $nid (sort keys %nid_configs) {
	foreach my $model (sort keys %{$nid_configs{$nid}}) {
		next if( 'DEFAULT' eq $model );
		my $configs = $nid_configs{$nid}->{$model};
		print( "static unsigned int " . lc( $model )
			. '_pin_configs[' . scalar @$configs . '] = {' );
		my $i = 0;
		for my $config (@$configs) {
			print( "\n\t" ) if( 0 == $i % 5 );
			print( "$config, " );
			$i++;
		}
		print( "\n};\n\n" );
	}
}

# Write list of enums
foreach my $nid (sort keys %nid_configs) {
	my $nids = $nid_configs{$nid}->{'DEFAULT'};
	$nids = 'STAC_' . $nid_function_map{ $nids } . '_DELL'
		if( exists $nid_function_map{ $nids } );
	$nids = uc( $nids );
	print( "enum {\n" );
	foreach my $model (sort keys %{$nid_configs{$nid}}) {
		next if( 'DEFAULT' eq $model );
		print( "\t$model,\n" );
	}
	print( "\t${nids}_MODELS\n" );
	print( "};\n\n" );
}

# Write table of models per nid 
foreach my $nid (sort keys %nid_configs) {
	my $nids = $nid_configs{$nid}->{'DEFAULT'};
	$nids = 'STAC_' . $nid_function_map{ $nids } . '_DELL'
		if( exists $nid_function_map{ $nids } );
	$nids = uc( $nids );
	print( 'static unsigned int *' . lc( $nids )
		. "_brd_tbl[${nids}_MODELS] = {\n" );
	foreach my $model (sort keys %{$nid_configs{$nid}}) {
		next if( 'DEFAULT' eq $model );
		print( "\t[${model}] = " . lc($model) . "_pin_config,\n" );
	}
	print( "};\n\n" );
}

# Write quirk tables
foreach my $nid (sort keys %nid_configs) {
	my $nids = $nid_configs{$nid}->{'DEFAULT'};
	$nids = 'STAC_' . $nid_function_map{ $nids } . '_DELL'
		if( exists $nid_function_map{ $nids } );
	print( 'static struct snd_pci_quirk ' . lc( $nids )
		. "_cfg_tbl[] = {\n" );
	foreach my $model (sort keys %{$nid_configs{$nid}}) {
		next if( 'DEFAULT' eq $model );
		my $ini = $enum_subini{ $model };
		my $modelids = $subini_models{ $ini };
		for my $modelid (@$modelids) {
			print( "\tSND_PCI_QUIRK[PCI_VENDOR_ID_DELL, 0x" 
				. $modelid->{subdevice} . ",\n" 
				. "\t\t\t\"Unknown Dell\", ${model}),\n" );
		}
	}
	print( "};\n\n" );
}

print <<"EOF";
#endif

EOF

