Difference between revisions of "Embedded-Linux-Device-Driver/C3/Interrupt-Handling/English"

From Script | Spoken-Tutorial
Jump to: navigation, search
(Created page with " {| border="1" |- || '''VISUAL CUE''' || '''NARRATION''' |- || Slide 1: Welcome slide: || Welcome to the spoken tutorial on '''Interrupt Handling.''' |- || Slide 2: Learnin...")
 
Line 13: Line 13:
  
 
Learning objectives:
 
Learning objectives:
|| In this tutorial, we will learn how to
+
|| In this tutorial, we will learn how to handle the software interrupt in the driver.
* Handle the software interrupt in the driver.
+
 
|-  
 
|-  
 
|| Slide 3:
 
|| Slide 3:
Line 37: Line 36:
 
'''Interrupt handler'''
 
'''Interrupt handler'''
  
|| * The '''function''' that runs in response to a specific '''interrupt''' is called an '''interrupt handler'''
+
||  
 +
* The '''function''' that runs in response to a specific '''interrupt''' is called an '''interrupt handler'''
 
* Different '''devices''' can be associated with different '''interrupts'''.
 
* Different '''devices''' can be associated with different '''interrupts'''.
 
* A '''driver''' needs to handle the '''interrupts''' properly for its '''device'''.  
 
* A '''driver''' needs to handle the '''interrupts''' properly for its '''device'''.  
Line 44: Line 44:
  
 
Working - '''Interrupt Handling.'''
 
Working - '''Interrupt Handling.'''
|| In this tutorial, a user program will '''open''' and '''close''' the device file.
+
|| In this tutorial, a user program will '''open''' and '''close''' the '''device file'''.
  
When the user program opens a device, the software interrupt will be triggered by the driver.
+
When the '''user program''' opens a '''device''', the '''software interrupt''' will be triggered by the '''driver'''.
  
When the kernel receives an interrupt, the registered handler from the driver will be executed.
+
When the '''kernel''' receives an '''interrupt''', the '''registered handler''' from the '''driver''' will be '''executed'''.
 
|-  
 
|-  
 
|| Point to the folder and file in '''desktop'''
 
|| Point to the folder and file in '''desktop'''
  
 
Point to the '''files'''.  
 
Point to the '''files'''.  
|| Go to the '''DeviceDriver '''folder in the desktop which we have created earlier.
+
|| Go to the '''DeviceDriver '''folder in the '''Desktop''' which we have created earlier.
  
 
In this directory, I have created a directory named '''Interrupt'''.
 
In this directory, I have created a directory named '''Interrupt'''.
  
Here, I have saved an''' interrupt dot c , Makefile '''and''' user dot c files.'''
+
Here, I have saved an''' interrupt dot c, Makefile '''and''' user dot c files.'''
  
 
I’ll use these files for demonstration.
 
I’ll use these files for demonstration.
Line 76: Line 76:
 
Go to the directory where '''Interrupt '''is saved on your system.
 
Go to the directory where '''Interrupt '''is saved on your system.
  
Press Enter key after every command.
+
Press '''Enter''' key after every '''command'''.
 
|-  
 
|-  
 
|| Type >>''' gedit interrupt.c'''
 
|| Type >>''' gedit interrupt.c'''
Line 87: Line 87:
 
Highlight '''<linux/interrupt.h>'''
 
Highlight '''<linux/interrupt.h>'''
  
|| We have to include an '''interrupt dot h kernel header file''' to register an '''interrupt'''.
+
|| We have to include an '''interrupt dot h kernel header file''' to '''register''' an '''interrupt'''.
  
 
The purpose of each file is mentioned as shown here.
 
The purpose of each file is mentioned as shown here.
Line 98: Line 98:
 
|| We have defined the''' IRQ line number as 2 '''which will be used in this '''driver'''.  
 
|| We have defined the''' IRQ line number as 2 '''which will be used in this '''driver'''.  
  
The '''devices''' can send interrupts to the '''processor''' using these '''IRQ''' lines.
+
The '''devices''' can send '''interrupts''' to the '''processor''' using these '''IRQ''' lines.
  
 
We have implemented an '''interrupt handler''' as shown here.
 
We have implemented an '''interrupt handler''' as shown here.
Line 108: Line 108:
 
Highlight''' request_irq()'''
 
