[prev in list] [next in list] [prev in thread] [next in thread] 

List:       ros-diffs
Subject:    [ros-diffs]
From:       hpoussin () svn ! reactos ! org
Date:       2006-04-25 22:22:22
Message-ID: 200604252323.k3PNN1X0027001 () mailhost ! geldorp ! nl
[Download RAW message or body]

Author: hpoussin
Date: Wed Apr 26 02:22:22 2006
New Revision: 21741

URL: http://svn.reactos.ru/svn/reactos?rev=21741&view=rev
Log:
Complete IRP_MJ_CREATE, IRP_MJ_CLOSE, IRP_MJ_CLEANUP
Use correct buffer when filling read request. Use SEH when needed
Correctly propagate DO_BUFFERED_IO, DO_DIRECT_IO and FILE_DEVICE_SECURE_OPEN flags

Modified:
    trunk/reactos/drivers/input/kbdclass/kbdclass.c
    trunk/reactos/drivers/input/kbdclass/kbdclass.h
    trunk/reactos/drivers/input/kbdclass/kbdclass.rbuild
    trunk/reactos/drivers/input/mouclass/mouclass.c
    trunk/reactos/drivers/input/mouclass/mouclass.h
    trunk/reactos/drivers/input/mouclass/mouclass.rbuild

Modified: trunk/reactos/drivers/input/kbdclass/kbdclass.c
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/drivers/input/kbdclass/kbdclass.c?rev=21741&r1=21740&r2=21741&view=diff
 ==============================================================================
--- trunk/reactos/drivers/input/kbdclass/kbdclass.c (original)
+++ trunk/reactos/drivers/input/kbdclass/kbdclass.c Wed Apr 26 02:22:22 2006
@@ -35,6 +35,9 @@
 		return ForwardIrpAndForget(DeviceObject, Irp);
 
 	/* FIXME: open all associated Port devices */
+	Irp->IoStatus.Status = STATUS_SUCCESS;
+	Irp->IoStatus.Information = 0;
+	IoCompleteRequest(Irp, IO_NO_INCREMENT);
 	return STATUS_SUCCESS;
 }
 
@@ -49,6 +52,9 @@
 		return ForwardIrpAndForget(DeviceObject, Irp);
 
 	/* FIXME: close all associated Port devices */
+	Irp->IoStatus.Status = STATUS_SUCCESS;
+	Irp->IoStatus.Information = 0;
+	IoCompleteRequest(Irp, IO_NO_INCREMENT);
 	return STATUS_SUCCESS;
 }
 
@@ -63,6 +69,9 @@
 		return ForwardIrpAndForget(DeviceObject, Irp);
 
 	/* FIXME: cleanup all associated Port devices */
+	Irp->IoStatus.Status = STATUS_SUCCESS;
+	Irp->IoStatus.Information = 0;
+	IoCompleteRequest(Irp, IO_NO_INCREMENT);
 	return STATUS_SUCCESS;
 }
 
@@ -361,7 +370,8 @@
 	DeviceExtension->ReadIsPending = FALSE;
 	DeviceExtension->InputCount = 0;
 	DeviceExtension->PortData = ExAllocatePool(NonPagedPool, \
                DeviceExtension->DriverExtension->DataQueueSize * \
                sizeof(KEYBOARD_INPUT_DATA));
