#! /usr/bin/perl -w
use strict;

#
# $Id: init_card_9_29 3793 2008-02-04 23:00:48Z tzafrir $
#

#
# Written by Oron Peled <oron@actcom.co.il>
# Copyright (C) 2007, Xorcom
#
# All rights reserved.
#
# 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;	either version 2 of the License, or
# (at your option) any later version.
#
# See the file LICENSE in the top level of this tarball.
#

# This script is run from the xpp kernel module upon detection
# of a new XPD.
#
# Expects the following environment variables to be set:
#	XPD_BUS		- bus name
#	XBUS_CONNECTOR	- bus connector id string
#	XPD_NAME	- xpd name
#	XPD_UNIT	- xpd unit number
#	XPD_TYPE	- xpd type number (from protocol reply):
#			3 - FXS
#			4 - FXO
#			6 - BRI_TE
#			7 - BRI_NT
#			8 - PRI_TE
#			9 - PRI_NT
#	XPD_REVISION	- xpd revision number
#
# Output data format:
#	- An optional comment start with ';' or '#' until the end of line
#	- Optional Blank lines are ignored
#	- Fields are whitespace separated (spaces or tabs)
#
# The fields are (in command line order):
#	1. CHIP select in decimal (ignored, taken from 3 LSB's of subunit number)
#	2. Command word:
#		- RD	Read Direct register.
#		- WD	Write Direct register.
#	3. Register number in hexadecimal.
#	4. Subregister number in hexadecimal. (for RS and WS commands).
#	5. Data byte in hexadecimal. (for WD and WS commands only).
#

package main;
use File::Basename;

my $program = basename("$0");
my $init_dir = dirname("$0");
my $unit_id;

sub logit {
	print STDERR "$unit_id: @_\n";
}

# Arrange for error logging
if (-t STDERR) {
	$unit_id = 'Interactive';
	logit "Interactive startup\n";
} else {
	$unit_id = "$ENV{XPD_BUS}/$ENV{XPD_NAME}";
	open (STDERR, "| logger -t $program -p kern.info") || die;
	logit "Non Interactive startup\n";
}

package PRI;

sub gen {
	my $fmt = shift;
	$| = 1;
	printf "$fmt\n", @_;
}

package PRI::Port;

sub new {
	my $pack = shift;
	my $port = { @_ };
	bless $port, $pack;
}

package main;
use Getopt::Std;
BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
use Zaptel::Config::Defaults;

my %opts;
getopts('o:', \%opts);

$ENV{XPP_BASE} = '/proc/xpp';
#my $cmd = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/command";
my $output;
if ($opts{o}) {
	$output = $opts{o};
} else {
	$ENV{XPD_BUS} || die "Missing XPD_BUS environment variable\n";
	$ENV{XPD_NAME} || die "Missing XPD_NAME environment variable\n";
	$ENV{XPD_TYPE} || die "Missing XPD_TYPE environment variable\n";
	$ENV{XPD_REVISION} || die "Missing XPD_REVISION environment variable\n";
	$ENV{XBUS_CONNECTOR} || die "Missing XBUS_CONNECTOR environment variable\n";
	$output = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/$ENV{XPD_NAME}/slics";
}

sub write_pri_info {
	my $pri_type = shift || die "Missing pri_type parameter";
	my $pri_proto = shift || die "Missing pri_proto parameter";
	my $info = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/$ENV{XPD_NAME}/pri_info";	

	open(INFO, ">$info") || die "Failed to open '$info': $!\n";
	print INFO "$pri_type $pri_proto\n" || die "Failed writing to '$info': $!\n";
	close INFO || die "Failed during close of '$info': $!\n";
}

my @PRI_SETUP;