Highlight''' request_irq()'''
  
|| In the '''initialization '''function, we have to register the '''interrupt handler.'''
+
|| In the '''initialization function''', we have to '''register''' the '''interrupt handler.'''
  
'''Drivers''' can register an''' interrupt handler '''and enable a given '''interrupt line''' for handling.
+
'''Drivers''' can '''register''' an''' interrupt handler '''and enable a given '''interrupt line''' for handling.
  
The '''request_irq '''function''' '''is used to register an '''interrupt handler.'''
+
The '''request_irq function''' is used to '''register''' an '''interrupt handler.'''
 
|-  
 
|-  
 
|| Highlight '''IRQ_NUM'''
 
|| Highlight '''IRQ_NUM'''
  
 
Highlight '''irq_handler'''
 
Highlight '''irq_handler'''
|| The first parameter specifies the '''interrupt number''' to allocate.
+
|| The first '''parameter''' specifies the '''interrupt number''' to allocate.
  
 
This value is typically hard-coded in the '''kernel'''.
 
This value is typically hard-coded in the '''kernel'''.
The second parameter is a''' function pointer''' to the actual''' interrupt handler.'''
+
 
 +
The second '''parameter''' is a''' function pointer''' to the actual''' interrupt handler.'''
  
 
This '''function''' is invoked whenever the '''kernel '''receives the '''interrupt'''.
 
This '''function''' is invoked whenever the '''kernel '''receives the '''interrupt'''.
Line 126: Line 127:
 
|| Highlight '''flag'''
 
|| Highlight '''flag'''
  
|| The third parameter can be either zero or one or any of the '''flags''' defined in the''' interrupt dot h .'''
+
|| The third '''parameter''' can be either zero or one or any of the '''flags''' defined in the''' interrupt dot h.'''
  
The fourth parameter is used to identify the '''device''' '''interrupt''' name.
+
The fourth '''parameter''' is used to identify the '''device interrupt''' name.
  
The fifth parameter is used for shared '''interrupt lines.'''
+
The fifth '''parameter''' is used for shared '''interrupt lines.'''
  
This parameter is used to identify the handlers on the same interrupt line.
+
This '''parameter''' is used to identify the '''handlers''' on the same '''interrupt line'''.
  
 
|-  
 
|-  
Line 144: Line 145:
  
 
'''IRQF_SHARED''' - Allows sharing the irq among several devices
 
'''IRQF_SHARED''' - Allows sharing the irq among several devices
|| Let us see some important '''flags''' that can be used by '''request_irq '''function
+
|| Let us see some important '''flags''' that can be used by '''request_irq function'''.
  
'''IRQF_DISABLED''' - It disables all interrupts when executing this interrupt handler.
+
'''IRQF_DISABLED''' - It disables all '''interrupts''' when executing this '''interrupt handler'''.
  
'''IRQF_SAMPLE_RANDOM '''- It specifies that interrupts should contribute to the kernel entropy pool.
+
'''IRQF_SAMPLE_RANDOM '''- It specifies that '''interrupts''' should contribute to the '''kernel entropy''' pool.
  
'''IRQF_TIMER''' - It is used to mark this interrupt as timer interrupt
+
'''IRQF_TIMER''' - It is used to mark this '''interrupt''' as '''timer interrupt'''
  
'''IRQF_SHARED''' - It allows sharing the irq among several devices.
+
'''IRQF_SHARED''' - It allows sharing the '''irq''' among several '''devices'''.
 
|-  
 
|-  
 
||  
 
||  
Line 160: Line 161:
  
 
'''Highlight printk'''
 
'''Highlight printk'''
|| '''Request_irq function''' will register the '''irq_handler''' with the name '''my_interrupt.'''
+
|| '''Request_irq function''' will '''register''' the '''irq_handler''' with the name '''my_interrupt.'''
  
 
'''my_interrupt''' is used by '''slash proc slash interrupts''' for communication with the '''user'''.
 
'''my_interrupt''' is used by '''slash proc slash interrupts''' for communication with the '''user'''.
Line 166: Line 167:
 
Here, we have used the''' IRQF_SHARED flag.'''
 
Here, we have used the''' IRQF_SHARED flag.'''
  
On success,''' request_irq '''function''' '''returns zero.
+
On success,''' request_irq function''' returns zero.
  
 
A nonzero value indicates an error.
 