-	Fdo->Flags |= DO_POWER_PAGABLE | DO_BUFFERED_IO;
+	Fdo->Flags |= DO_POWER_PAGABLE;
+	Fdo->Flags |= DO_BUFFERED_IO; /* FIXME: Why is it needed for 1st stage setup? */
 	Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
 
 	/* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
@@ -381,6 +391,53 @@
 	return STATUS_SUCCESS;
 }
 
+static NTSTATUS
+FillOneEntry(
+	IN PDEVICE_OBJECT ClassDeviceObject,
+	IN PIRP Irp,
+	IN PKEYBOARD_INPUT_DATA DataStart)
+{
+	NTSTATUS Status = STATUS_SUCCESS;
+
+	if (ClassDeviceObject->Flags & DO_BUFFERED_IO)
+	{
+		RtlCopyMemory(
+			Irp->AssociatedIrp.SystemBuffer,
+			DataStart,
+			sizeof(KEYBOARD_INPUT_DATA));
+	}
+	else if (ClassDeviceObject->Flags & DO_DIRECT_IO)
+	{
+		PVOID DestAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, \
NormalPagePriority); +		if (DestAddress)
+		{
+			RtlCopyMemory(
+				DestAddress,
+				DataStart,
+				sizeof(KEYBOARD_INPUT_DATA));
+		}
+		else
+			Status = STATUS_UNSUCCESSFUL;
+	}
+	else
+	{
+		_SEH_TRY
+		{
+			RtlCopyMemory(
+				Irp->UserBuffer,
+				DataStart,
+				sizeof(KEYBOARD_INPUT_DATA));
+		}
+		_SEH_HANDLE
+		{
+			Status = _SEH_GetExceptionCode();
+		}
+		_SEH_END;
+	}
+
+	return Status;
+}
+
 static BOOLEAN
 ClassCallback(
 	IN PDEVICE_OBJECT ClassDeviceObject,
@@ -406,28 +463,32 @@
 	 */
 	if (ClassDeviceExtension->ReadIsPending == TRUE && InputCount)
 	{
+		NTSTATUS Status;
+
 		Irp = ClassDeviceObject->CurrentIrp;
 		ClassDeviceObject->CurrentIrp = NULL;
 		Stack = IoGetCurrentIrpStackLocation(Irp);
 
 		/* A read request is waiting for input, so go straight to it */
-		/* FIXME: use SEH */
-		RtlCopyMemory(
-			Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, \
                NormalPagePriority) : Irp->AssociatedIrp.SystemBuffer,
-			DataStart,
-			sizeof(KEYBOARD_INPUT_DATA));
-
-		/* Go to next packet and complete this request with STATUS_SUCCESS */
-		Irp->IoStatus.Status = STATUS_SUCCESS;
-		Irp->IoStatus.Information = sizeof(KEYBOARD_INPUT_DATA);
-		Stack->Parameters.Read.Length = sizeof(KEYBOARD_INPUT_DATA);
-
-		ClassDeviceExtension->ReadIsPending = FALSE;
-
-		/* Skip the packet we just sent away */
-		DataStart++;
-		(*ConsumedCount)++;
-		InputCount--;
+		Status = FillOneEntry(
+			ClassDeviceObject,
+			Irp,
+			DataStart);
+
+		if (NT_SUCCESS(Status))
+		{
+			/* Go to next packet and complete this request with STATUS_SUCCESS */
+			Irp->IoStatus.Status = STATUS_SUCCESS;
+			Irp->IoStatus.Information = sizeof(KEYBOARD_INPUT_DATA);
+			Stack->Parameters.Read.Length = sizeof(KEYBOARD_INPUT_DATA);
+
+			ClassDeviceExtension->ReadIsPending = FALSE;
+
+			/* Skip the packet we just sent away */
+			DataStart++;
+			(*ConsumedCount)++;
+			InputCount--;
+		}
 	}
 
 	/* If we have data from the port driver and a higher service to send the data to */
