2004-01-21 09:45:26

by tuija t.

[permalink] [raw]
Subject: swusp acpi

Hi,

Sorry about the newbie question but I haven't managed
to get answer elsewhere :-)
I have a laptop (Fujitsu Lifebook C1020) Debian system
with linux-2.6.1 vanilla.
An I have wondered how I should but it in sleep?
# echo 4 > /proc/acpi/sleep
writes the ram in the swap:

Stopping tasks: ===================================================|
Freeing memory: ........................|
hdc: start_power_step(step: 0)
hdc: completing PM request, suspend
hda: start_power_step(step: 0)
hda: completing PM request, suspend
/critical section: Counting pages to copy[nosave c03cf000] (pages needed:
4727+512=5239 free: 118136)
Alloc pagedir
[nosave c03cf000]<4>Freeing prev allocated pagedir
eth0: link up, 100Mbps, full-duplex, lpa 0x45E1
hda: Wakeup request inited, waiting for !BSY...
hda: start_power_step(step: 1000)
hda: completing PM request, resume
hdc: Wakeup request inited, waiting for !BSY...
hdc: start_power_step(step: 1000)
hdc: completing PM request, resume
Fixing swap signatures... ok
Restarting tasks... done
And after reboot comes back to same than it was before
This behaviour is kind of "big sleep" and have to boot from grub.

When I do
# echo 3 > /proc/acpi/sleep
it beebs from bios and do:
PM: Preparing system for suspend
Stopping tasks: ===================================================|
hdc: start_power_step(step: 0)
hdc: completing PM request, suspend
hda: start_power_step(step: 0)
hda: start_power_step(step: 1)
hda: complete_power_step(step: 1, stat: 50, err: 0)
hda: completing PM request, suspend
PM: Entering state.
Back to C!
PM: Finishing up.
eth0: link up, 100Mbps, full-duplex, lpa 0x45E1
hda: Wakeup request inited, waiting for !BSY...
hda: start_power_step(step: 1000)
hda: completing PM request, resume
hdc: Wakeup request inited, waiting for !BSY...
hdc: start_power_step(step: 1000)
hdc: completing PM request, resume
Restarting tasks...<6>usb 1-1: USB disconnect, address 2
drivers/usb/host/uhci-hcd.c: 1200: host system error, PCI problems?
drivers/usb/host/uhci-hcd.c: 1200: host controller halted. very bad
drivers/usb/host/uhci-hcd.c: 1300: host system error, PCI problems?
drivers/usb/host/uhci-hcd.c: 1300: host controller halted. very bad
drivers/usb/host/uhci-hcd.c: 1700: host system error, PCI problems?
drivers/usb/host/uhci-hcd.c: 1700: host controller halted. very bad
psmouse: reconnect request, but serio is disconnected, ignoring...
done
hub 1-0:1.0: new USB device on port 1, assigned address 3
usb 1-1: control timeout on ep0out

And with pressing power button everything else comes back exept
usb.
This behaviour is kind of "little light nap" and system comes back fast.
And I have also noticed that I cannot use bios passwd with
# echo 3 > /proc/acpi/sleep cause even it doesn't reboot it goes
somehow to bios and bios passwd prompted but it doesn't accept it?
But after disabled bios passwd it works exept usb.

Can somebody give me any wise what I'm doing wrong or point
me to some documentation about this matter?

Thank you for your patience and possible answers advance :-)

--
best rgds
~tt


2004-01-22 00:32:29

by Pavel Machek

[permalink] [raw]
Subject: Re: swusp acpi

Hi!

> And with pressing power button everything else comes back exept
> usb.
> This behaviour is kind of "little light nap" and system comes back fast.
> And I have also noticed that I cannot use bios passwd with
> # echo 3 > /proc/acpi/sleep cause even it doesn't reboot it goes
> somehow to bios and bios passwd prompted but it doesn't accept it?
> But after disabled bios passwd it works exept usb.
>
> Can somebody give me any wise what I'm doing wrong or point
> me to some documentation about this matter?

Seems like USB suspend/resume support is not yet working... Talk to
usb maintainers and offer them some testing...
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2004-01-22 01:45:51

by Nigel Cunningham

[permalink] [raw]
Subject: Re: swusp acpi

