new autosuspend code for hid

Oliver Neukum <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
Hi,

this is the new autosuspend code separately.

	Regards
		Oliver

-------

--- linux-2.6.20/include/linux/hid.h	2007-02-06 14:14:56.000000000 +0100
+++ linux-stern/include/linux/hid.h	2007-02-15 14:26:18.000000000 +0100
@@ -389,6 +389,8 @@
 #define HID_RESET_PENDING	4
 #define HID_SUSPENDED		5
 #define HID_CLEAR_HALT		6
+#define HID_BUSY		7
+#define HID_REPORTED_IDLE	8
 
 struct hid_input {
 	struct list_head list;
--- linux-2.6.20/drivers/usb/input/usbhid.h	2007-02-06 14:14:49.000000000 +0100
+++ linux-stern/drivers/usb/input/usbhid.h	2007-02-15 14:17:59.000000000 +0100
@@ -63,21 +63,24 @@
 	unsigned char ctrlhead, ctrltail;                               /* Control fifo head & tail */
 	char *ctrlbuf;                                                  /* Control buffer */
 	dma_addr_t ctrlbuf_dma;                                         /* Control buffer dma */
-	spinlock_t ctrllock;                                            /* Control fifo spinlock */
 
 	struct urb *urbout;                                             /* Output URB */
 	struct hid_report *out[HID_CONTROL_FIFO_SIZE];                  /* Output pipe fifo */
 	unsigned char outhead, outtail;                                 /* Output pipe fifo head & tail */
 	char *outbuf;                                                   /* Output buffer */
 	dma_addr_t outbuf_dma;                                          /* Output buffer dma */
-	spinlock_t outlock;                                             /* Output fifo spinlock */
 
-	unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
-	struct timer_list io_retry;                                     /* Retry timer */
-	unsigned long stop_retry;                                       /* Time to give up, in jiffies */
-	unsigned int retry_delay;                                       /* Delay length in ms */
-	struct work_struct reset_work;                                  /* Task context for resets */
+	spinlock_t outputlock;                                             /* Output fifo spinlock */
 
+	unsigned long iofl;					/* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
+	struct timer_list io_retry;				/* Retry timer */
+	struct timer_list idle_timer;				/* timer to determine idleness */
+	unsigned long stop_retry;				/* Time to give up, in jiffies */
+	unsigned int idle_time;					/* Time to determine idleness, in seconds */
+	unsigned int retry_delay;				/* Delay length in ms */
+	struct work_struct reset_work;				/* Task context for resets */
+	struct work_struct idle_work;				/* Task context for reporting idleness */
+	struct work_struct restart_work;			/* waking up for output to be done in task context */
 };
 
 #define	hid_to_usb_dev(hid_dev) \
--- linux-2.6.20/drivers/usb/input/hid-core.c	2007-02-06 14:14:48.000000000 +0100
+++ linux-stern/drivers/usb/input/hid-core.c	2007-02-15 15:47:37.000000000 +0100
@@ -5,6 +5,7 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <[email protected]>
  *  Copyright (c) 2005 Michael Haboustak <[email protected]> for Concept2, Inc
  *  Copyright (c) 2006 Jiri Kosina
+ *  Copyright (c) 2007 Oliver Neukum
  */
 
 /*
@@ -56,11 +57,15 @@
 module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
 MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
 
+static DEFINE_MUTEX(hid_open_mut);
+
 /*
  * Input submission and I/O error handler.
  */
 
 static void hid_io_error(struct hid_device *hid);
+static int hid_submit_out(struct hid_device *hid);
+static int hid_submit_ctrl(struct hid_device *hid);
 
 /* Start up the input URB */
 static int hid_start_in(struct hid_device *hid)
@@ -169,6 +174,44 @@
 	spin_unlock_irqrestore(&usbhid->inlock, flags);
 }
 