sub set_defaults {
	my @pri_specs;
	my $match;
	my $setup;
	# For lab tests
	my $labfile = "${0}.setup";

	# Source default files
	$ENV{ZAPTEL_DEFAULTS} = "$labfile" if -r "$labfile";
	my $setup_var = 'XPP_PRI_SETUP';
	my $setup_string;
	my ($default_file, %source_defaults) =
		Zaptel::Config::Defaults::source_vars($setup_var);
	$setup_string = $source_defaults{$setup_var};
	$setup_string =~ s/^\s+//;		# trim
	$setup_string =~ s/\s+$//;		# trim
	$setup_string =~ s/\s+/\n/g;		# cannonical spaces
	logit "From $default_file: $setup_var=\n$setup_string\n";
	@pri_specs = split(/\s+/, $setup_string);
	push(@pri_specs, 'NUM/*=TE,E1');	# Fall back default (last)
	logit "pri_specs: @pri_specs";
SPEC:
	for(my $i = 0; $i < @pri_specs; $i++) {
		my $spec = $pri_specs[$i];
		($match, $setup) = split(/=/, $spec);
		next unless defined $match and defined $setup;
		# Convert "globs" to regex
		$match =~ s/\*/.*/g;
		$match =~ s/\?/./g;
		#logit "match: $match";
		my @patlist = (
			"CONNECTOR/$ENV{XBUS_CONNECTOR}/$ENV{XPD_NAME}",
			"NUM/$ENV{XPD_BUS}/$ENV{XPD_NAME}"
			);
		foreach my $pattern (@patlist) {
			#logit "testmatch: $pattern =~ $match";
			if($pattern =~ $match) {
				logit "MATCH($i): '$match' setup=$setup";
				last SPEC;
			}
		}
	}
	die "No setup matching $ENV{XPD_BUS}/$ENV{XPD_NAME}\n" unless defined $setup;
	@PRI_SETUP = split(/,/, $setup);
	die "Bad setup string '$setup'\n" unless @PRI_SETUP;
}

set_defaults;

open(REG, ">$output") || die "Failed to open '$output': $!\n";
select REG;

logit "Starting '$0'";

PRI::gen "#--------------------------- start";

# only one of the following loopbacks can be activated in the same time 
my $LIM1_RL  = 0 << 1; 	# RL  (Remote  Loopback)
my $lim1 = 0xB0 | $LIM1_RL;

my $subunits_num = 4;
my $subunit      = $ENV{XPD_SUBUNIT};