Howdy.

It looks like PM support for serial ports is also broken; a serial
console is unusable after resuming.

Regards,

Nigel

On Thu, 2004-01-22 at 13:32, Pavel Machek wrote:
> Hi!
>
> > And with pressing power button everything else comes back exept
> > usb.
> > This behaviour is kind of "little light nap" and system comes back fast.
> > And I have also noticed that I cannot use bios passwd with
> > # echo 3 > /proc/acpi/sleep cause even it doesn't reboot it goes
> > somehow to bios and bios passwd prompted but it doesn't accept it?
> > But after disabled bios passwd it works exept usb.
> >
> > Can somebody give me any wise what I'm doing wrong or point
> > me to some documentation about this matter?
>
> Seems like USB suspend/resume support is not yet working... Talk to
> usb maintainers and offer them some testing...
> Pavel
--
My work on Software Suspend is graciously brought to you by
LinuxFund.org.


Attachments:
signature.asc (189.00 B)
This is a digitally signed message part

2004-01-22 10:27:07

by Pavel Machek

[permalink] [raw]
Subject: Re: swusp acpi

Hi!

> > Not only serial console... Noone wrote serial port support.
>
> Incorrect. I never merged the changes because it's rather too hacky.

Who wrote them? Do you have that patch somewhere?
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2004-01-22 10:23:34

by Russell King

[permalink] [raw]
Subject: Re: swusp acpi

On Thu, Jan 22, 2004 at 11:15:55AM +0100, Pavel Machek wrote:
> Not only serial console... Noone wrote serial port support.

Incorrect. I never merged the changes because it's rather too hacky.

--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of: 2.6 PCMCIA - http://pcmcia.arm.linux.org.uk/
2.6 Serial core

2004-01-22 10:32:06

by Russell King

[permalink] [raw]
Subject: Re: swusp acpi

On Thu, Jan 22, 2004 at 11:26:55AM +0100, Pavel Machek wrote:
> > > Not only serial console... Noone wrote serial port support.
> >
> > Incorrect. I never merged the changes because it's rather too hacky.
>
> Who wrote them? Do you have that patch somewhere?

Me and not separated out from the ARM changes.

--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of: 2.6 PCMCIA - http://pcmcia.arm.linux.org.uk/
2.6 Serial core

2004-01-22 10:16:05

by Pavel Machek

[permalink] [raw]
Subject: Re: swusp acpi

Hi!

> It looks like PM support for serial ports is also broken; a serial
> console is unusable after resuming.

Not only serial console... Noone wrote serial port support.
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2004-01-22 18:05:57

by Nigel Cunningham

[permalink] [raw]
Subject: Re: swusp acpi

Hi.

Michael Frank has done a patch giving 2.4 PM support for serial ports
(my serial console now works flawlessly). Perhaps it could be ported to
2.6 and the driver model...

Nigel

On Thu, 2004-01-22 at 23:26, Pavel Machek wrote:
> Hi!
>
> > > Not only serial console... Noone wrote serial port support.
> >
> > Incorrect. I never merged the changes because it's rather too hacky.
>
> Who wrote them? Do you have that patch somewhere?
> Pavel
--
My work on Software Suspend is graciously brought to you by
LinuxFund.org.


Attachments:
signature.asc (189.00 B)
This is a digitally signed message part

2004-01-23 05:55:41

by Michael Frank

[permalink] [raw]
Subject: Re: swusp acpi

On Friday 23 January 2004 02:08, Nigel Cunningham wrote:
> Hi.
>
> Michael Frank has done a patch giving 2.4 PM support for serial ports
> (my serial console now works flawlessly). Perhaps it could be ported to
> 2.6 and the driver model...
>
> Nigel
>
> On Thu, 2004-01-22 at 23:26, Pavel Machek wrote:
> > Hi!
> >
> > > > Not only serial console... Noone wrote serial port support.
> > >
> > > Incorrect. I never merged the changes because it's rather too hacky.
> >
> > Who wrote them? Do you have that patch somewhere?
> > Pavel
> --
> My work on Software Suspend is graciously brought to you by
> LinuxFund.org.
>

This patch works fine for standerd serial ports with serial.c compiled in.

We use it mainly to suspend/resume serial consoles.

