/*
 * projectTxKernel.c
 *
 *  Created on: Apr 26, 2014
 *      Author: kab8c8
 *      Description:
 *      Abandoned code! For reference only.
 *      causes kernel panic and the board to lock until the watchdog timer resets the real time task in which the board appears to recover.
 *      references:
 *      Code from kernelnewbies did send out a packet, but caused randomly caused a kernel panic.
 *http://kernelnewbies.org/Simple_UDP_Server
 *http://stackoverflow.com/questions/18339174/sending-small-udp-packets-from-the-linux-kernel-to-loopback-wont-work-reliable
 */


#ifndef MODULE
#define MODULE
#endif

#ifndef __KERNEL__
#define __KERNEL__
#endif
#define MSG_SIZE 40			// message size. The messages will always be character arrays of size 40.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/in.h>
#include <net/sock.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/inet.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <rtai.h>
#include <rtai_sched.h>	// scheduler
#include <rtai_fifos.h>	// for FIFOs
#include <linux/time.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

#include <linux/errno.h>
#include <linux/types.h>

#include <linux/netdevice.h>
#include <linux/ip.h>
#include <linux/in.h>

#include <linux/delay.h>
MODULE_LICENSE("GPL");

/////////////////// added
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

#include <linux/errno.h>
#include <linux/types.h>

#include <linux/netdevice.h>
#include <linux/ip.h>
#include <linux/in.h>

#include <linux/delay.h>

//PortB0 is the LSB
//buttons are active LOW, so check for a low for a button press.
#define BTN0 ((portvalue & 0x01) == 0x00)	//PortB0 is button 0
#define BTN1 ((portvalue & 0x02) == 0x00)	//PortB1 is button 1
#define BTN2 ((portvalue & 0x04) == 0x00)	//PortB2 is button 2
#define BTN3 ((portvalue & 0x08) == 0x00)	//PortB0 is button 3
#define BTN4 ((portvalue & 0x10) == 0x00)	//PortB0 is button 4
#define RedOn *pBdr = *pBdr | 0x20; //turn on red LED on the sixth bit xx1x xxxx
#define RedOff  *pBdr = *pBdr & 0xFFFFFFDF; //turn off red LED         xx0x xxxx
#define YlwOn  *pBdr = *pBdr | 0x40; //turn on yellow LED              x1xx xxxx
#define YlwOff *pBdr = *pBdr & 0xFFFFFFBF; //turn off yellow LED       x0xx xxxx
#define GrnOn  *pBdr = *pBdr | 0x80; //turn on green LED               1xxx xxxx
#define GrnOff *pBdr = *pBdr & 0xFFFFFF7F; //turn off red LED          0xxx xxxx
#define AllLedOff *pBdr = *pBdr & 0xFFFFFF1F; //                       000x_xxxx
#define OnlyRedOn AllLedOff;  RedOn;
#define OnlyYlwOn AllLedOff;  YlwOn;
#define OnlyGrnOn AllLedOff;  GrnOn;

//#define KDEBUG
#ifdef  KDEBUG
#define KTRACE(x) x
#define TRACE(x) (x);
#define PRINT(x) printk(x); printk("\n") ;
#define KALEN(x) {(printk(x));  printk("\n");}
#else
#define KTRACE(x)
#define TRACE(x) ;
#define PRINT(x) ;
#define KALEN(x) ;
#endif

// RT task global variables, needed to destroy task.
static RT_TASK Rt_Task_Speaker_Forever, Rt_Task_watchdog;
#define HARDWARE_FIFO_TO_USER_SPACE 0
#define HARDWARE_IRQ 59
#define SOFTWARE_IRQ 63
#define SOFTWARE_FIFO_FROM_USER_SPACE 1
unsigned irq = 0;
#define REGS_BASE                    0x80000000
#define ep93xxSYSCON_BASE                 (REGS_BASE + 0x00930000)
#define DEVICECFG                   (ep93xxSYSCON_BASE + 0x0080)
#define SYSSWLOCK                   (ep93xxSYSCON_BASE + 0x00C0)
//xxx I added this to explicitly translate to user space memory.
//#include <asm-arm/proc-armv/uaccess.h>
#include <asm-arm/uaccess.h>
#include <linux/byteorder/generic.h>
//USING PORT NUMBER 2001, with host to net hardcoded because cannot use in kernel space.
//0x0915//2325
#define DEFAULT_PORT 0xD107
//0x0017//23 // port for sending the packet.
#define CONNECT_PORT 0xD107
#define MODULE_NAME "ksocket"
#define INADDR_SEND ((unsigned long int)0x1334030A) /*0x7f000001 127.0.0.1 "0x1334030A 10.3.52.19"*/
//0xD007; // port number 2000 TODO htons(atoi(argv[1])) WHERE 2000d == 0x07D0
//#define INADDR_SEND INADDR_LOOPBACK
/***********************************************************************************************************
 * *********************************************************************************************************
 2006/06/27 - Added ksocket_send, so, after receive a packet, the kernel send another back to the CONNECT_PORT
 - Rodrigo Rubira Branco <rodrigo@kernelhacking.com>

 2006/05/14 - Initial version
 - Toni Garcia-Navarro <topi@phreaker.net>
 */