if($subunit eq 0) {
	# Tuning of clocking unit to the 16.384 MHz reference frequence
	# by setting Global Clock Mode registers (GCM[1:8]), same for E1 and T1/J1
	PRI::gen "0 WD 92 00"; 		# GCM1
	PRI::gen "0 WD 93 18";		# GCM2
	PRI::gen "0 WD 94 FB";		# GCM3
	PRI::gen "0 WD 95 0B";		# GCM4
	PRI::gen "0 WD 96 01";		# GCM5
	PRI::gen "0 WD 97 0B";		# GCM6
	PRI::gen "0 WD 98 DB";		# GCM7
	PRI::gen "0 WD 99 DF";		# GCM8
	
	for(my $i = 0; $i < $subunits_num; $i++) {
		PRI::gen "0 WS 26 $i BD"; 	# XPM0: Pulse Shape Programming for R1=18Ohms (0x54)
		PRI::gen "0 WS 27 $i 03"; 	# XPM1: ...3V Pulse Level at the line         (0x02)
		PRI::gen "0 WS 28 $i 00"; 	# XPM2: ~XLT (transmit line is not in the high impedance state)

						# if (unchannelized)
		#PRI::gen "0 WS 1F $i 22";	# LOOP (Channel Looback): 
						#      ECLB (Enable Channel Loop-Back) 
						#      CLA  (Channel Address)
		PRI::gen "0 WS 2B $i EF";	# IDL (Idle): 
						#      If channel loopback is enabled than transmit this code on the outgoing
		PRI::gen "0 WS 1F $i 00";	# LOOP (Channel Looback): 
		#if($i eq 0){ 
		#	PRI::gen "0 WS 1F $i 00";	# LOOP (Channel Looback): 
		#				#      channels (XL1/XL2)
		#}else { 
		#	PRI::gen "0 WS 1F $i 20";	# LOOP (Channel Looback): 
		#}

		PRI::gen "0 WS 37 $i %02X", $lim1;
					 	# LIM1: ~RL (Remote Loop bit 0x02),
						#       ~DRS (Dual Rail Select, latch receive data while trasmit),
						#       RIL1, RIL0 (Receive Input Treshold 0.62 V),
						#       CLOS (Clear data in case of LOS)
		PRI::gen "0 WS 3A $i 20";	# LIM2: SLT1, SLT0 = 01 
						#            (Receiver Slicer Threshold, the receive slicer 
						#             generates a mark (digital one) if the voltage at
						#             RL1/2 exceeds 50% of the peak amplitude,
						#             default, recommended in E1 mode).
		  
		PRI::gen "0 WS 38 $i 0A"; 	# PCD: (Pulse Count Detection, LOS Detection after 176 consecutive 0s)
		PRI::gen "0 WS 39 $i 15"; 	# PCR: (Pulse Count Recovery, LOS Recovery after 22 ones in PCD interval)

		# Configure system interface
		PRI::gen "0 WS 3E $i C2";	# SIC1: SSC1 (System clock    ) is 8.192 Mhz, 
						#       SSD1 (System Data rate) is 8.192 Mbit/s,
						#	~BIM (Byte interleaved mode),
						#	XBS  (Transmit Buffer Size) is 2 frames
		PRI::gen "0 WS 40 $i 04";	# SIC3: Edges for capture, Synchronous Pulse Receive @Rising Edge
		PRI::gen "0 WS 41 $i 04";	# CMR4: RCLK is 8.192 MHz
		PRI::gen "0 WS 43 $i 04";	# CMR5: TCLK is 8.192 MHz
		PRI::gen "0 WS 44 $i 34";	# CMR6: Receive reference clock generated by channel 1,
						#       RCLK is at 8.192 Mhz dejittered, Clock recovered from the line
						#       TCLK is at 8.192 MHz is de-jittered by DCO-R to drive a6.176 MHz 
						#       clock on RCLK.*/

		PRI::gen "0 WS 20 $i 9F"; 	# XSW: XSIS (Spare Bit For International Use fixed to 1),
						#      XY0, XY1, XY2, XY3, XY4 (Y0, Y1 and Y3-Bits fixed to 1)

						#  	cas = 0x1c;
						#	if (!(lineconfig & ZT_CONFIG_CCS))
						#		cas |= 0x40;

		PRI::gen "0 WS 22 $i 00"; 	# XC0: (Transmit Counter Offset = 497/T=2)
		PRI::gen "0 WS 23 $i 04"; 	# XC1: 

		PRI::gen "0 WS 24 $i 00"; 	# RC0: (Receive  Counter Offset = 497/T=2)
		PRI::gen "0 WS 25 $i 05"; 	# RC1: 

		my $sic2 = sprintf("%x", 0x00 | ($i << 1));

		PRI::gen "0 WS 3F $i $sic2";	# SIC2: No FFS, no center receive elastic buffer, data active at phase ($sic >> 1)
			
		# enable the following interrupt sources
		PRI::gen "0 WS 16 $i 00"; 	# IMR2 (Interrupt Mask Register2): Enable ALL
			
		PRI::gen "0 WS 17 $i 3F"; 	# IMR3 ~ES, ~SEC (Enable ES and SEC interrupts)
		PRI::gen "0 WS 18 $i 00"; 	# IMR4: Enable ALL

		PRI::gen "0 WS 08 $i 04";	# IPC: SYNC is 8 Khz

		PRI::gen "0 WS 02 $i 51"; 	# CMDR (Command Register): RRES, XRES, SRES (Receiver/Transmitter reset)
		PRI::gen "0 WS 02 $i 00"; 	# CMDR


		#  Configure interrupts
		PRI::gen "0 WS 46 $i 40";	# GCR: Interrupt on Activation/Deactivation of AIX, LOS
									
		PRI::gen "0 WS 45 $i 00";	# CMR2: External sources for SYPR, SCLKR, SYPX, SCLKX for TX and RX.
		#PRI::gen "0 WS 22 $i 00";	# XC0: Normal operation of Sa-bits
		#PRI::gen "0 WS 23 $i 04";	# XC1: X=4  => T=4-X=0 offset
		#PRI::gen "0 WS 24 $i 00";	# RC0: 0 offset
		#PRI::gen "0 WS 25 $i 00";	# RC1: Remaining part of RC0

		#  Configure ports
		PRI::gen "0 WD 85 80";		# GPC1 (Global Port Configuration 1):
		#PRI::gen "0 WD 85 00";		# GPC1 (Global Port Configuration 1):
									#      SMM (System Interface Multiplex Mode)
		PRI::gen "0 WS 80 $i 00";	# PC1: SYPR/SYPX provided to RPA/XPA inputs

		PRI::gen "0 WS 84 $i 31";	# PC5: XMFS active low, SCLKR is input, RCLK is output (unused)
		PRI::gen "0 WS 86 $i 03";	# PC6: CLK1 is Tx Clock output, CLK2 is 8.192 Mhz from DCO-R
		PRI::gen "0 WS 3B $i 00";	# Clear LCR1 - Loop Code Register 1

		#  printk("TE110P: Successfully initialized serial bus for card\n");

		# Initialize PCM and SIG regs
		PRI::gen "0 WS A0 $i 00";	# TSEO (Time Slot Even/Odd Select) 
		PRI::gen "0 WS A1 $i FF";	# TSBS (Time Slot Bit Select)- only selected bits are used for HDLC channel 1
						#      in selected time slots
		PRI::gen "0 WS 03 $i 89";	# Mode Register:
						#      MDS  (Mode Select) = 100 (No address comparison)
						#      HRAC (Receiver Active - HDLC channel 1) 
						#      RFT2 (HDLC Receive FIFO is 64 byte deep)
		PRI::gen "0 WS 09 $i 18";	# CCR1 (Common Configuration Register1)
						#      EITS (Enable Internal Time Slot 0 to 31 Signalling)
						#      ITF  (Interframe Time Fill)
		PRI::gen "0 WS 0A $i 04";	# CCR2 (Common Configuration Register2)
						#      RCRC (enable CRC - HDLC channel 1enable CRC - HDLC channel 1)
		PRI::gen "0 WS 0C $i 00";	# RTR1 (Receive  Time Slot register 1)
		PRI::gen "0 WS 0D $i 00";	# RTR2 (Receive  Time Slot register 2)
		PRI::gen "0 WS 0E $i 00";	# RTR3 (Receive  Time Slot register 3), TS16 (Enable time slot 16) 
		PRI::gen "0 WS 0F $i 00";	# RTR4 (Receive  Time Slot register 4)

		PRI::gen "0 WS 10 $i 00";	# TTR1 (Transmit Time Slot register 1)
		PRI::gen "0 WS 11 $i 00";	# TTR2 (Transmit Time Slot register 2)
		PRI::gen "0 WS 12 $i 00";	# TTR3 (Transmit Time Slot register 3), TS16 (Enable time slot 16) 
		PRI::gen "0 WS 13 $i 00";	# TTR4 (Transmit Time Slot register 4)

		# configure the best performance of the Bipolar Violation detection for all four channels
		PRI::gen "0 WS BD $i 00";	# BFR (Bugfix Register): ~BVP (Bipolar Violations),
						#                         use Improved Bipolar Violation Detection instead
	}
	PRI::gen "0 WD BB FF"; 		# REGFP
	PRI::gen "0 WD BC AC"; 		# REGFD
	PRI::gen "0 WD BB 2B"; 		# REGFP
	PRI::gen "0 WD BC 00"; 		# REGFD
	PRI::gen "0 WD BB AB"; 		# REGFP
	PRI::gen "0 WD BC 2A"; 		# REGFD
	PRI::gen "0 WD BB FF"; 		# REGFP
	PRI::gen "0 WD BC AA"; 		# REGFD
	PRI::gen "0 WD BB 29"; 		# REGFP
	PRI::gen "0 WD BC FF"; 		# REGFD
	PRI::gen "0 WD BB A9"; 		# REGFP
	PRI::gen "0 WD BC 28"; 		# REGFD
	PRI::gen "0 WD BB 00"; 		# REGFP
	PRI::gen "0 WD BC A8"; 		# REGFD
	PRI::gen "0 WD BB 27"; 		# REGFP
	PRI::gen "0 WD BC FF"; 		# REGFD
	PRI::gen "0 WD BB A7"; 		# REGFP
	PRI::gen "0 WD BC 00"; 		# REGFD

#	PRI::gen "0 WS 80 00 00"; 	# PC1 (Port configuration 1): RPB_1.SYPR           , XPB_1.SYPX
	PRI::gen "0 WS 81 00 0B"; 	# PC2 (Port configuration 2): RPB_1.GPOH (ResetID ), XPB_1.GPOL (MUX_SEL0)
	PRI::gen "0 WS 82 00 9B"; 	# PC3 (Port configuration 3): RPC_1.GPI  (nConfig0), XPC_1.GPOL (MUX_SEL1)
	PRI::gen "0 WS 83 00 9B"; 	# PC4 (Port configuration 4): RPD_1.GPI  (nConfig1), XPD_1.GPOL (MUX_SEL2)
}

 
#------------------------------------------- Instance detection

logit "Ending '$0'";

close REG;

write_pri_info @PRI_SETUP;

close STDERR;
exit 0;