The patch was implemented with the objective to just move code around
in testable blocks to prevent breaking devices unavailable for testing.

However this patch is not suitable for 2.6 as the 2.6 drivers are
a rewrite and the old driver and this patch have a number of issues.

- The patch does not touch interupts and relies on the resuming kernel
to init them for standard serial ports with serial.c compiled in.

- Terefor, device resume would not work with serial.c as a module
or some non-standard serial ports because of the foregoing.

- The old driver initializes serial ports in a non-standard way.
Notably MCR lines and interrupts are enabled prior to setting
baud rate. This is unsuitable for suspending while hardware
handshaked transfers are ongoing.

- No suspend support for software handshaked transmissions. I think
the driver should send the current XOFF character in this case.

- The patch does not attempt to fix the above problem to minimize
disruption and the likelyhood of break device that can't be test.

Another fundamental limitation is that only open ports are resumed,
this will not resume DOSEMU/Win4Lin ports for example. I got a
utility for this which reads back the ports from userspace and writes
them back on resume. This is a bad fix as some registers can't be
read back (FIFO control) and must be set with generic settings.


Regards
Michael

--- linux-2.4.23-Vanilla/drivers/char/serial.c 2003-12-02 05:37:49.000000000 +0800
+++ linux-2.4.23-mhf156/drivers/char/serial.c 2004-01-17 18:05:43.000000000 +0800
@@ -62,10 +62,14 @@
* Robert Schwebel <[email protected]>,
* Juergen Beisert <[email protected]>,
* Theodore Ts'o <[email protected]>
+ *
+ * 01/04: Verion: 5.1
+ * Add PM suspend/resume support
+ * Michael Frank <[email protected]>
*/

-static char *serial_version = "5.05c";
-static char *serial_revdate = "2001-07-08";
+static char *serial_version = "5.1-alpha";
+static char *serial_revdate = "2004-01-01";

/*
* Serial driver configuration section. Here are the various options:
@@ -99,6 +103,13 @@

#include <linux/config.h>
#include <linux/version.h>
+#include <linux/completion.h>
+#include <linux/suspend.h>
+#include <linux/suspend-debug.h>
+
+#ifdef CONFIG_PM
+extern struct completion swsusp_wait_for_shift;
+#endif

#undef SERIAL_PARANOIA_CHECK
#define CONFIG_SERIAL_NOPAUSE_IO
@@ -203,6 +214,9 @@
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/slab.h>
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
#if (LINUX_VERSION_CODE >= 131343)
#include <linux/init.h>
#endif
@@ -223,6 +237,21 @@
#include <linux/sysrq.h>
#endif

+#ifdef CONFIG_KDB
+#include <linux/kdb.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+/*
+ * kdb_serial_line records the serial line number of the first serial console.
+ * NOTE: The kernel ignores characters on the serial line unless a user space
+ * program has opened the line first. To enter kdb before user space has opened
+ * the serial line, you can use the 'kdb=early' flag to lilo and set the
+ * appropriate breakpoints.
+ */
+
+static int kdb_serial_line = -1;
+static const char *kdb_serial_ptr = kdb_serial_str;
+#endif /* CONFIG_SERIAL_CONSOLE */
+#endif /* CONFIG_KDB */
/*
* All of the compatibilty code so we can compile serial.c against
* older kernels is hidden in serial_compat.h
@@ -577,6 +606,18 @@
return; // if TTY_DONT_FLIP is set
}
ch = serial_inp(info, UART_RX);
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_KDB)
+ if ((info->line == kdb_serial_line) && kdb_on) {
+ if (ch == *kdb_serial_ptr) {
+ if (!(*++kdb_serial_ptr)) {
+ kdb(KDB_REASON_KEYBOARD, 0, regs);
+ kdb_serial_ptr = kdb_serial_str;
+ break;
+ }
+ } else
+ kdb_serial_ptr = kdb_serial_str;
+ }
+#endif /* CONFIG_SERIAL_CONSOLE && CONFIG_KDB */
*tty->flip.char_buf_ptr = ch;
icount->rx++;