struct timeval tPacket;
unsigned long watchDogTimer;
#define WATCHDOG_TIMER_THRESHOLD 10
struct kthread_t {
	//Not used.
	//struct task_struct *thread;
	//Not used.
	//struct socket *sock;
	//Not used.
	//struct sockaddr_in addr;
	//used for sending.
	struct socket *sock_send;
	//used for sending.
	struct sockaddr_in addr_send;
	//not used.
	//int running;
};
//global kthread used for kernel socket sending.
struct kthread_t *kthread = NULL;
int ksocket_send(struct socket *sock, struct sockaddr_in *addr, unsigned char *buf, int len);

static void ksocket_start(void) {

	memset(kthread, 0, sizeof(struct kthread_t));

	int err;
	int bufsize = MSG_SIZE;
	unsigned char buf[bufsize + 1];

	/* create a socket */
	if (((err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &kthread->sock_send)) < 0)) {
		printk(KERN_INFO MODULE_NAME": Could not create a datagram socket, error = %d\n", -ENXIO);
		//goto out;
		//kthread->thread = NULL;
		//kthread->running = 0;
		return;

	}

	memset(&kthread->addr_send, 0, sizeof(struct sockaddr));
	kthread->addr_send.sin_family = AF_INET;
	kthread->addr_send.sin_addr.s_addr = (INADDR_SEND);
	kthread->addr_send.sin_port = (CONNECT_PORT);

	//xxx sending need to make more modular to accept different commands to send.//
	memset(&buf, 0, bufsize+1);
	strcat(buf, "setup testing...");
	sprintf(buf, " %ld.%06ld", tPacket.tv_sec, tPacket.tv_usec);
	ksocket_send(kthread->sock_send, &kthread->addr_send, buf, strlen(buf));


	PRINT("start() finished\n");
}

int ksocket_send(struct socket *sock, struct sockaddr_in *addr, unsigned char *buf, int len) {
	PRINT("Message send attempt\n");

	struct msghdr msg;
	struct iovec iov;
	mm_segment_t oldfs;
	int size = 0;

	if (sock->sk == NULL){
		printk("Socket was not ready");
	return 0;
	}
	if (buf == NULL) {
		printk("buffer was empty\n");
		return 0;
	}

	iov.iov_base = buf;
	iov.iov_len = len;

	msg.msg_flags = 0;
	msg.msg_name = addr;
	msg.msg_namelen = sizeof(struct sockaddr_in);
	msg.msg_control = NULL;
	msg.msg_controllen = 0;
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = NULL;

	//translate from kernel space to user space to send the socket message.
	//but the request originates from this kernel module.
	oldfs = get_fs();
	set_fs(KERNEL_DS);
	size = sock_sendmsg(sock, &msg, len);
	set_fs(oldfs);
	PRINT("message sent\n");
	return size;
}

///////////////////added

