source: trunk/src/os2ahci/apm.c@ 153

Last change on this file since 153 was 153, checked in by David Azarewicz, 12 years ago

Makefile updates
Debug output improvements
Support for ACPI suspend/resume added

File size: 5.2 KB
Line 
1/******************************************************************************
2 * apm.c - Functions to interface with the APM driver.
3 *
4 * Copyright (c) 2011 thi.guten Software Development
5 * Copyright (c) 2011 Mensys B.V.
6 *
7 * Authors: Christian Mueller, Markus Thielen
8 *
9 * Parts copied from/inspired by the Linux AHCI driver;
10 * those parts are (c) Linux AHCI/ATA maintainers
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27#include "os2ahci.h"
28
29#include <apmcalls.h>
30
31/* -------------------------- macros and constants ------------------------- */
32
33/* ------------------------ typedefs and structures ------------------------ */
34
35/* -------------------------- function prototypes -------------------------- */
36
37/* ------------------------ global/static variables ------------------------ */
38
39USHORT _far _cdecl apm_event (APMEVENT _far *evt);
40
41/* ----------------------------- start of code ----------------------------- */
42
43/******************************************************************************
44 * Connect to APM driver and register for power state change events.
45 */
46void apm_init(void)
47{
48 USHORT rc;
49
50 /* connect to APM driver */
51 if ((rc = APMAttach()) != 0) {
52 dprintf("couldn't connect to APM driver (rc = %d)\n", rc);
53 return;
54 }
55
56 /* register for suspend/resume events */
57 if ((rc = APMRegister(apm_event, APM_NOTIFYSETPWR |
58 APM_NOTIFYNORMRESUME |
59 APM_NOTIFYCRITRESUME, 0)) != 0) {
60 dprintf("couldn't register for power event notificatins (rc = %d)\n", rc);
61 return;
62 }
63}
64
65/******************************************************************************
66 * APM event handler
67 */
68USHORT _far _cdecl apm_event(APMEVENT _far *evt)
69{
70 USHORT msg = (USHORT) evt->ulParm1;
71
72 dprintf("received APM event: 0x%lx/0x%lx\n");
73
74 switch (msg) {
75
76 case APM_SETPWRSTATE:
77 if (evt->ulParm2 >> 16 != APM_PWRSTATEREADY) {
78 /* we're suspending */
79 apm_suspend();
80 }
81 break;
82
83 case APM_NORMRESUMEEVENT:
84 case APM_CRITRESUMEEVENT:
85 /* we're resuming */
86 apm_resume();
87 break;
88
89 default:
90 dprintf("unknown APM event; ignoring...\n");
91 break;
92 }
93
94 return(0);
95}
96
97/******************************************************************************
98 * APM suspend handler. In a nutshell, it'll turn of interrupts and flush all
99 * write caches.
100 */
101void apm_suspend(void)
102{
103 int a;
104 int p;
105 int d;
106
107 if (suspended) return;
108 dprintf("apm_suspend()\n");
109
110 /* restart all ports with interrupts disabled */
111 for (a = 0; a < ad_info_cnt; a++) {
112 AD_INFO *ai = ad_infos + a;
113
114 lock_adapter(ai);
115 for (p = 0; p <= ai->port_max; p++) {
116 /* wait until all active commands have completed on this port */
117 while (ahci_port_busy(ai, p)) {
118 msleep(250);
119 }
120
121 /* restart port with interrupts disabled */
122 ahci_stop_port(ai, p);
123 ahci_start_port(ai, p, 0);
124
125 /* flush cache on all attached devices */
126 for (d = 0; d <= ai->ports[p].dev_max; d++) {
127 if (ai->ports[p].devs[d].present) {
128 ahci_flush_cache(ai, p, d);
129 }
130 }
131 }
132 }
133
134 /* reset init_complete so that we can process IORBs without interrupts */
135 init_complete = 0;
136
137 /* restore BIOS configuration for each adapter and release the adapter */
138 for (a = 0; a < ad_info_cnt; a++) {
139 ahci_restore_bios_config(ad_infos + a);
140 unlock_adapter(ad_infos + a);
141 }
142
143 suspended = 1;
144 dprintf("apm_suspend() finished\n");
145}
146
147/******************************************************************************
148 * APM resume handler. All ports are restarted with interrupts enabled using
149 * the same function as the IOCM_COMPLETE_INIT handler does.
150 */
151void apm_resume(void)
152{
153 int a;
154
155 if (!suspended) return;
156 dprintf("apm_resume()\n");
157
158 for (a = 0; a < ad_info_cnt; a++) {
159 AD_INFO *ai = ad_infos + a;
160
161 /* Complete initialization of this adapter; this will restart the ports
162 * with interrupts enabled and take care of whatever else needs to be
163 * done to get the adapter and its ports up and running.
164 */
165 lock_adapter(ai);
166 ahci_complete_init(ai);
167 }
168
169 /* tell the driver we're again fully operational */
170 init_complete = 1;
171
172 /* unlock all adapters now that we have set the init_complete flag */
173 for (a = 0; a < ad_info_cnt; a++) {
174 unlock_adapter(ad_infos + a);
175 }
176
177 suspended = 0;
178 dprintf("apm_resume() finished\n");
179}
Note: See TracBrowser for help on using the repository browser.