A nonzero value indicates an error.
Line 174: Line 175:
  
 
Highlight '''asm("int $50")'''
 
Highlight '''asm("int $50")'''
|| In the '''open() '''function,''' asm("int $50")''' '''instruction''' will trigger the '''interrupt'''.
+
|| In the '''open() function asm("int $50")''' instruction will trigger the '''interrupt'''.
We are not going to use any '''hardware''' interrupt as they can come from anywhere at any time.
+
We are not going to use any '''hardware interrupt''' as they can come from anywhere at any time.
  
 
Here, we are going to trigger a '''software interrupt''' using the '''int instruction.'''
 
Here, we are going to trigger a '''software interrupt''' using the '''int instruction.'''
Line 186: Line 187:
  
 
Highlight '''02'''
 
Highlight '''02'''
|| Let us see how to calculate the interrupt line number.
+
|| Let us see how to calculate the '''interrupt''' line number.
  
In '''Linux''' '''IRQ''' to '''vector''', mapping is done using '''FIRST_EXTERNAL_VECTOR macro'''.
+
In '''Linux IRQ''' to '''vector''', mapping is done using '''FIRST_EXTERNAL_VECTOR macro'''.
  
To raise an''' interrupt IRQ 2''', we have to add 2 to a vector of '''IRQ 0''' as shown here.
+
To raise an''' interrupt IRQ 2''', we have to add 2 to a '''vector''' of '''IRQ 0''' as shown here.
 
|-  
 
|-  
 
|| Highlight '''asm("int $50")'''
 
|| Highlight '''asm("int $50")'''
|| The '''asm''' '''instruction''' will be executed while opening the '''device file''' of our '''driver'''.
+
|| The '''asm''' instruction will be executed while opening the '''device file''' of our '''driver'''.
  
When this '''instruction''' executes, it will raise the''' interrupt IRQ 2.'''
+
When this instruction '''executes''', it will raise the''' interrupt IRQ 2.'''
 
|-  
 
|-  
 
|| Highlight '''free_irq(IRQ_NUM,(void *)irq_handler)'''
 
|| Highlight '''free_irq(IRQ_NUM,(void *)irq_handler)'''
  
 
Highlight '''IRQ_NUM'''
 
Highlight '''IRQ_NUM'''
|| When the '''driver''' unloads, we need to unregister the '''interrupt handler.'''
+
|| When the '''driver''' unloads, we need to un'''register''' the '''interrupt handler.'''
  
 
The '''free_irq function''' is used to remove the '''handler''' and disable the line if not shared.
 
The '''free_irq function''' is used to remove the '''handler''' and disable the line if not shared.
  
If it is shared and no handlers remain on the '''line''', the given''' interrupt line''' will be disabled.
+
If it is shared and no '''handlers''' remain on the line, the given''' interrupt''' line will be disabled.
 
|-  
 
|-  
 
|| Highlight''' free_irq().'''
 
|| Highlight''' free_irq().'''
Line 210: Line 211:
 
|| In the '''exit function''', we have used the '''free function''' to remove the '''handler''' from the '''kernel'''.
 
|| In the '''exit function''', we have used the '''free function''' to remove the '''handler''' from the '''kernel'''.
  
It will unregister the''' interrupt handler''' from the '''kernel'''.
+
It will un'''register''' the''' interrupt handler''' from the '''kernel'''.
 
|-  
 
|-  
 
|| Save and close the '''file'''
 
|| Save and close the '''file'''
Line 242: Line 243:
  
 
Type >>''' insmod interrupt.ko'''
 
Type >>''' insmod interrupt.ko'''
|| Let’s compile the '''driver'''.
+
|| Let’s '''compile''' the '''driver'''.
  
 
Type''' make space all'''
 
Type''' make space all'''
Line 261: Line 262:
 
'''Interrupt file''' in '''procfs''' contains the list of registered '''interrupts''' in the '''system'''.
 
'''Interrupt file''' in '''procfs''' contains the list of registered '''interrupts''' in the '''system'''.
  
This '''command''' will show the '''registered interrupt''' '''my_interrupt '''and its '''IRQ line number'''.
+
This '''command''' will show the '''registered interrupt my_interrupt '''and its '''IRQ''' line number.
  