//Global Period Variables
//RTC clock 32.768 kHz crystal,
//CPU clock 200 mhz?
//2273000 nano seconds period == 440.000 hz == A
//2024770 nano seconds period == 493.883 hz == B
//1911130 nano seconds period == 523.251 hz == C
//1702620 nano seconds period == 587.330 hz == D
//1516860 nano seconds period == 659.255 hz == E
//1431730 nano seconds period == 698.456 hz == F
//1275520 nano seconds period == 783.991 hz == G
// 100000 I wouldn't use anything below that.
RTIME period, A, B, C, D, E, periodArray[5];
unsigned int fifo = 0;
unsigned long *ptr; //Global holds pointer to mapped memory IO
unsigned long *pBdr; //Global port B data register
unsigned long *pBddr; //Global port B data Direction register
unsigned long *pFdr; //Global port F data register
unsigned long *pFddr; //Global port F Data Direction Register
//offsets to Software Interrupt Registers. = 0x800C_0010
//enable vector controlled interrupts. We use VIC1 controls interrupts 1-32, VIC2 controls interrupts 33-64.
unsigned long *VIC2IntEnable;
//offsets to Software Interrupt Clear Register. = 0x800C_001C
//Global clear software interrupt.
unsigned long *VIC2SoftIntClear;
//Software interrupt.
unsigned long * VIC2SoftInt;
unsigned long *port_B_end_of_interrupt; //end of interrupt register.
// Global GPIOBIntEn, the General Purpose I/O Interrupt Enable register for port B.
// 0x8084_00B8  GPIOBIntEn  Controls the generation of interrupts by the pins of Port B
// Turn on interrupts for the input pins for the buttons, but turn off interrupts for the output pins the led's.
// we must turn on/off individual bits to throw interrupt because it throws a single interrupt and the handler has to filter why it was thrown.
unsigned long *GPIOBIntEn;
//	Global 0x8084_00B4  GPIOBEOI  GPIO Port B End Of Interrupt Register. In order to clear the interrupt you have to write a 1 or zero to clear this bit to say that the interrupt should not be triggered the next time it is checked.
// end of interrupt flags, clear interrupt flags from any old random values.
unsigned long *GPIOBEOI;
//	Global You should also list the ep9301 registers that need to be modified to control interrupts on port B. http://vigir.ee.missouri.edu/~gdesouza/ece4220/Lab_Assignments/ts-7000_ep9301-ug.pdf p54
//	0x8084_00AC  GPIOBIntType1  Register controlling type, level or edge, of interrupt generated by the pins of Port B
// These 5 buttons should trigger interrupt on falling edge.
unsigned long *GPIOBIntType1;
//	Global 0x8084_00B0  GPIOBIntType2  Register controlling polarity, high/low or rising/falling, of interrupt generated by Port B
//  These five buttons should trigger interrupt on falling edge.
unsigned long *GPIOBIntType2;
//	Global 0x8084_00C0 RawIntStsB  Raw Interrupt Status Register. Contains raw interrupt status of Port B before masking.
// Not used because we use masking.
unsigned long *RawIntStsB;
//  Global 0x8084_00C4 GPIOBDB GPIO Interrupt debouncing register.
unsigned long *GPIOBDB;
// Global 0x8084_00BC IntStsB GPIO Interrupt Status Register.
// Contains status of Port B interrupt after masking.
// This register gives you the status of the interrupt meaning if you read this register you can determine which of the buttons were pressed.
unsigned long *IntStsB;

//xxx Realtime Methods start
static void Toggle_Speaker_Forever(int t) {
	RedOn;
	PRINT("\n\nToggle_Speaker_Forever Module Installed. Red LED's Should be on\n"); //use dmesg command to read the log file.
	while (1) {
		//keep same distance from after rt wait and order of tasks to keep the periods between performing the tasks equal.
		rt_task_wait_period();
		do_gettimeofday(&tPacket);
		ksocket_start();

		//Toggling a bit http://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit-in-c-c
		//*pFdr ^= 0x2;
		//*pFdr = *pFdr | 0x02; //"turn on" speaker
		RedOn;
		//watchDogTimer = 0;
		//blocking function. wait for the period to occur.
		rt_task_wait_period();
		do_gettimeofday(&tPacket);

		//ksocket_start();
		//*pFdr ^= 0x2;
		//*pFdr = *pFdr & 0xFFFFFFFD; //"turn off" speaker
		RedOff;
		watchDogTimer = 0;
	}
}
static void watchdog(int t) {
	while (1) {
		rt_task_wait_period();
		if (++watchDogTimer >= WATCHDOG_TIMER_THRESHOLD) {
			printk("Threshold reached, resetting task.");
			rt_task_delete(&Rt_Task_Speaker_Forever); //delete realtime task
			rt_task_init(&Rt_Task_Speaker_Forever, Toggle_Speaker_Forever, 0, 256, 1, 0, 0);
			rt_task_make_periodic(&Rt_Task_Speaker_Forever, rt_get_time(), period * 10);
			watchDogTimer = 0;
			GrnOn;
			YlwOn;
		} else {
			TRACE(printk("Threshold Not Reached. is now %ld\n",watchDogTimer));
			YlwOff;
		}
	}
}