@@ -638,7 +679,8 @@
else if (*status & UART_LSR_FE)
*tty->flip.flag_buf_ptr = TTY_FRAME;
}
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#if defined(CONFIG_SERIAL_CONSOLE)
+#if defined(CONFIG_MAGIC_SYSRQ)
if (break_pressed && info->line == sercons.index) {
if (ch != 0 &&
time_before(jiffies, break_pressed + HZ*5)) {
@@ -648,7 +690,71 @@
}
break_pressed = 0;
}
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+#ifdef CONFIG_PM
+ if ((software_suspend_state & SOFTWARE_SUSPEND_RUNNING) ||
+ waitqueue_active(&swsusp_wait_for_shift.wait)) {
+#ifdef CONFIG_SOFTWARE_SUSPEND2
+ extern void prepare_status(int printalways, int clearbar, const char *fmt, ...);
+ extern unsigned long swsusp_action;
+ extern void request_abort_suspend(void);
+
+ switch (ch) {
+ case 27:
+ /* Abort suspend */
+ if (TEST_ACTION_STATE(SUSPEND_CAN_CANCEL))
+ request_abort_suspend();
+ break;
+ case 49:
+ console_loglevel = 1;
+ break;
+ case 48:
+ console_loglevel = 0;
+ break;
+#ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG
+ case 80:
+ case 112:
+ /* During suspend, toggle pausing with Pause or Break if kdb active */
+ swsusp_action ^= (1 << SUSPEND_PAUSE);
+ prepare_status(1, 0, "Pausing %s.\n",
+ TEST_ACTION_STATE(SUSPEND_PAUSE) ? "enabled" : "disabled");
+ if (!TEST_ACTION_STATE(SUSPEND_PAUSE))
+ complete(&swsusp_wait_for_shift);
+ break;
+ case 82:
+ case 114:
+ /* Otherwise, if R pressed, toggle rebooting */
+ swsusp_action ^= (1 << SUSPEND_REBOOT);
+ prepare_status(1, 0, "Rebooting %s.\n",
+ TEST_ACTION_STATE(SUSPEND_REBOOT) ? "enabled" : "disabled");
+ break;
+ case 76:
+ case 108:
+ /* Otherwise, if L pressed, toggle logging everything */
+ swsusp_action ^= (1 << SUSPEND_LOGALL);
+ prepare_status(1, 0, "Logging all output %s.\n",
+ TEST_ACTION_STATE(SUSPEND_LOGALL) ? "enabled" : "disabled");
+ break;
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ console_loglevel = ((ch - 48));
+ break;
+#endif
+ }
#endif
+ if (ch == 32)
+ complete(&swsusp_wait_for_shift);
+
+ goto ignore_char;
+ }
+#endif /* CONFIG_PM */
+#endif /* CONFIG_SERIAL_CONSOLE */
+
if ((*status & info->ignore_status_mask) == 0) {
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;
@@ -666,7 +772,7 @@
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;
}
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#if defined(CONFIG_SERIAL_CONSOLE) && ( defined(CONFIG_MAGIC_SYSRQ) || defined(CONFIG_PM))
ignore_char:
#endif
*status = serial_inp(info, UART_LSR);
@@ -1208,44 +1314,16 @@
}
#endif /* CONFIG_SERIAL_RSA */