In the output, we can see our '''registered interrupt name''' and '''IRQ '''number.
+
In the output, we can see our '''registered interrupt''' name and '''IRQ '''number.
  
It indicates that our '''interrupt handler '''is''' '''registered successfully.
+
It indicates that our '''interrupt handler '''is registered successfully.
  
 
Clear the screen.
 
Clear the screen.
Line 276: Line 277:
 
Type >>''' gcc -o user.out user.o'''
 
Type >>''' gcc -o user.out user.o'''
  
|| Now compile the''' user program.'''
+
|| Now '''compile''' the''' user program.'''
  
 
Type '''gcc hyphen c user dot c'''
 
Type '''gcc hyphen c user dot c'''
Line 287: Line 288:
  
 
Type >> '''clear'''
 
Type >> '''clear'''
|| Now let us execute the''' user program.'''
+
|| Now let us '''execute''' the''' user program.'''
  
 
Type''' dot slash user dot out'''
 
Type''' dot slash user dot out'''
Line 302: Line 303:
 
|| Type '''dmesg space pipe space grep space my_driver'''.
 
|| Type '''dmesg space pipe space grep space my_driver'''.
  
This message shows that the device''' open function '''triggered the '''interrupt'''.
+
This message shows that the '''device open function '''triggered the '''interrupt'''.
  
It indicates that as soon as the '''interrupt''' triggered, its '''handler got''' executed.  
+
It indicates that as soon as the '''interrupt''' triggered, its '''handler''' got '''executed'''.  
  
After the execution of the '''handler''', the remaining code''' '''from the '''open''' function is executed.
+
After the '''execution''' of the '''handler''', the remaining code from the '''open function''' is '''executed'''.
  
 
It shows that the '''driver''' properly handled the '''interrupt'''.
 
It shows that the '''driver''' properly handled the '''interrupt'''.
Line 317: Line 318:
  
 
Type >>''' clear'''
 