static void Port_B_handler(unsigned irq, void *cookie) {
	rt_disable_irq(irq);
	GrnOn;
	YlwOff;
	PRINT("\n\nLab6 btn handlr Module called. green LED's Should be on\n"); //use dmesg command to read the log file.
	//Log2(x) = result. The result is the bit number.
	// 1,2,4,8,16 are the possible decimal answers
	// 0,1,2,3,4 should be the range of results.
	int result = 0;
	unsigned int x = *IntStsB & 0x1F;
	while (x >>= 1)
		result++;
	if (result <= 4) {
		//if this is backwards from the tone we want, then change it in init.
		rt_task_make_periodic(&Rt_Task_Speaker_Forever, rt_get_time(), periodArray[result]);
		//xxx added
		rt_task_make_periodic(&Rt_Task_watchdog, rt_get_time() + 10 * period, periodArray[result] * 10);
	} else {
		//Shouldn't occur because we masked other bits. One of them has to be high if we are here.
		printk("result > 4 :/ \n");
		result = 9;
	}
	TRACE(printk("sending %d button pressed over fifo\n",result));
	//send this to the user space program to possibly transmit to the slave boards.
	rtf_put(HARDWARE_FIFO_TO_USER_SPACE, &result, sizeof(int));
	// clear hardware interrupt
	*GPIOBEOI |= 0x1F;

	//re-enable interrupt handling
	rt_enable_irq(irq);
	PRINT("Hardware Interrupt Finished.");
}
static void Sfwtr_handler(unsigned irq, void *cookie) {
	rt_disable_irq(irq);

	YlwOn;
	GrnOff;
	PRINT("\n\nLab6 software handlr Module called. Yellow LED's Should be on\n"); //use dmesg command to read the log file.
	//int from SOFTWARE_FIFO_FROM_USER_SPACE
	int result;
	rtf_get(SOFTWARE_FIFO_FROM_USER_SPACE, &result, sizeof(int));

	TRACE(printk("Received %d button pressed over fifo",result));

	if (result >= 0 && result <= 4) {
		//if this is backwards from the tone we want, then change it in init.
		//TODO ptxk network change period. rt_task_make_periodic(&Rt_Task_Speaker_Forever, rt_get_time(), periodArray[result]);
	} else if (result == -1) {
		//TODO ptxk network change period. rt_task_make_periodic(&Rt_Task_Speaker_Forever, rt_get_time(), period * 9999);
	} else {
		//Shouldn't occur because we masked other bits. One of them has to be high if we are here.
		printk("result > 4 :/ \n");
	}

	// clear software interrupt
	*VIC2SoftIntClear |= 0x80000000;

	//re-enable interrupt handling
	rt_enable_irq(irq);
	PRINT("Software Interrupt Finished");
}