@@ -439,9 +500,11 @@
 			ReadSize = InputCount;
 
 		/*
-		 * FIXME: If we exceed the buffer, data gets thrown away.. better
-		 * solution?
-		*/
+		 * If we exceed the buffer, data gets thrown away...
+		 * Try at least to display a dialog
+		 */
+		if (Irp != NULL)
+			IoRaiseHardError(Irp, NULL, ClassDeviceObject);
 
 		/*
 		 * Move the input data from the port data queue to our class data
@@ -549,7 +612,7 @@
 		sizeof(PORT_DEVICE_EXTENSION),
 		NULL,
 		Pdo->DeviceType,
-		FILE_DEVICE_SECURE_OPEN,
+		Pdo->Characteristics & FILE_DEVICE_SECURE_OPEN ? FILE_DEVICE_SECURE_OPEN : 0,
 		TRUE,
 		&Fdo);
 	if (!NT_SUCCESS(Status))
@@ -573,6 +636,8 @@
 		Fdo->Flags |= DO_POWER_PAGABLE;
 	if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO)
 		Fdo->Flags |= DO_BUFFERED_IO;
+	if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO)
+		Fdo->Flags |= DO_DIRECT_IO;
 
 	if (DriverExtension->ConnectMultiplePorts)
 		DeviceExtension->ClassDO = DriverExtension->MainClassDeviceObject;
@@ -646,35 +711,35 @@
 	if (DeviceExtension->InputCount > 0)
 	{
 		KIRQL oldIrql;
+		NTSTATUS Status;
 
 		KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql);
 
-		DPRINT("Mdl: %p, UserBuffer: %p, InputCount: %lu\n",
-			Irp->MdlAddress,
-			Irp->UserBuffer,
-			DeviceExtension->InputCount);
-
-		/* FIXME: use SEH */
-		RtlCopyMemory(
-			Irp->AssociatedIrp.SystemBuffer,
-			DeviceExtension->PortData - DeviceExtension->InputCount,
-			sizeof(KEYBOARD_INPUT_DATA));
-
-		if (DeviceExtension->InputCount > 1)
-		{
-			RtlMoveMemory(
-				DeviceExtension->PortData - DeviceExtension->InputCount,
-				DeviceExtension->PortData - DeviceExtension->InputCount + 1,
-				(DeviceExtension->InputCount - 1) * sizeof(KEYBOARD_INPUT_DATA));
-		}
-		DeviceExtension->PortData--;
-		DeviceExtension->InputCount--;
-		DeviceExtension->ReadIsPending = FALSE;
-
-		/* Go to next packet and complete this request with STATUS_SUCCESS */
-		Irp->IoStatus.Status = STATUS_SUCCESS;
-		Irp->IoStatus.Information = sizeof(KEYBOARD_INPUT_DATA);
-		Stack->Parameters.Read.Length = sizeof(KEYBOARD_INPUT_DATA);
+		Status = FillOneEntry(
+			DeviceObject,
+			Irp,
+			DeviceExtension->PortData - DeviceExtension->InputCount);
+
+		if (NT_SUCCESS(Status))
+		{
+			if (DeviceExtension->InputCount > 1)
+			{
+				RtlMoveMemory(
+					DeviceExtension->PortData - DeviceExtension->InputCount,
+					DeviceExtension->PortData - DeviceExtension->InputCount + 1,
+					(DeviceExtension->InputCount - 1) * sizeof(KEYBOARD_INPUT_DATA));
+			}
+
+			DeviceExtension->PortData--;
+			DeviceExtension->InputCount--;
+			DeviceExtension->ReadIsPending = FALSE;
+
+			Irp->IoStatus.Information = sizeof(KEYBOARD_INPUT_DATA);
+			Stack->Parameters.Read.Length = sizeof(KEYBOARD_INPUT_DATA);
+		}
+
+		/* Go to next packet and complete this request */
+		Irp->IoStatus.Status = Status;
 		IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
 
 		IoStartNextPacket(DeviceObject, FALSE);

Modified: trunk/reactos/drivers/input/kbdclass/kbdclass.h
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/drivers/input/kbdclass/kbdclass.h?rev=21741&r1=21740&r2=21741&view=diff
 ==============================================================================
--- trunk/reactos/drivers/input/kbdclass/kbdclass.h (original)
+++ trunk/reactos/drivers/input/kbdclass/kbdclass.h Wed Apr 26 02:22:22 2006
@@ -1,6 +1,7 @@
 #include <ntifs.h>
 #include <kbdmou.h>
 #include <ntddkbd.h>