+static int usbhid_restart_out_queue(struct usbhid_device *usbhid)
+{
+	struct hid_device *hid = usb_get_intfdata(usbhid->intf);
+	int kicked;
+
+	WARN_ON(hid == NULL);
+	if (!hid)
+		return 0;
+
+	if ((kicked = (usbhid->outhead != usbhid->outtail))) {
+		dbg("Kicking head %d tail %d", usbhid->outhead, usbhid->outtail);
+		if (hid_submit_out(hid)) {
+			clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+			wake_up(&hid->wait);
+		}
+	}
+	return kicked;
+}
+
+static int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid)
+{
+	struct hid_device *hid = usb_get_intfdata(usbhid->intf);
+	int kicked;
+
+	WARN_ON(hid == NULL);
+	if (!hid)
+		return 0;
+
+	if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) {
+		dbg("Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail);
+		if (hid_submit_ctrl(hid)) {
+			clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+			wake_up(&hid->wait);
+		}
+	}
+	return kicked;
+}
+
 /*
  * Input interrupt completion handler.
  */
@@ -181,12 +224,14 @@
 
 	switch (urb->status) {
 		case 0:			/* success */
+			set_bit(HID_BUSY, &usbhid->iofl);
 			usbhid->retry_delay = 0;
 			hid_input_report(urb->context, HID_INPUT_REPORT,
 					 urb->transfer_buffer,
 					 urb->actual_length, 1);
 			break;
 		case -EPIPE:		/* stall */
+			set_bit(HID_BUSY, &usbhid->iofl);
 			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
 			set_bit(HID_CLEAR_HALT, &usbhid->iofl);
 			schedule_work(&usbhid->reset_work);
@@ -200,6 +245,7 @@
 		case -EPROTO:		/* protocol error or unplug */
 		case -ETIME:		/* protocol error or unplug */
 		case -ETIMEDOUT:	/* Should never happen, but... */
+			set_bit(HID_BUSY, &usbhid->iofl);
 			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
 			hid_io_error(hid);
 			return;
@@ -242,9 +288,11 @@
 	struct hid_report *report;
 	struct usbhid_device *usbhid = hid->driver_data;
 
+	WARN_ON(usbhid == NULL);
 	report = usbhid->out[usbhid->outtail];
-
+	WARN_ON(report == NULL);
 	hid_output_report(report, usbhid->outbuf);
+	BUG_ON(usbhid->urbout == NULL);
 	usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
 	usbhid->urbout->dev = hid_to_usb_dev(hid);
 
@@ -332,24 +380,20 @@
 			warn("output irq status %d received", urb->status);
 	}
 
-	spin_lock_irqsave(&usbhid->outlock, flags);
+	spin_lock_irqsave(&usbhid->outputlock, flags);
 
 	if (unplug)
 		usbhid->outtail = usbhid->outhead;
 	else
 		usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
 
-	if (usbhid->outhead != usbhid->outtail) {
-		if (hid_submit_out(hid)) {
-			clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
-			wake_up(&hid->wait);
-		}
-		spin_unlock_irqrestore(&usbhid->outlock, flags);
+	if (usbhid_restart_out_queue(usbhid)) {
+		spin_unlock_irqrestore(&usbhid->outputlock, flags);
 		return;
 	}
 
 	clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
-	spin_unlock_irqrestore(&usbhid->outlock, flags);
+	spin_unlock_irqrestore(&usbhid->outputlock, flags);
 	wake_up(&hid->wait);
 }
 
@@ -364,7 +408,7 @@
 	unsigned long flags;
 	int unplug = 0;
 
-	spin_lock_irqsave(&usbhid->ctrllock, flags);
+	spin_lock_irqsave(&usbhid->outputlock, flags);
 
 	switch (urb->status) {
 		case 0:			/* success */
@@ -389,24 +433,55 @@
 	else
 		usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
 
-	if (usbhid->ctrlhead != usbhid->ctrltail) {
-		if (hid_submit_ctrl(hid)) {
-			clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
-			wake_up(&hid->wait);
-		}
-		spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+	if (usbhid_restart_ctrl_queue(usbhid)) {
+		spin_unlock_irqrestore(&usbhid->outputlock, flags);
 		return;
 	}
 
 	clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
-	spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+	spin_unlock_irqrestore(&usbhid->outputlock, flags);
 	wake_up(&hid->wait);
 }
 
-void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+static int usbhid_queue_report_out(struct hid_device *hid, struct hid_report *report)
 {
+	struct usbhid_device *usbhid = hid->driver_data;
 	int head;
-	unsigned long flags;
+
+	if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
+		warn("output queue full");
+		return 0;
+	}
+
+	usbhid->out[usbhid->outhead] = report;
+	usbhid->outhead = head;
+
+	return usbhid->outhead < usbhid->outtail ?
+		usbhid->outtail - usbhid->outhead :
+		HID_OUTPUT_FIFO_SIZE - usbhid->outhead + usbhid->outtail;
+}
+
+static int usbhid_queue_report_ctrl(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+{
+	struct usbhid_device *usbhid = hid->driver_data;
+	int head;
+
+	if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
+		warn("control queue full");
+		return 0;
+	}
+
+	usbhid->ctrl[usbhid->ctrlhead].report = report;
+	usbhid->ctrl[usbhid->ctrlhead].dir = dir;
+	usbhid->ctrlhead = head;
+
+	return usbhid->ctrlhead < usbhid->ctrltail ?
+		usbhid->ctrltail - usbhid->ctrlhead :
+		HID_CONTROL_FIFO_SIZE - usbhid->ctrlhead + usbhid->ctrltail;
+}
+
+static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+{
 	struct usbhid_device *usbhid = hid->driver_data;
 
 	if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
@@ -414,49 +489,53 @@
 
 	if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
 
-		spin_lock_irqsave(&usbhid->outlock, flags);
-
-		if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
-			spin_unlock_irqrestore(&usbhid->outlock, flags);
-			warn("output queue full");
-			return;
-		}
-
-		usbhid->out[usbhid->outhead] = report;
-		usbhid->outhead = head;
+		usbhid_queue_report_out(hid, report);
 
 		if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
 			if (hid_submit_out(hid))
 				clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
 
-		spin_unlock_irqrestore(&usbhid->outlock, flags);
-		return;
-	}
+	} else {
 
-	spin_lock_irqsave(&usbhid->ctrllock, flags);
+		usbhid_queue_report_ctrl(hid, report, dir);
+
+		if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+			if (hid_submit_ctrl(hid))
+				clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
 
-	if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
-		spin_unlock_irqrestore(&usbhid->ctrllock, flags);
-		warn("control queue full");
-		return;
 	}
+}
 
-	usbhid->ctrl[usbhid->ctrlhead].report = report;
-	usbhid->ctrl[usbhid->ctrlhead].dir = dir;
-	usbhid->ctrlhead = head;
+void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+{
+	struct usbhid_device *usbhid = hid->driver_data;
+	unsigned long flags;
 
-	if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))
-		if (hid_submit_ctrl(hid))
-			clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+	spin_lock_irqsave(&usbhid->outputlock, flags);
+	__usbhid_submit_report(hid, report, dir);
+	spin_unlock_irqrestore(&usbhid->outputlock, flags);
+}
 
-	spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+static int usbhid_queue_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+{
+	struct usbhid_device *usbhid = hid->driver_data;
+	int rv;
+
+	if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
+		rv = usbhid_queue_report_out(hid, report);
+	} else {
+		rv = usbhid_queue_report_ctrl(hid, report, dir);
+	}
+	return rv;
 }
 
 static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
 	struct hid_device *hid = dev->private;
+	struct usbhid_device *usbhid = hid->driver_data;
 	struct hid_field *field;
-	int offset;
+	unsigned long flags;
+	int offset, used;
 
 	if (type == EV_FF)
 		return input_ff_event(dev, type, code, value);
@@ -469,9 +548,21 @@
 		return -1;
 	}
 
+	spin_lock_irqsave(&usbhid->outputlock, flags);
+
 	hid_set_field(field, offset, value);
-	usbhid_submit_report(hid, field->report, USB_DIR_OUT);
+	if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) {
+		/* the device isn't idle, we do the output now*/
+		__usbhid_submit_report(hid, field->report, USB_DIR_OUT);
+	} else {
+		/* the device is idle, queue the request
+		and wake it up if the queue fills up too much*/
+		used = usbhid_queue_report(hid, field->report, USB_DIR_OUT);
+		if ( 3 < HID_OUTPUT_FIFO_SIZE - used)
+			schedule_work(&usbhid->restart_work);
 
+	}
+	spin_unlock_irqrestore(&usbhid->outputlock, flags);
 	return 0;
 }
 
@@ -514,7 +605,23 @@
 
 int usbhid_open(struct hid_device *hid)
 {
-	++hid->open;
+	struct usbhid_device *usbhid = hid->driver_data;
+	int res;
+
+	set_bit(HID_BUSY, &usbhid->iofl);
+	mutex_lock(&hid_open_mut);
+	if (!hid->open++) {
+		res = usb_autopm_get_interface(usbhid->intf);
+		/* this has a twofold purpose */
+		if (res < 0) {
+			hid->open--;
+			mutex_unlock(&hid_open_mut);
+			return -EIO;
+		}
+		usbhid->intf->needs_remote_wakeup = 1;
+		usb_autopm_put_interface(usbhid->intf);
+	}
+	mutex_unlock(&hid_open_mut);
 	if (hid_start_in(hid))
 		hid_io_error(hid);
 	return 0;
@@ -524,8 +631,15 @@
 {
 	struct usbhid_device *usbhid = hid->driver_data;
 
-	if (!--hid->open)
+	mutex_lock(&hid_open_mut);
+	if (!--hid->open) {
 		usb_kill_urb(usbhid->urbin);
+		flush_scheduled_work();
+		usbhid->intf->needs_remote_wakeup = 0;
+		if (!test_and_clear_bit(HID_REPORTED_IDLE, &usbhid->iofl))
+			usb_autopm_put_interface(usbhid->intf);
+	}
+	mutex_unlock(&hid_open_mut);
 }
 
 static int hidinput_open(struct input_dev *dev)
@@ -552,14 +666,21 @@
 void usbhid_init_reports(struct hid_device *hid)
 {
 	struct hid_report *report;
-	struct usbhid_device *usbhid = hid->driver_data;
+	unsigned long flags;
 	int err, ret;
+	struct usbhid_device *usbhid = hid->driver_data;
 
-	list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
-		usbhid_submit_report(hid, report, USB_DIR_IN);
+	list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) {
+		spin_lock_irqsave(&usbhid->outputlock, flags);
+		__usbhid_submit_report(hid, report, USB_DIR_IN);
+		spin_unlock_irqrestore(&usbhid->outputlock, flags);
+	}
 
-	list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
-		usbhid_submit_report(hid, report, USB_DIR_IN);
+	list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) {
+		spin_lock_irqsave(&usbhid->outputlock, flags);
+		__usbhid_submit_report(hid, report, USB_DIR_IN);
+		spin_unlock_irqrestore(&usbhid->outputlock, flags);
+	}
 
 	err = 0;
 	ret = usbhid_wait_io(hid);
@@ -1005,6 +1126,41 @@
 	return 0;
 }
 