//xxx use insmod lab1week2.o to install
int init_module(void) {
	printk("Installing project Tx\n");
	kthread = kmalloc(sizeof(struct kthread_t), GFP_KERNEL);
	ksocket_start();
	//KERNEL INIT module will perform the following.

	////offsets to Software Interrupt Registers. = 0x800C_0010
	//enable software interrupt. Enable our software interrupt.
	//A high enables the interrupt. Allows interrupt request to processor.
	// We use VIC1 controls interrupts 1-32, VIC2 controls interrupts 33-64.
	unsigned long *VIC2ptr = (unsigned long *) __ioremap(0x800C0000, 4096, 0);
	VIC2IntEnable = (unsigned long *) ((char *) VIC2ptr + 0x10);
	//Here we set the 31st bit. VIC1 is 0-31. so VIC1 + 31 == 62 which is interrupt 64 when taking both zeros into account.
	*VIC2IntEnable |= 0x80000000;
	//offsets to Software Interrupt Clear Register. = 0x800C_001C
	//clear software interrupt register. Just delcaring location here.
	VIC2SoftIntClear = (unsigned long *) ((char *) VIC2ptr + 0x1C);
	// clear software interrupt
	*VIC2SoftIntClear |= 0x80000000;
	VIC2SoftInt = (unsigned long*) ((char *) ptr + 0x18);

	// enable interrupt (register level)
	// YOU WILL map and then modify registers themselves.
	//page size is 4096, flag is zero
	ptr = (unsigned long *) __ioremap(0x80840000, 4096, 0);

	//find port  pointer address
	pBdr = (unsigned long *) ((char *) ptr + 0x04);//offsets to port B = 0x8084_0004
	pFdr = (unsigned long *) ((char *) ptr + 0x30);//offsets to port F = 0x8084_0030

	//	You should also list the ep9301 registers that need to be modified to control interrupts on port B. http://vigir.ee.missouri.edu/~gdesouza/ece4220/Lab_Assignments/ts-7000_ep9301-ug.pdf p54
	//	0x8084_00AC  GPIOBIntType1  Register controlling type, level or edge, of interrupt generated by the pins of Port B
	// These 5 buttons should trigger interrupt on falling edge.
	GPIOBIntType1 = (unsigned long *) ((char *) ptr + 0xac);
	*GPIOBIntType1 |= 0x1f;

	//	0x8084_00B0  GPIOBIntType2  Register controlling polarity, high/low or rising/falling, of interrupt generated by Port B
	//These five buttons should trigger interrupt on falling edge.
	GPIOBIntType2 = (unsigned long *) ((char *) ptr + 0xb0);
	*GPIOBIntType2 &= ~0x1f;

	//	GPIOBIntEn, the General Purpose I/O Interrupt Enable register for port B.
	//	0x8084_00B8  GPIOBIntEn  Controls the generation of interrupts by the pins of Port B
	// Turn on interrupts for the input pins for the buttons, but turn off interrupts for the output pins the led's.
	// we must turn on/off individual bits to throw interrupt because it throws a single interrupt and the handler has to filter why it was thrown.
	GPIOBIntEn = (unsigned long *) ((char *) ptr + 0xb8);
	*GPIOBIntEn |= 0x1f;
	*GPIOBIntEn &= ~0xe0;

	//	0x8084_00BC IntStsB GPIO Interrupt Status Register. Contains status of Port B interrupt after masking.
	// This just sets up the variable to be read from later. This is where
	IntStsB = (unsigned long *) ((char *) ptr + 0xbc);
	//	0x8084_00C0 RawIntStsB  Raw Interrupt Status Register. Contains raw interrupt status of Port B before masking. This register gives you the status of the interrupt meaning if you read this register you can determine which of the buttons were pressed.
	// not used.
	RawIntStsB = (unsigned long *) ((char *) ptr + 0xc0);

	//  0x8084_00C4 GPIOBDB GPIO Interrupt debouncing register.
	// we would like to enable debouncing because we are using a switch as our input which requires debouncing.
	GPIOBDB = (unsigned long *) ((char *) ptr + 0xC4);
	*GPIOBDB |= 0x1f;

	//pBddr == port B data Direction Register sets the data register as output or input.
	pBddr = (unsigned long *) ((char *) pBdr + 0x10); //offsets to DDR for port B = 0x8084_0014
	pFddr = (unsigned long *) ((char *) ptr + 0x34); //offsets to DDR for port F = 0x8084_0034
	//set data direction registers
	*pBddr = *pBddr | 0xE0; // 111x_xxxx Set high three bits to 1 to output
	*pBddr = *pBddr & 0xFFFFFFE0; //&xxx0_0000 Set low five bits to 0 to input and making sure
	//  1110_0000 higher bits are not affected
	//set speaker port to output.
	*pFddr = *pFddr | 0x02; // 0000_0010 Set 2nd bit to 1 to output

	//Set timing
	//RTC clock 32.768 kHz crystal, 30518 ns  (nanoseconds)
	//CPU clock 200 mhz?
	//75000000 nano seconds period you can see flashing LED rapidly.
	//2273000 nano seconds period == 440.000 hz == A
	//2024770 nano seconds period == 493.883 hz == B
	//1911130 nano seconds period == 523.251 hz == C
	//1702620 nano seconds period == 587.330 hz == D
	//1516860 nano seconds period == 659.255 hz == E
	//1431730 nano seconds period == 698.456 hz == F
	//1275520 nano seconds period == 783.991 hz == G
	// 100000 I wouldn't use anything below that.
	rt_set_periodic_mode(); // set periodic mode
	period = start_rt_timer(nano2count(100000000));
	periodArray[0] = A = period * 10000;
	periodArray[1] = B = period * 1000;
	periodArray[2] = C = period * 100;
	periodArray[3] = D = period * 10;
	periodArray[4] = E = period * 1;

	// initialize real time task called Toggle_Speaker_Forever, and make it periodic
	rt_task_init(&Rt_Task_Speaker_Forever, Toggle_Speaker_Forever, 0, 256, 1, 0, 0);
	rt_task_init(&Rt_Task_watchdog, watchdog, 0, 256, 0, 0, 0);
	//rt_task_make_periodic(&Rt_Task_Speaker_Forever, rt_get_time() + 100 * period, period * 12);
	rt_task_make_periodic(&Rt_Task_Speaker_Forever, rt_get_time(), period * 10);
	rt_task_make_periodic(&Rt_Task_watchdog, rt_get_time() + 100 * period, period * 10);
	//	0x8084_00B4  GPIOBEOI  GPIO Port B End Of Interrupt Register. In order to clear the interrupt you have to write a 1 or zero to clear this bit to say that the interrupt should not be triggered the next time it is checked.
	// end of interrupt flags, clear interrupt flags from any old random values.
	GPIOBEOI = (unsigned long *) ((char *) ptr + 0xb4);
	*GPIOBEOI |= 0x1f;

	//setup interrupt vector table with arg designated in lab document.
	//	rt_request_irq(irq_num, Port_B_handler, 0, 1); // actual code
	//	rt_request_irq(irq_num, Sfwtr_handler, 0, 1); // actual code
	irq = 59;
	rt_request_irq(irq, Port_B_handler, 0, 1);
	irq = 63;
	rt_request_irq(irq, Sfwtr_handler, 0, 1);
	//enable interrupt handling
	irq = 59;
	rt_enable_irq(irq);
	irq = 63;
	rt_enable_irq(irq);

	//rtf_create,int rtf_create(unsigned int fifo, int size); creates a real-time FIFO.Arg 0 holds the address of the fifo., Arg 1 states the dimension of the FIFO. The function returns 0 on success.
	int size = sizeof(int);
	printk("Creating HARDWARE_FIFO_TO_USER_SPACE real time fifo");
	if (rtf_create(HARDWARE_FIFO_TO_USER_SPACE, size) == 0) {
		PRINT("\nHARDWARE_FIFO_TO_USER_SPACE kernel real time fifo created sucussfully\n");
	} else {
		printk("error creating HARDWARE_FIFO_TO_USER_SPACE kernel real time fifo******************************************\n");
	}
	printk("Creating SOFTWARE_FIFO_FROM_USER_SPACE");
	if (rtf_create(SOFTWARE_FIFO_FROM_USER_SPACE, size) == 0) {
		PRINT("\n SOFTWARE_FIFO_FROM_USER_SPACE created sucussfully\n");
	} else {
		printk("error creating SOFTWARE_FIFO_FROM_USER_SPACE kernel real time fifo******************************************\n");
	}
	printk("lab6kernel init finished.\n");
	return 0;

}