-static int startup(struct async_struct * info)
+/*
+ * Starts the uart
+ */
+
+int start_uart(struct async_struct * info)
{
- unsigned long flags;
int retval=0;
- void (*handler)(int, void *, struct pt_regs *);
struct serial_state *state= info->state;
- unsigned long page;
-#ifdef CONFIG_SERIAL_MANY_PORTS
- unsigned short ICP;
-#endif
-
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;

- save_flags(flags); cli();
-
- if (info->flags & ASYNC_INITIALIZED) {
- free_page(page);
- goto errout;
- }
-
- if (!CONFIGURED_SERIAL_PORT(state) || !state->type) {
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- free_page(page);
- goto errout;
- }
- if (info->xmit.buf)
- free_page(page);
- else
- info->xmit.buf = (unsigned char *) page;
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttys%d (irq %d)...", info->line, state->irq);
-#endif
-
- if (uart_config[state->type].flags & UART_STARTECH) {
+ if (uart_config[state->type].flags & UART_STARTECH) {
/* Wake up UART */
serial_outp(info, UART_LCR, 0xBF);
serial_outp(info, UART_EFR, UART_EFR_ECB);
@@ -1341,69 +1419,20 @@
retval = -ENODEV;
goto errout;
}
-
- /*
- * Allocate the IRQ if necessary
- */
- if (state->irq && (!IRQ_ports[state->irq] ||
- !IRQ_ports[state->irq]->next_port)) {
- if (IRQ_ports[state->irq]) {
-#ifdef CONFIG_SERIAL_SHARE_IRQ
- free_irq(state->irq, &IRQ_ports[state->irq]);
-#ifdef CONFIG_SERIAL_MULTIPORT
- if (rs_multiport[state->irq].port1)
- handler = rs_interrupt_multi;
- else
-#endif
- handler = rs_interrupt;
-#else
- retval = -EBUSY;
- goto errout;
-#endif /* CONFIG_SERIAL_SHARE_IRQ */
- } else
- handler = rs_interrupt_single;
-
- retval = request_irq(state->irq, handler, SA_SHIRQ,
- "serial", &IRQ_ports[state->irq]);
- if (retval) {
- if (capable(CAP_SYS_ADMIN)) {
- if (info->tty)
- set_bit(TTY_IO_ERROR,
- &info->tty->flags);
- retval = 0;
- }
- goto errout;
- }
- }
+errout:
+ return retval;
+}

- /*
- * Insert serial port into IRQ chain.
- */
- info->prev_port = 0;
- info->next_port = IRQ_ports[state->irq];
- if (info->next_port)
- info->next_port->prev_port = info;
- IRQ_ports[state->irq] = info;
- figure_IRQ_timeout(state->irq);
+int init_uart(struct async_struct * info)
+{
+ int retval=0;
+ struct serial_state *state= info->state;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+ unsigned short ICP;
+#endif

- /*
- * Now, initialize the UART
- */
serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */

- info->MCR = 0;
- if (info->tty->termios->c_cflag & CBAUD)
- info->MCR = UART_MCR_DTR | UART_MCR_RTS;
-#ifdef CONFIG_SERIAL_MANY_PORTS
- if (info->flags & ASYNC_FOURPORT) {
- if (state->irq == 0)
- info->MCR |= UART_MCR_OUT1;
- } else
-#endif
- {
- if (state->irq != 0)
- info->MCR |= UART_MCR_OUT2;
- }
info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
serial_outp(info, UART_MCR, info->MCR);

@@ -1459,6 +1488,108 @@
* and set the speed of the serial port
*/
change_speed(info, 0);
+ return retval;
+}
+
+static int startup(struct async_struct * info)
+{
+ unsigned long flags;
+ int retval=0;
+ void (*handler)(int, void *, struct pt_regs *);
+ struct serial_state *state= info->state;
+ unsigned long page;
+
+ page = get_zeroed_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ save_flags(flags); cli();
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ free_page(page);
+ goto errout;
+ }
+
+ if (!CONFIGURED_SERIAL_PORT(state) || !state->type) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ free_page(page);
+ goto errout;
+ }
+ if (info->xmit.buf)
+ free_page(page);
+ else
+ info->xmit.buf = (unsigned char *) page;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+#endif
+
+ info->MCR = 0;
+ if (info->tty->termios->c_cflag & CBAUD)
+ info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+ if (info->flags & ASYNC_FOURPORT) {
+ if (state->irq == 0)
+ info->MCR |= UART_MCR_OUT1;
+ } else
+#endif
+ {
+ if (state->irq != 0)
+ info->MCR |= UART_MCR_OUT2;
+ }
+
+ start_uart(info);
+
+ /*
+ * Allocate the IRQ if necessary
+ */
+ if (state->irq && (!IRQ_ports[state->irq] ||
+ !IRQ_ports[state->irq]->next_port)) {
+ if (IRQ_ports[state->irq]) {
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+ free_irq(state->irq, &IRQ_ports[state->irq]);
+#ifdef CONFIG_SERIAL_MULTIPORT
+ if (rs_multiport[state->irq].port1)
+ handler = rs_interrupt_multi;
+ else
+#endif
+ handler = rs_interrupt;
+#else
+ retval = -EBUSY;
+ goto errout;
+#endif /* CONFIG_SERIAL_SHARE_IRQ */
+ } else
+ handler = rs_interrupt_single;
+
+ retval = request_irq(state->irq, handler, SA_SHIRQ,
+ "serial", &IRQ_ports[state->irq]);
+ if (retval) {
+ if (capable(CAP_SYS_ADMIN)) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR,
+ &info->tty->flags);
+ retval = 0;
+ }
+ goto errout;
+ }
+ }
+
+ /*
+ * Insert serial port into IRQ chain.
+ */
+ info->prev_port = 0;
+ info->next_port = IRQ_ports[state->irq];
+ if (info->next_port)
+ info->next_port->prev_port = info;
+ IRQ_ports[state->irq] = info;
+ figure_IRQ_timeout(state->irq);
+
+ /*
+ * Now, initialize the UART
+ */
+
+ init_uart(info);

info->flags |= ASYNC_INITIALIZED;
restore_flags(flags);
@@ -1470,6 +1601,33 @@
}

/*
+ * Sleep capable UART
+ */
+
+static void sleep_uart(struct async_struct * info)
+{
+ (void)serial_in(info, UART_RX); /* read data port to reset things */
+
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ if (uart_config[info->state->type].flags & UART_STARTECH) {
+ /* Arrange to enter sleep mode */
+ serial_outp(info, UART_LCR, 0xBF);
+ serial_outp(info, UART_EFR, UART_EFR_ECB);
+ serial_outp(info, UART_LCR, 0);
+ serial_outp(info, UART_IER, UART_IERX_SLEEP);
+ serial_outp(info, UART_LCR, 0xBF);
+ serial_outp(info, UART_EFR, 0);
+ serial_outp(info, UART_LCR, 0);
+ }
+ if (info->state->type == PORT_16750) {
+ /* Arrange to enter sleep mode */
+ serial_outp(info, UART_IER, UART_IERX_SLEEP);
+ }
+}
+
+/*
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
@@ -1566,27 +1724,9 @@
disable_rsa(info)))
state->baud_base = SERIAL_RSA_BAUD_BASE_LO;
#endif
-

- (void)serial_in(info, UART_RX); /* read data port to reset things */
-
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
+ sleep_uart(info);

- if (uart_config[info->state->type].flags & UART_STARTECH) {
- /* Arrange to enter sleep mode */
- serial_outp(info, UART_LCR, 0xBF);
- serial_outp(info, UART_EFR, UART_EFR_ECB);
- serial_outp(info, UART_LCR, 0);
- serial_outp(info, UART_IER, UART_IERX_SLEEP);
- serial_outp(info, UART_LCR, 0xBF);
- serial_outp(info, UART_EFR, 0);
- serial_outp(info, UART_LCR, 0);
- }
- if (info->state->type == PORT_16750) {
- /* Arrange to enter sleep mode */
- serial_outp(info, UART_IER, UART_IERX_SLEEP);
- }
info->flags &= ~ASYNC_INITIALIZED;
restore_flags(flags);
}
@@ -3250,6 +3390,108 @@
return 0;
}