+static void usbhid_restart_queues(struct usbhid_device *usbhid)
+{
+	if (usbhid->urbout)
+		usbhid_restart_out_queue(usbhid);
+	usbhid_restart_ctrl_queue(usbhid);
+}
+
+static void __usbhid_restart_queues(struct work_struct *work)
+{
+	struct usbhid_device *usbhid =
+		container_of(work, struct usbhid_device, restart_work);
+
+	usb_autopm_get_interface(usbhid->intf);
+	usbhid_restart_queues(usbhid);
+	usb_autopm_put_interface(usbhid->intf);
+}
+
+static int hid_check_busy(struct usb_interface *intf)
+{
+	struct hid_device *hid = usb_get_intfdata(intf);
+	struct usbhid_device *usbhid = hid->driver_data;
+	unsigned long flags;
+	int rv;
+
+	spin_lock_irqsave(&usbhid->outputlock, flags);
+	rv = test_and_clear_bit(HID_BUSY, &usbhid->iofl)
+		|| test_bit(HID_OUT_RUNNING, &usbhid->iofl)
+		|| test_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+	if (!rv)
+		set_bit(HID_REPORTED_IDLE, &usbhid->iofl);
+	spin_unlock_irqrestore(&usbhid->outputlock, flags);
+printk(KERN_ERR"%s - reporting %d at %ld\n", __FUNCTION__, rv, jiffies);
+	return rv;
+}
+
 static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
 {
 	struct usbhid_device *usbhid = hid->driver_data;
@@ -1183,17 +1339,18 @@
 	init_waitqueue_head(&hid->wait);
 
 	INIT_WORK(&usbhid->reset_work, hid_reset);
+	INIT_WORK(&usbhid->restart_work, __usbhid_restart_queues);
 	setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
 
 	spin_lock_init(&usbhid->inlock);
-	spin_lock_init(&usbhid->outlock);
-	spin_lock_init(&usbhid->ctrllock);
+	spin_lock_init(&usbhid->outputlock);
 
 	hid->version = le16_to_cpu(hdesc->bcdHID);
 	hid->country = hdesc->bCountryCode;
 	hid->dev = &intf->dev;
 	usbhid->intf = intf;
 	usbhid->ifnum = interface->desc.bInterfaceNumber;
+	usbhid->idle_time = 10; //FIXME
 
 	hid->name[0] = 0;
 
@@ -1299,6 +1456,8 @@
 	if (!(hid = usb_hid_configure(intf)))
 		return -ENODEV;
 
+	usb_set_intfdata(intf, hid);
+
 	usbhid_init_reports(hid);
 	hid_dump_device(hid);
 
@@ -1307,7 +1466,6 @@
 	if (!hiddev_connect(hid))
 		hid->claimed |= HID_CLAIMED_HIDDEV;
 
-	usb_set_intfdata(intf, hid);
 
 	if (!hid->claimed) {
 		printk ("HID device not claimed by input or hiddev\n");
@@ -1351,7 +1509,7 @@
 
 static int hid_suspend(struct usb_interface *intf, pm_message_t message)
 {
-	struct hid_device *hid = usb_get_intfdata (intf);
+	struct hid_device *hid = usb_get_intfdata(intf);
 	struct usbhid_device *usbhid = hid->driver_data;
 
 	spin_lock_irq(&usbhid->inlock);	/* Sync with error handler */
@@ -1359,6 +1517,7 @@
 	spin_unlock_irq(&usbhid->inlock);
 	del_timer(&usbhid->io_retry);
 	usb_kill_urb(usbhid->urbin);
+	flush_scheduled_work();
 	dev_dbg(&intf->dev, "suspend\n");
 	return 0;
 }
@@ -1370,8 +1529,10 @@
 	int status;
 
 	clear_bit(HID_SUSPENDED, &usbhid->iofl);
+	set_bit(HID_BUSY, &usbhid->iofl);
 	usbhid->retry_delay = 0;
 	status = hid_start_in(hid);
+	usbhid_restart_queues(usbhid);
 	dev_dbg(&intf->dev, "resume status %d\n", status);
 	return status;
 }
@@ -1409,7 +1570,9 @@
 	.resume =	hid_resume,
 	.pre_reset =	hid_pre_reset,
 	.post_reset =	hid_post_reset,
+	.check_busy =	hid_check_busy,
 	.id_table =	hid_usb_ids,
+	.supports_autosuspend = 1,
 };
 
 static int __init hid_init(void)
--- linux-2.6.20/drivers/usb/input/hiddev.c	2007-02-06 14:14:49.000000000 +0100
+++ linux-stern/drivers/usb/input/hiddev.c	2007-02-15 11:24:17.000000000 +0100
@@ -496,8 +496,11 @@
 		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
 			return -EINVAL;
 
+		if (usb_autopm_get_interface(usbhid->intf) < 0)
+			return -EIO;
 		usbhid_submit_report(hid, report, USB_DIR_IN);
 		usbhid_wait_io(hid);
+		usb_autopm_put_interface(usbhid->intf);
 
 		return 0;
 
@@ -511,8 +514,11 @@
 		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
 			return -EINVAL;
 
+		if (usb_autopm_get_interface(usbhid->intf) < 0)
+			return -EIO;
 		usbhid_submit_report(hid, report, USB_DIR_OUT);
 		usbhid_wait_io(hid);
+		usb_autopm_put_interface(usbhid->intf);
 
 		return 0;
 

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.