//use rmmod lab1week2 to remove
void cleanup_module(void) {
	PRINT("Removing Lab6kernel");

	rt_disable_irq(59);
	rt_disable_irq(63);
	rt_task_delete(&Rt_Task_Speaker_Forever); //delete realtime task
	stop_rt_timer(); //stop timer
	rtf_destroy(HARDWARE_FIFO_TO_USER_SPACE); //destroy fifo
	rtf_destroy(SOFTWARE_FIFO_FROM_USER_SPACE);
	rt_release_irq(59);
	rt_release_irq(63);

	//old cleanup code here

	unsigned long *ptr; //holds pointer to mapped memory IO
	unsigned long *pBdr; //port B data register
	unsigned long *pBddr; //port B data Direction register


	//page size is 4096, flag is zero
	ptr = (unsigned long *) __ioremap(0x80840000, 4096, 0);

	//find port B pointer address
	pBdr = (unsigned long *) ((char *) ptr + 0x04);//offsets to port B = 0x8084_0004

	//pBddr == port B data Direction Register sets the data register as output or input.
	pBddr = (unsigned long *) ((char *) pBdr + 0x10); //offsets to DDR for port B = 0x8084_0014

	//set data direction registers
	*pBddr = *pBddr | 0xE0; // 111x_xxxx Set high three bits to 1 to output
	*pBddr = *pBddr & 0xFFFFFFE0; //&xxx0_0000 Set low five bits to 0 to input and making sure
	//  1110_0000 higher bits are not affected

	//turn Red and yellow LED's off
	*pBdr = *pBdr & 0xFFFFFF9F; //&000x_xxxx Set the output bits to 0 to turn off LEDs
	AllLedOff;
	PRINT("\n\nLab 6 Module removed. AllLedOff\n"); //use dmesg command to read the log file.


	{
//		if (kthread != NULL && kthread->sock != NULL && kthread->sock_send != NULL) {
//			sock_release(kthread->sock);
//			sock_release(kthread->sock_send);
//			kthread->sock = NULL;
//			kthread->sock_send = NULL;
//
//			kthread->thread = NULL;
//			kthread->running = 0;
//		}
		/* free allocated resources before exit */
//		if (kthread->sock != NULL) {
//			sock_release(kthread->sock);
//			kthread->sock = NULL;
//		}
		sock_release(kthread->sock_send);
		kthread->sock_send = NULL;

		kfree(kthread);
		kthread = NULL;

		printk(KERN_INFO MODULE_NAME": module unloaded\n");
	}
}