+#include <pseh/pseh.h>
 #include <stdio.h>
 
 #define MAX_PATH 260

Modified: trunk/reactos/drivers/input/kbdclass/kbdclass.rbuild
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/drivers/input/kbdclass/kbdclass.rbuild?rev=21741&r1=21740&r2=21741&view=diff
 ==============================================================================
--- trunk/reactos/drivers/input/kbdclass/kbdclass.rbuild (original)
+++ trunk/reactos/drivers/input/kbdclass/kbdclass.rbuild Wed Apr 26 02:22:22 2006
@@ -1,6 +1,7 @@
 <module name="kbdclass" type="kernelmodedriver" installbase="system32/drivers" \
installname="kbdclass.sys">  <bootstrap base="reactos" />
 	<define name="__USE_W32API" />
+	<library>pseh</library>
 	<library>ntoskrnl</library>
 	<library>hal</library>
 	<file>kbdclass.c</file>

Modified: trunk/reactos/drivers/input/mouclass/mouclass.c
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/drivers/input/mouclass/mouclass.c?rev=21741&r1=21740&r2=21741&view=diff
 ==============================================================================
--- trunk/reactos/drivers/input/mouclass/mouclass.c (original)
+++ trunk/reactos/drivers/input/mouclass/mouclass.c Wed Apr 26 02:22:22 2006
@@ -35,6 +35,9 @@
 		return ForwardIrpAndForget(DeviceObject, Irp);
 
 	/* FIXME: open all associated Port devices */
+	Irp->IoStatus.Status = STATUS_SUCCESS;
+	Irp->IoStatus.Information = 0;
+	IoCompleteRequest(Irp, IO_NO_INCREMENT);
 	return STATUS_SUCCESS;
 }
 
@@ -49,6 +52,9 @@
 		return ForwardIrpAndForget(DeviceObject, Irp);
 
 	/* FIXME: close all associated Port devices */
+	Irp->IoStatus.Status = STATUS_SUCCESS;
+	Irp->IoStatus.Information = 0;
+	IoCompleteRequest(Irp, IO_NO_INCREMENT);
 	return STATUS_SUCCESS;
 }
 
@@ -63,6 +69,9 @@
 		return ForwardIrpAndForget(DeviceObject, Irp);
 
 	/* FIXME: cleanup all associated Port devices */
+	Irp->IoStatus.Status = STATUS_SUCCESS;
+	Irp->IoStatus.Information = 0;
+	IoCompleteRequest(Irp, IO_NO_INCREMENT);
 	return STATUS_SUCCESS;
 }
 
@@ -114,7 +123,7 @@
 			PLIST_ENTRY Head = \