Type >>''' clear'''
|| Now lets unload the '''driver'''.
+
|| Now let's unload the '''driver'''.
  
 
Type '''rmmod space interrupt dot ko'''
 
Type '''rmmod space interrupt dot ko'''
Line 325: Line 326:
 
Type '''dmesg space pipe space grep space my_driver.'''
 
Type '''dmesg space pipe space grep space my_driver.'''
  
Here, we can see our interrupt handler is unregistered from the '''kernel'''.
+
Here, we can see our '''interrupt handler''' is un'''registered''' from the '''kernel'''.
  
 
Clear the screen.
 
Clear the screen.
Line 348: Line 349:
 
|| As an assignment:
 
|| As an assignment:
 
# Open the''' interrupt.c driver file.'''
 
# Open the''' interrupt.c driver file.'''
# Write the''' interrupt instruction '''in the release '''function'''.
+
# Write the''' interrupt''' instruction in the '''release function'''.
# Compile and load the '''driver'''.
+
# '''Compile''' and load the '''driver'''.
# Compile and execute the '''user program.'''
+
# '''Compile''' and '''execute''' the '''user program.'''
 
# See the output using''' dmesg command.'''
 
# See the output using''' dmesg command.'''
 
|-  
 
|-  
Line 363: Line 364:
  
 
Spoken Tutorial workshops :
 
Spoken Tutorial workshops :
|| The Spoken Tutorial Project Team:* conducts workshops and
+
|| The Spoken Tutorial Project Team conducts workshops and gives certificates.
* gives certificates.
+
  
 
For more details, please write to us.
 
For more details, please write to us.
Line 370: Line 370:
 
|| Slide 15:
 
|| Slide 15:
 
Forum questions :
 
Forum questions :
|| * Please post your timed queries in this forum
+
|| Please post your timed queries in this forum
 
|-  
 
|-  
 
|| Slide 16:
 
|| Slide 16:
  
 
Forum for specific questions :
 
Forum for specific questions :
|| * Do you have any general or technical questions on Embedded Linux Device Driver?
+
||  
 +
* Do you have any general or technical questions on Embedded Linux Device Driver?
 
* Please visit the FOSSEE forum and post your question
 
* Please visit the FOSSEE forum and post your question
 
|-  
 
|-  

Revision as of 23:13, 30 January 2021

VISUAL CUE NARRATION
Slide 1:

Welcome slide:

Welcome to the spoken tutorial on Interrupt Handling.
Slide 2:

Learning objectives:

In this tutorial, we will learn how to handle the software interrupt in the driver.
Slide 3:

System Requirements:

To record this tutorial, I am using,
  • VirtualBox 5.2.
  • Ubuntu Linux 18.04 LTS Operating System.
  • Linux kernel version 5.0.0-31 generic.
  • gedit text editor.
Slide 4:

Prerequisites:

To follow this tutorial, you should be familiar with:
  • C programming language and
  • Basics of Linux kernel

If not, then go through the C/C++ and Linux spoken tutorials on this website

Slide 6 :

Interrupt handler

  • The function that runs in response to a specific interrupt is called an interrupt handler
  • Different devices can be associated with different interrupts.
  • A driver needs to handle the interrupts properly for its device.
Slide :

Working - Interrupt Handling.

In this tutorial, a user program will open and close the device file.

When the user program opens a device, the software interrupt will be triggered by the driver.

When the kernel receives an interrupt, the registered handler from the driver will be executed.

Point to the folder and file in desktop

Point to the files.

Go to the DeviceDriver folder in the Desktop which we have created earlier.

In this directory, I have created a directory named Interrupt.

Here, I have saved an interrupt dot c, Makefile and user dot c files.

I’ll use these files for demonstration.

Slide:5

Code files:

  • The files used in this tutorial are available in the Code Files link on this tutorial page.
  • Please download and extract them
  • Make a copy and then use them while practising
Open the terminal

Type >> cd Desktop/DeviceDriver/Interrupt

Open the terminal by pressing ALT+Ctrl+T keys simultaneously.

Go to the directory where Interrupt is saved on your system.

Press Enter key after every command.

Type >> gedit interrupt.c Type gedit space interrupt dot c.
Highlight header files

Highlight <linux/interrupt.h>

We have to include an interrupt dot h kernel header file to register an interrupt.

The purpose of each file is mentioned as shown here.

In this file, I have implemented only open and close file operations for a device.

Highlight IRQ_NUM

Highlight irqreturn_t irq_handler()

We have defined the IRQ line number as 2 which will be used in this driver.

The devices can send interrupts to the processor using these IRQ lines.

We have implemented an interrupt handler as shown here.

When the kernel receives the respective interrupt, it will execute this handler.

Highlight int_function()

Highlight request_irq()

In the initialization function, we have to register the interrupt handler.

Drivers can register an interrupt handler and enable a given interrupt line for handling.

The request_irq function is used to register an interrupt handler.

Highlight IRQ_NUM

Highlight irq_handler

The first parameter specifies the interrupt number to allocate.

This value is typically hard-coded in the kernel.

The second parameter is a function pointer to the actual interrupt handler.

This function is invoked whenever the kernel receives the interrupt.

Highlight flag The third parameter can be either zero or one or any of the flags defined in the interrupt dot h.

The fourth parameter is used to identify the device interrupt name.

The fifth parameter is used for shared interrupt lines.

This parameter is used to identify the handlers on the same interrupt line.

Slide - Important flags :

IRQF_DISABLED - Disables all interrupts when executing this interrupt handler.

IRQF_SAMPLE_RANDOM - Specifies that interrupts should contribute to the kernel entropy pool.

IRQF_TIMER - Used to mark this interrupt as timer interrupt

IRQF_SHARED - Allows sharing the irq among several devices

Let us see some important flags that can be used by request_irq function.

IRQF_DISABLED - It disables all interrupts when executing this interrupt handler.

IRQF_SAMPLE_RANDOM - It specifies that interrupts should contribute to the kernel entropy pool.

IRQF_TIMER - It is used to mark this interrupt as timer interrupt

IRQF_SHARED - It allows sharing the irq among several devices.

Switch back to the code.
Highlight request_irq()

Highlight printk

Request_irq function will register the irq_handler with the name my_interrupt.

my_interrupt is used by slash proc slash interrupts for communication with the user.

Here, we have used the IRQF_SHARED flag.

On success, request_irq function returns zero.

A nonzero value indicates an error.

Highlight open() function

Highlight asm("int $50")

In the open() function asm("int $50") instruction will trigger the interrupt.

We are not going to use any hardware interrupt as they can come from anywhere at any time.

Here, we are going to trigger a software interrupt using the int instruction.

Highlight #define IRQ0_VECTOR()

Highlight FIRST_EXTERNAL_VECTOR

Highlight 0x20 + 0x10 + 02 = 50

Highlight 02

Let us see how to calculate the interrupt line number.

In Linux IRQ to vector, mapping is done using FIRST_EXTERNAL_VECTOR macro.

To raise an interrupt IRQ 2, we have to add 2 to a vector of IRQ 0 as shown here.

Highlight asm("int $50") The asm instruction will be executed while opening the device file of our driver.

When this instruction executes, it will raise the interrupt IRQ 2.

Highlight free_irq(IRQ_NUM,(void *)irq_handler)

Highlight IRQ_NUM

When the driver unloads, we need to unregister the interrupt handler.

The free_irq function is used to remove the handler and disable the line if not shared.

If it is shared and no handlers remain on the line, the given interrupt line will be disabled.

Highlight free_irq(). In the exit function, we have used the free function to remove the handler from the kernel.

It will unregister the interrupt handler from the kernel.

Save and close the file Now, save and close the file.

Type >> gedit user.c

Let us now open the user program.

Type gedit space user dot c.

The program will open and close a device using respective system calls.

Save and close the file.

Clear the screen.

Now, save and close the file.

Clear the screen.

Type >> sudo su.

Type >> system password

To be a superuser, type sudo space su.

Now type the system password.

Type >> make all

Type >> insmod interrupt.ko

Let’s compile the driver.

Type make space all

Clear the screen.

Now let us load the driver into the kernel.

Type insmod space interrupt dot ko.

Type cat /proc/interrupts | grep my_interrupt

/proc/interrupts

Type >> clear

Type cat space slash proc slash interrupts space pipe space grep space my_interrupt.

Interrupt file in procfs contains the list of registered interrupts in the system.

This command will show the registered interrupt my_interrupt and its IRQ line number.

In the output, we can see our registered interrupt name and IRQ number.

It indicates that our interrupt handler is registered successfully.

Clear the screen.

Type >> gcc -c user.c.


Type >> gcc -o user.out user.o

Now compile the user program.

Type gcc hyphen c user dot c

Type gcc hyphen o user dot out user dot o.

Type >> ./user.out

Highlight output

Type >> clear

Now let us execute the user program.

Type dot slash user dot out

Here, output shows that the device opened and closed successfully.

Clear the screen.

Type >> dmesg | grep my_driver

Type >> clear

Type dmesg space pipe space grep space my_driver.

This message shows that the device open function triggered the interrupt.

It indicates that as soon as the interrupt triggered, its handler got executed.

After the execution of the handler, the remaining code from the open function is executed.

It shows that the driver properly handled the interrupt.

Clear the screen.

Type >> rmmod interrupt.ko

Type >> dmesg | grep my_driver

Type >> clear

Now let's unload the driver.

Type rmmod space interrupt dot ko

Let us see the unloaded printk messages.

Type dmesg space pipe space grep space my_driver.

Here, we can see our interrupt handler is unregistered from the kernel.

Clear the screen.

Type >> make clean. To remove the object files, type make space clean.
With this, we come to the end of this tutorial. Let us summarise.
Slide 11:

Summary:

In this tutorial, we learnt
  • Interrupt Handling in the driver
Slide 12:

Assignment :

As an assignment:
  1. Open the interrupt.c driver file.
  2. Write the interrupt instruction in the release function.
  3. Compile and load the driver.
  4. Compile and execute the user program.
  5. See the output using dmesg command.
Slide 13:

About Spoken Tutorial Project:

  • The video at the following link summarizes the Spoken Tutorial project.
  • Please download and watch it.
Slide 14:

Spoken Tutorial workshops :

The Spoken Tutorial Project Team conducts workshops and gives certificates.

For more details, please write to us.

Slide 15:

Forum questions :

Please post your timed queries in this forum
Slide 16:

Forum for specific questions :

  • Do you have any general or technical questions on Embedded Linux Device Driver?
  • Please visit the FOSSEE forum and post your question
Slide 17:

Acknowledgment:

The Spoken Tutorial Project is funded by MHRD, Government of India.
Slide 18:

Thank you slide:

This tutorial has been contributed by FOSSEE and Spoken Tutorial Project, IIT Bombay.

This is Usha signing off.

Thanks for watching.

Contributors and Content Editors

Nancyvarkey, Nirmala Venkat