//lab3...
static void rt_process(int t) {
	unsigned long *ptr; //holds pointer to mapped memory IO
	unsigned long *pBdr; //port B data register
	unsigned long *pBddr; //port B data Direction register
	unsigned long *pFdr; //port F data register
	unsigned long *pFddr; //port F Data Direction Register
	//page size is 4096, flag is zero
	ptr = (unsigned long *) __ioremap(0x80840000, 4096, 0);
	//find port  pointer address
	pBdr = (unsigned long *) ((char *) ptr + 0x04);//offsets to port B = 0x8084_0004
	pFdr = (unsigned long *) ((char *) ptr + 0x30);//offsets to port F = 0x8084_0030
	//pBddr == port B data Direction Register sets the data register as output or input.
	pBddr = (unsigned long *) ((char *) pBdr + 0x10); //offsets to DDR for port B = 0x8084_0014
	pFddr = (unsigned long *) ((char *) ptr + 0x34); //offsets to DDR for port F = 0x8084_0034
	//set data direction registers
	*pBddr = *pBddr | 0xE0; // 111x_xxxx Set high three bits to 1 to output
	*pBddr = *pBddr & 0xFFFFFFE0; //&xxx0_0000 Set low five bits to 0 to input and making sure
	//set speaker port to output.
	*pFddr = *pFddr | 0x02; // 0000_0010 Set 2nd bit to 1 to output
	//rtf_create,int rtf_create(unsigned int fifo, int size); creates a real-time FIFO.Arg 0 holds the address of the fifo., Arg 1 states the dimension of the FIFO. The function returns 0 on success.
	struct timeval tBtn;
	unsigned int fifo = 0;
	int size = sizeof(tBtn);
	if (rtf_create(fifo, size) == 0) {
		printk("\nkernel real time fifo created sucussfully\n");
	} else {
		printk("error creating kernel real time fifo******************************************\n");
	}
	RedOn;
	printk("\n\nModule Installed. Red LED's Should be on\n"); //use dmesg command to read the log file.
	while (1) {
		//do stuff
		unsigned long portvalue = *pBdr;
		//if the user hits any button.
		if (BTN0 || BTN1 || BTN2 || BTN3 || BTN4) {
			//get the time of the button press
			do_gettimeofday(&tBtn);
			// write to real time fifo
			rtf_put(0, &tBtn, sizeof(tBtn));
			//debugging
			//printk("\n*************btn press event @ %ld.%06ld\n", tBtn.tv_sec, tBtn.tv_usec);
			//turn Red and yellow LED's off to tell the user that its button press was received.
			*pBdr = *pBdr & 0xFFFFFF9F; //&000x_xxxx Set the output bits to 0 to turn off LEDs
		} else {
			//turn Red and yellow LED's on to signify button release.
			*pBdr = *pBdr | 0x60; // 111x_xxxx
			// REMOVE THIS LINE< FOR ERROR CHECKING ONLY
			/*			//get the time of the button press
			 do_gettimeofday(&tBtn);
			 // write to real time fifo
			 rtf_put(0, &tBtn, sizeof(tBtn));*/
		}
		//blocking function. wait for the period to occur.
		rt_task_wait_period();
	}
}