+#ifdef CONFIG_PM
+
+/*
+ * Suspend an UART
+ */
+
+static int rs_suspend_uart(struct async_struct *info)
+{
+ int retval = 0;
+ printk("serio: Suspending %lx\n", info->port);
+
+ /* disable all intrs */
+ serial_outp(info, UART_IER, 0x00);
+
+ /* disable break condition */
+ serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+
+ /* Disable line */
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+ serial_outp(info, UART_MCR,(info->MCR & ~(UART_MCR_DTR|UART_MCR_RTS)));
+
+ /* put UART to sleep */
+ sleep_uart(info);
+
+ if (retval)
+ info->flags &= ~ASYNC_INITIALIZED;
+ return retval;
+}
+static int rs_suspend(struct tty_struct *tty)
+{
+ int retval = 0;
+ unsigned long flags;
+ save_flags(flags); cli();
+
+ retval = rs_suspend_uart((struct async_struct *)tty->driver_data);
+
+ restore_flags(flags);
+ return retval;
+}
+
+/*
+ * Resume an UART
+ */
+
+/* Todo: eval multiport interrupt resume */
+
+static int rs_resume_uart(struct async_struct *info)
+{
+ int retval = 0;
+
+ printk("serio: Resuming %lx\n", info->port);
+
+ if ((retval = start_uart(info)))
+ goto out;
+ retval = init_uart(info);
+out:
+ if (retval)
+ info->flags &= ~ASYNC_INITIALIZED;
+ return retval;
+}
+
+static int rs_resume(struct tty_struct *tty)
+{
+ int retval = 0;
+ unsigned long flags;
+ save_flags(flags); cli();
+
+ retval = rs_resume_uart((struct async_struct *)tty->driver_data);
+
+ restore_flags(flags);
+ return retval;
+}
+
+/*
+ * Suspend or Resume all UARTs
+ */
+
+static int rs_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+ struct serial_state *state = rs_table;
+ int i;
+ unsigned long flags; /* Interrupts will be reenabled once per iteration */
+
+ for (i =0; i < NR_PORTS; i++, state++) {
+ if (!state->info) /* info is NULL unless port opened */
+ continue;
+
+ save_flags(flags); cli();
+
+ switch (rqst) {
+ case PM_SUSPEND:
+ rs_suspend_uart(state->info);
+ break;
+ case PM_RESUME:
+ rs_resume_uart(state->info);
+ }
+ restore_flags(flags);
+ }
+ return 0;
+}
+#endif
+
/*
* /proc fs routines....
*/
@@ -5475,6 +5717,10 @@
serial_driver.wait_until_sent = rs_wait_until_sent;
serial_driver.read_proc = rs_read_proc;
#endif
+#ifdef CONFIG_PM
+ serial_driver.suspend = rs_suspend;
+ serial_driver.resume = rs_resume;
+#endif

/*
* The callout device is just like normal device except for
@@ -5554,8 +5800,13 @@
probe_serial_pci();
#endif
#ifdef ENABLE_SERIAL_PNP
- probe_serial_pnp();
+ probe_serial_pnp();
+#endif
+#ifdef CONFIG_PM
+ if (!pm_register(PM_UNKNOWN_DEV, 0, rs_pm_callback))
+ panic("Couldn't register with PM subsystem\n");
#endif
+
return 0;
}

@@ -5726,6 +5977,7 @@
struct async_struct *info;

/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
+ pm_unregister_all(rs_pm_callback);
del_timer_sync(&serial_timer);
save_flags(flags); cli();
remove_bh(SERIAL_BH);
@@ -6001,6 +6253,30 @@
if (serial_in(info, UART_LSR) == 0xff)
return -1;

+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_KDB)
+ /*
+ * Remember the line number of the first serial
+ * console. We'll make this the kdb serial console too.
+ */
+ if (kdb_serial_line == -1) {
+ kdb_serial_line = co->index;
+ kdb_serial.io_type = info->io_type;
+ switch (info->io_type) {
+ case SERIAL_IO_MEM:
+#ifdef SERIAL_IO_MEM32
+ case SERIAL_IO_MEM32:
+#endif
+ kdb_serial.iobase = (unsigned long)(info->iomem_base);
+ kdb_serial.ioreg_shift = info->iomem_reg_shift;
+ break;
+ default:
+ kdb_serial.iobase = state->port;
+ kdb_serial.ioreg_shift = 0;
+ break;
+ }
+ }
+#endif /* CONFIG_SERIAL_CONSOLE && CONFIG_KDB */
+
return 0;
}


2004-01-31 11:42:25

by Pavel Machek

[permalink] [raw]
Subject: Re: swusp acpi

Hi!

> Michael Frank has done a patch giving 2.4 PM support for serial ports
> (my serial console now works flawlessly). Perhaps it could be ported to
> 2.6 and the driver model...

That would certainly be good thing (tm).

>
> Nigel
>
> On Thu, 2004-01-22 at 23:26, Pavel Machek wrote:
> > Hi!
> >
> > > > Not only serial console... Noone wrote serial port support.
> > >
> > > Incorrect. I never merged the changes because it's rather too hacky.
> >
> > Who wrote them? Do you have that patch somewhere?
> > Pavel
> --
> My work on Software Suspend is graciously brought to you by
> LinuxFund.org.



--
64 bytes from 195.113.31.123: icmp_seq=28 ttl=51 time=448769.1 ms