&((PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->ListHead;  if (Head->Flink \
!= Head)  {
-				/* We have at least one keyboard */
+				/* We have at least one mouse */
 				PPORT_DEVICE_EXTENSION DevExt = CONTAINING_RECORD(Head->Flink, \
                PORT_DEVICE_EXTENSION, ListEntry);
 				IoGetCurrentIrpStackLocation(Irp)->MajorFunction = \
IRP_MJ_INTERNAL_DEVICE_CONTROL;  IoSkipCurrentIrpStackLocation(Irp);
@@ -358,6 +367,53 @@
 	return STATUS_SUCCESS;
 }
 
+static NTSTATUS
+FillOneEntry(
+	IN PDEVICE_OBJECT ClassDeviceObject,
+	IN PIRP Irp,
+	IN PMOUSE_INPUT_DATA DataStart)
+{
+	NTSTATUS Status = STATUS_SUCCESS;
+
+	if (ClassDeviceObject->Flags & DO_BUFFERED_IO)
+	{
+		RtlCopyMemory(
+			Irp->AssociatedIrp.SystemBuffer,
+			DataStart,
+			sizeof(MOUSE_INPUT_DATA));
+	}
+	else if (ClassDeviceObject->Flags & DO_DIRECT_IO)
+	{
+		PVOID DestAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, \
NormalPagePriority); +		if (DestAddress)
+		{
+			RtlCopyMemory(
+				DestAddress,
+				DataStart,
+				sizeof(MOUSE_INPUT_DATA));
+		}
+		else
+			Status = STATUS_UNSUCCESSFUL;
+	}
+	else
+	{
+		_SEH_TRY
+		{
+			RtlCopyMemory(
+				Irp->UserBuffer,
+				DataStart,
+				sizeof(MOUSE_INPUT_DATA));
+		}
+		_SEH_HANDLE
+		{
+			Status = _SEH_GetExceptionCode();
+		}
+		_SEH_END;
+	}
+
+	return Status;
+}
+
 static BOOLEAN
 ClassCallback(
 	IN PDEVICE_OBJECT ClassDeviceObject,
@@ -383,28 +439,32 @@
 	 */
 	if (ClassDeviceExtension->ReadIsPending == TRUE && InputCount)
 	{
+		NTSTATUS Status;
+
 		Irp = ClassDeviceObject->CurrentIrp;
 		ClassDeviceObject->CurrentIrp = NULL;
 		Stack = IoGetCurrentIrpStackLocation(Irp);
 
 		/* A read request is waiting for input, so go straight to it */
-		/* FIXME: use SEH */
-		RtlCopyMemory(
-			Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, \
                NormalPagePriority) : Irp->UserBuffer,
-			DataStart,
-			sizeof(MOUSE_INPUT_DATA));
-
-		/* Go to next packet and complete this request with STATUS_SUCCESS */
-		Irp->IoStatus.Status = STATUS_SUCCESS;
-		Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA);
-		Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA);
-
-		ClassDeviceExtension->ReadIsPending = FALSE;
-
-		/* Skip the packet we just sent away */
-		DataStart++;
-		(*ConsumedCount)++;
-		InputCount--;
+		Status = FillOneEntry(
+			ClassDeviceObject,
+			Irp,
+			DataStart);
+
+		if (NT_SUCCESS(Status))
+		{
+			/* Go to next packet and complete this request with STATUS_SUCCESS */
+			Irp->IoStatus.Status = STATUS_SUCCESS;
+			Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA);
+			Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA);
+
+			ClassDeviceExtension->ReadIsPending = FALSE;
+
+			/* Skip the packet we just sent away */
+			DataStart++;
+			(*ConsumedCount)++;
+			InputCount--;
+		}
 	}
 
 	/* If we have data from the port driver and a higher service to send the data to */
@@ -416,9 +476,11 @@
 			ReadSize = InputCount;
 
 		/*
-		 * FIXME: If we exceed the buffer, data gets thrown away.. better
-		 * solution?
-		*/
+		 * If we exceed the buffer, data gets thrown away...
+		 * Try at least to display a dialog
+		 */
+		if (Irp != NULL)
+			IoRaiseHardError(Irp, NULL, ClassDeviceObject);
 
 		/*
 		 * Move the input data from the port data queue to our class data
@@ -526,7 +588,7 @@
 		sizeof(PORT_DEVICE_EXTENSION),
 		NULL,
 		Pdo->DeviceType,
-		FILE_DEVICE_SECURE_OPEN,
+		Pdo->Characteristics & FILE_DEVICE_SECURE_OPEN ? FILE_DEVICE_SECURE_OPEN : 0,
 		TRUE,
 		&Fdo);
 	if (!NT_SUCCESS(Status))
@@ -550,6 +612,8 @@
 		Fdo->Flags |= DO_POWER_PAGABLE;
 	if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO)
 		Fdo->Flags |= DO_BUFFERED_IO;
+	if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO)
+		Fdo->Flags |= DO_DIRECT_IO;
 
 	if (DriverExtension->ConnectMultiplePorts)
 		DeviceExtension->ClassDO = DriverExtension->MainClassDeviceObject;
@@ -623,35 +687,35 @@
 	if (DeviceExtension->InputCount > 0)
 	{
 		KIRQL oldIrql;
+		NTSTATUS Status;
 
 		KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql);
 
-		DPRINT("Mdl: %p, UserBuffer: %p, InputCount: %lu\n",
-			Irp->MdlAddress,
-			Irp->UserBuffer,
-			DeviceExtension->InputCount);
-
-		/* FIXME: use SEH */
-		RtlCopyMemory(
-			Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, \
                NormalPagePriority) : Irp->UserBuffer,
-			DeviceExtension->PortData - DeviceExtension->InputCount,
-			sizeof(MOUSE_INPUT_DATA));
-
-		if (DeviceExtension->InputCount > 1)
-		{
-			RtlMoveMemory(
-				DeviceExtension->PortData - DeviceExtension->InputCount,
-				DeviceExtension->PortData - DeviceExtension->InputCount + 1,
-				(DeviceExtension->InputCount - 1) * sizeof(MOUSE_INPUT_DATA));
-		}
-		DeviceExtension->PortData--;
-		DeviceExtension->InputCount--;
-		DeviceExtension->ReadIsPending = FALSE;
-
-		/* Go to next packet and complete this request with STATUS_SUCCESS */
-		Irp->IoStatus.Status = STATUS_SUCCESS;
-		Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA);
-		Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA);
+		Status = FillOneEntry(
+			DeviceObject,
+			Irp,
+			DeviceExtension->PortData - DeviceExtension->InputCount);
+
+		if (NT_SUCCESS(Status))
+		{
+			if (DeviceExtension->InputCount > 1)
+			{
+				RtlMoveMemory(
+					DeviceExtension->PortData - DeviceExtension->InputCount,
+					DeviceExtension->PortData - DeviceExtension->InputCount + 1,
+					(DeviceExtension->InputCount - 1) * sizeof(MOUSE_INPUT_DATA));
+			}
+
+			DeviceExtension->PortData--;
+			DeviceExtension->InputCount--;
+			DeviceExtension->ReadIsPending = FALSE;
+
+			Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA);
+			Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA);
+		}
+
+		/* Go to next packet and complete this request */
+		Irp->IoStatus.Status = Status;
 		IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
 
 		IoStartNextPacket(DeviceObject, FALSE);

Modified: trunk/reactos/drivers/input/mouclass/mouclass.h
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/drivers/input/mouclass/mouclass.h?rev=21741&r1=21740&r2=21741&view=diff
 ==============================================================================
--- trunk/reactos/drivers/input/mouclass/mouclass.h (original)
+++ trunk/reactos/drivers/input/mouclass/mouclass.h Wed Apr 26 02:22:22 2006
@@ -1,6 +1,7 @@
 #include <ntifs.h>
 #include <kbdmou.h>
 #include <ntddmou.h>
+#include <pseh/pseh.h>
 #include <stdio.h>
 
 #define MAX_PATH 260

Modified: trunk/reactos/drivers/input/mouclass/mouclass.rbuild
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/drivers/input/mouclass/mouclass.rbuild?rev=21741&r1=21740&r2=21741&view=diff
 ==============================================================================
--- trunk/reactos/drivers/input/mouclass/mouclass.rbuild (original)
+++ trunk/reactos/drivers/input/mouclass/mouclass.rbuild Wed Apr 26 02:22:22 2006
@@ -1,6 +1,7 @@
 <module name="mouclass" type="kernelmodedriver" installbase="system32/drivers" \
installname="mouclass.sys">  <include base="mouclass">.</include>
 	<define name="__USE_W32API" />
+	<library>pseh</library>
 	<library>ntoskrnl</library>
 	<library>hal</library>
 	<file>misc.c</file>


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic