Jump to content

HP DVx AppleACPIBatteryManager Driver


  • Please log in to reply
73 replies to this topic

#1
gsly

gsly

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 141 posts
  • Gender:Male
  • Location:The Great White North
Please Note! The following driver has been deprecated. Please switch to the newest version at http://www.insanelym...howtopic=264597


The following implements a battery manager driver for HP DVx laptops. There are two pieces required to make this work, the AppleACPIBatteryManager.kext (driver) and a DSDT edit.

The driver is generic and will probably work on other platforms that properly implement the _BST and _BIF methods in their DSDT. As the HP _BST method on DVx isn't (IMHO) implemented correctly, DVx owners will also have to implement the DSDT edit so that the _BST method returns proper values to the driver in order to calculate the time remaining (to charge or discharge) value.

This was tested on an HP DV8 but will likely work on any DVx model that implements a similar DSDT method. Also, I have only tested this on a 32-bit kernel, but it should work on a 64-bit kernel as the driver has been compiled to a 10.6 32/64-bit universal (FAT) binary.

There are two zip files below, a debug and release version. The debug version outputs messages to kernel.log and the release version does not, otherwise they are identical.

Step 1: DSDT Edit

In your DSDT.dsl, locate the method UPBS that should look like this:

Method (UPBS, 0, NotSerialized)
			{
				Store (^^PCI0.LPCB.EC0.MBRM, Local5)
				If (LNot (And (Local5, 0x8000)))
				{
					ShiftRight (Local5, 0x05, Local5)
					ShiftLeft (Local5, 0x05, Local5)
					If (LNotEqual (Local5, DerefOf (Index (PBST, 0x02))))
					{
						If (LEqual (^^PCI0.LPCB.EC0.BACR, One))
						{
							Store (FABL, Index (PBST, 0x02))
						}
						Else
						{
							Store (Local5, Index (PBST, 0x02))
						}
					}
				}

				Store (^^PCI0.LPCB.EC0.MBCV, Index (PBST, 0x03))
				Store (^^PCI0.LPCB.EC0.MBST, Index (PBST, Zero))
			}
If your method matches the above, replace it with:
Method (UPBS, 0, NotSerialized)
			{
				Store (^^PCI0.LPCB.EC0.MBST, Index (PBST, Zero))
				^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x0A, RefOf (Local0))
				Store (Local0, Index (PBST, One))
				^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x0F, RefOf (Local1))
				Store (Local1, Index (PBST, 0x02))
				^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x09, RefOf (Local2))
				Store (Local2, Index (PBST, 0x03))
			}
Compile it and install as usual.

Step 2: Install Driver

Install the kext in /Extra/Extensions, set the permissions and rebuild your kext cache. Reboot.

#2
NIXin

NIXin

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 114 posts
  • Gender:Male
  • Location:Krakow, Poland
Looks awesome! I'll try that and if it works, I'll implement the patch to my DSDT Auto-Patch for DVx, if you don't mind :-)
On another thought, you should have maybe made this topic in The Genius Bar instead of here.

#3
Mammoth

Mammoth

    InsanelyMac Legend

  • Members
  • PipPipPipPipPipPipPip
  • 625 posts
Awesome NIXin, that would be great. I'm looking to try it right now. I'll report back my results.

Mine doesn't look anything like that. Here is mine:
[codebox] Method (_BST, 0, NotSerialized)
{
If (ECON)
{
If (^^PCI0.LPCB.EC0.MBTS)
{
UPBS ()
}
Else
{
IVBS ()
}
}
Else
{
IVBS ()
}

Return (PBST)
}

Method (UPBI, 0, NotSerialized)
{
If (LNot (^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x10, RefOf (Local5))))
{
If (LAnd (Local5, LNot (And (Local5, 0x8000))))
{
ShiftRight (Local5, 0x05, Local5)
ShiftLeft (Local5, 0x05, Local5)
Store (Local5, Index (PBIF, 0x02))
Divide (Local5, 0x64, , Local2)
Add (Local2, One, Local2)
Multiply (Local2, 0x0C, Local4)
Add (Local4, 0x02, Index (PBIF, 0x05))
Multiply (Local2, 0x07, Local4)
Add (Local4, 0x02, Index (PBIF, 0x06))
Multiply (Local2, 0x09, Local4)
Add (Local4, 0x02, FABL)
}
}

If (^^PCI0.LPCB.EC0.MBNH)
{
Store (^^PCI0.LPCB.EC0.BCLB, Local0)
Store (^^PCI0.LPCB.EC0.BCHB, Local1)
ShiftLeft (Local1, 0x08, Local1)
Or (Local0, Local1, Local0)
Store (Local0, Index (PBIF, One))
Store (^^PCI0.LPCB.EC0.BVLB, Local0)
Store (^^PCI0.LPCB.EC0.BVHB, Local1)
ShiftLeft (Local1, 0x08, Local1)
Or (Local0, Local1, Local0)
Store (Local0, Index (PBIF, 0x04))
Store ("OANI$", Index (PBIF, 0x09))
Store ("NiMH", Index (PBIF, 0x0B))
}
Else
{
Store (^^PCI0.LPCB.EC0.BCLB, Local0)
Store (^^PCI0.LPCB.EC0.BCHB, Local1)
ShiftLeft (Local1, 0x08, Local1)
Or (Local0, Local1, Local0)
Store (Local0, Index (PBIF, One))
Store (^^PCI0.LPCB.EC0.BVLB, Local0)
Store (^^PCI0.LPCB.EC0.BVHB, Local1)
ShiftLeft (Local1, 0x08, Local1)
Or (Local0, Local1, Local0)
Store (Local0, Index (PBIF, 0x04))
Sleep (0x32)
Store ("LION", Index (PBIF, 0x0B))
}

Store ("Primary", Index (PBIF, 0x09))
UPUM ()
Store (One, Index (PBIF, Zero))
}

Method (UPUM, 0, NotSerialized)
{
Store (Buffer (0x0A)
{
/* 0000 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0008 */ 0x00, 0x00
}, Local0)
Store (Buffer (0x05)
{
0x36, 0x35, 0x35, 0x33, 0x35
}, Local6)
Store (Buffer (0x05)
{
0x31, 0x32, 0x33, 0x32, 0x31
}, Local7)
Store ("Hewlett-Packard", Index (PBIF, 0x0C))
}

Method (UPBS, 0, NotSerialized)
{
Store (^^PCI0.LPCB.EC0.MBRM, Local5)
If (LNot (And (Local5, 0x8000)))
{
ShiftRight (Local5, 0x05, Local5)
ShiftLeft (Local5, 0x05, Local5)
If (LNotEqual (Local5, DerefOf (Index (PBST, 0x02))))
{
If (LEqual (^^PCI0.LPCB.EC0.BACR, One))
{
Store (FABL, Index (PBST, 0x02))
}
Else
{
Store (Local5, Index (PBST, 0x02))
}
}
}

Store (^^PCI0.LPCB.EC0.MBCV, Index (PBST, 0x03))
Store (^^PCI0.LPCB.EC0.MBST, Index (PBST, Zero))
}

Method (IVBI, 0, NotSerialized)
{
Store (0xFFFFFFFF, Index (PBIF, One))
Store (0xFFFFFFFF, Index (PBIF, 0x02))
Store (0xFFFFFFFF, Index (PBIF, 0x04))
Store ("Bad", Index (PBIF, 0x09))
Store ("Bad", Index (PBIF, 0x0A))
Store ("Bad", Index (PBIF, 0x0B))
Store ("Bad", Index (PBIF, 0x0C))
}

Method (IVBS, 0, NotSerialized)
{
Store (Zero, Index (PBST, Zero))
Store (0xFFFFFFFF, Index (PBST, One))
Store (0xFFFFFFFF, Index (PBST, 0x02))
Store (0x2710, Index (PBST, 0x03))
}
}[/codebox]

#4
gsly

gsly

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 141 posts
  • Gender:Male
  • Location:The Great White North

Looks awesome! I'll try that and if it works, I'll implement the patch to my DSDT Auto-Patch for DVx, if you don't mind :-)
On another thought, you should have maybe made this topic in The Genius Bar instead of here.

Sure, no problem. Actually, I should have put it under the "Other" subsection of Hardware and Drivers forum. Ah well, this is what the moderators should be doing :unsure:



Mine doesn't look anything like that. Here is mine:

Method (UPBS, 0, NotSerialized)
{
Store (^^PCI0.LPCB.EC0.MBRM, Local5)
If (LNot (And (Local5, 0x8000)))
{
ShiftRight (Local5, 0x05, Local5)
ShiftLeft (Local5, 0x05, Local5)
If (LNotEqual (Local5, DerefOf (Index (PBST, 0x02))))
{
If (LEqual (^^PCI0.LPCB.EC0.BACR, One))
{
Store (FABL, Index (PBST, 0x02))
}
Else
{
Store (Local5, Index (PBST, 0x02))
}
}
}

Store (^^PCI0.LPCB.EC0.MBCV, Index (PBST, 0x03))
Store (^^PCI0.LPCB.EC0.MBST, Index (PBST, Zero))
}

Method (IVBI, 0, NotSerialized)
{
Store (0xFFFFFFFF, Index (PBIF, One))
Store (0xFFFFFFFF, Index (PBIF, 0x02))
Store (0xFFFFFFFF, Index (PBIF, 0x04))
Store ("Bad", Index (PBIF, 0x09))
Store ("Bad", Index (PBIF, 0x0A))
Store ("Bad", Index (PBIF, 0x0B))
Store ("Bad", Index (PBIF, 0x0C))
}

Method (IVBS, 0, NotSerialized)
{
Store (Zero, Index (PBST, Zero))
Store (0xFFFFFFFF, Index (PBST, One))
Store (0xFFFFFFFF, Index (PBST, 0x02))
Store (0x2710, Index (PBST, 0x03))
}
} _linenums:0'>Method (_BST, 0, NotSerialized) { If (ECON) { If (^^PCI0.LPCB.EC0.MBTS) { UPBS () } Else { IVBS () } } Else { IVBS () } Return (PBST) } Method (UPBI, 0, NotSerialized) { If (LNot (^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x10, RefOf (Local5)))) { If (LAnd (Local5, LNot (And (Local5, 0x8000)))) { ShiftRight (Local5, 0x05, Local5) ShiftLeft (Local5, 0x05, Local5) Store (Local5, Index (PBIF, 0x02)) Divide (Local5, 0x64, , Local2) Add (Local2, One, Local2) Multiply (Local2, 0x0C, Local4) Add (Local4, 0x02, Index (PBIF, 0x05)) Multiply (Local2, 0x07, Local4) Add (Local4, 0x02, Index (PBIF, 0x06)) Multiply (Local2, 0x09, Local4) Add (Local4, 0x02, FABL) } } If (^^PCI0.LPCB.EC0.MBNH) { Store (^^PCI0.LPCB.EC0.BCLB, Local0) Store (^^PCI0.LPCB.EC0.BCHB, Local1) ShiftLeft (Local1, 0x08, Local1) Or (Local0, Local1, Local0) Store (Local0, Index (PBIF, One)) Store (^^PCI0.LPCB.EC0.BVLB, Local0) Store (^^PCI0.LPCB.EC0.BVHB, Local1) ShiftLeft (Local1, 0x08, Local1) Or (Local0, Local1, Local0) Store (Local0, Index (PBIF, 0x04)) Store ("OANI$", Index (PBIF, 0x09)) Store ("NiMH", Index (PBIF, 0x0B)) } Else { Store (^^PCI0.LPCB.EC0.BCLB, Local0) Store (^^PCI0.LPCB.EC0.BCHB, Local1) ShiftLeft (Local1, 0x08, Local1) Or (Local0, Local1, Local0) Store (Local0, Index (PBIF, One)) Store (^^PCI0.LPCB.EC0.BVLB, Local0) Store (^^PCI0.LPCB.EC0.BVHB, Local1) ShiftLeft (Local1, 0x08, Local1) Or (Local0, Local1, Local0) Store (Local0, Index (PBIF, 0x04)) Sleep (0x32) Store ("LION", Index (PBIF, 0x0B)) } Store ("Primary", Index (PBIF, 0x09)) UPUM () Store (One, Index (PBIF, Zero)) } Method (UPUM, 0, NotSerialized) { Store (Buffer (0x0A) { /* 0000 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0008 */ 0x00, 0x00 }, Local0) Store (Buffer (0x05) { 0x36, 0x35, 0x35, 0x33, 0x35 }, Local6) Store (Buffer (0x05) { 0x31, 0x32, 0x33, 0x32, 0x31 }, Local7) Store ("Hewlett-Packard", Index (PBIF, 0x0C)) } Method (UPBS, 0, NotSerialized) { Store (^^PCI0.LPCB.EC0.MBRM, Local5) If (LNot (And (Local5, 0x8000))) { ShiftRight (Local5, 0x05, Local5) ShiftLeft (Local5, 0x05, Local5) If (LNotEqual (Local5, DerefOf (Index (PBST, 0x02)))) { If (LEqual (^^PCI0.LPCB.EC0.BACR, One)) { Store (FABL, Index (PBST, 0x02)) } Else { Store (Local5, Index (PBST, 0x02)) } } } Store (^^PCI0.LPCB.EC0.MBCV, Index (PBST, 0x03)) Store (^^PCI0.LPCB.EC0.MBST, Index (PBST, Zero)) } Method (IVBI, 0, NotSerialized) { Store (0xFFFFFFFF, Index (PBIF, One)) Store (0xFFFFFFFF, Index (PBIF, 0x02)) Store (0xFFFFFFFF, Index (PBIF, 0x04)) Store ("Bad", Index (PBIF, 0x09)) Store ("Bad", Index (PBIF, 0x0A)) Store ("Bad", Index (PBIF, 0x0B)) Store ("Bad", Index (PBIF, 0x0C)) } Method (IVBS, 0, NotSerialized) { Store (Zero, Index (PBST, Zero)) Store (0xFFFFFFFF, Index (PBST, One)) Store (0xFFFFFFFF, Index (PBST, 0x02)) Store (0x2710, Index (PBST, 0x03)) } }


You have been working too hard Mammoth! See the part in red above :P

#5
NIXin

NIXin

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 114 posts
  • Gender:Male
  • Location:Krakow, Poland
Here's the fix in Auto-Patcher format (also available in the "DSDT Editor"):
[codebox]# Support for AppleACPIBatteryManager for DVx by gsly:
into method label UPBS parent_hid PNP0C0A remove_entry;
into device name_hid PNP0C0A insert
begin
Method (UPBS, 0, NotSerialized)\n
{\n
Store (^^PCI0.LPCB.EC0.MBST, Index (PBST, Zero))\n
^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x0A, RefOf (Local0))\n
Store (Local0, Index (PBST, One))\n
^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x0F, RefOf (Local1))\n
Store (Local1, Index (PBST, 0x02))\n
^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x09, RefOf (Local2))\n
Store (Local2, Index (PBST, 0x03))\n
}
end;[/codebox]

#6
Sammity

Sammity

    InsanelyMac Protégé

  • Members
  • Pip
  • 22 posts
Gsly.

Thank you, thank you, thank you !

Correct time now shown on my dv8 for the remaining battery life :wacko:

Awesome.

#7
spawnedc

spawnedc

    InsanelyMac Protégé

  • Members
  • Pip
  • 28 posts
  • Gender:Male
  • Location:London / UK
Thank you so much for this! You are a lifesaver!

#8
kidamnesiac

kidamnesiac

    InsanelyMac Protégé

  • Members
  • Pip
  • 29 posts
  • Gender:Male
  • Location:Rome, IT
Hi all,

I was looking for a voodoo battery kext replacement for my HP DV5 1170el late 2008 hack and found this thread.

my dsdt looks like this in the UPBS part

LPC.EC0.MBRM, Local5)
If (LNot (And (Local5, 0x8000)))
{
ShiftRight (Local5, 0x05, Local5)
ShiftLeft (Local5, 0x05, Local5)
If (LNotEqual (Local5, DerefOf (Index (PBST, 0x02))))
{
Store (Local5, Index (PBST, 0x02))
}
}

Store (^^PCI0.LPC.EC0.MBCV, Index (PBST, 0x03))
Store (^^PCI0.LPC.EC0.MBST, Index (PBST, Zero))
} _linenums:0'>Method (UPBS, 0, NotSerialized) { Store (^^PCI0.<strong class='bbc'>LPC</strong>.EC0.MBRM, Local5) If (LNot (And (Local5, 0x8000))) { ShiftRight (Local5, 0x05, Local5) ShiftLeft (Local5, 0x05, Local5) If (LNotEqual (Local5, DerefOf (Index (PBST, 0x02)))) { Store (Local5, Index (PBST, 0x02)) } } Store (^^PCI0.<strong class='bbc'>LPC</strong>.EC0.MBCV, Index (PBST, 0x03)) Store (^^PCI0.<strong class='bbc'>LPC</strong>.EC0.MBST, Index (PBST, Zero)) }

slightly different from the one in the first post,
obviously the mod didn't compile, because of missing LPCB object ( i have LPC in mine)

Any workaround for this?

thank you


kidA

#9
NIXin

NIXin

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 114 posts
  • Gender:Male
  • Location:Krakow, Poland
Did you try changing all the LPBC to LPC and trying the .kext?

#10
kidamnesiac

kidamnesiac

    InsanelyMac Protégé

  • Members
  • Pip
  • 29 posts
  • Gender:Male
  • Location:Rome, IT
I wasn't unsure about that procedure, but I'll try rightaway and give some feedback.

kidA

Confirmed to work with LPCB -> LPC.

:( thanks!

any hint on how to get rid of voodoops2 controller by chance?

hehe

I wanted to clear the voodoo from my hack :P

thanks

kidA

#11
valv

valv

    InsanelyMac Architect

  • Members
  • PipPipPipPipPipPipPip
  • 910 posts
  • Gender:Male
  • Location:Unrevealed Area
  • Interests:Operating Systems<br />Networking<br />Security
@gsly,
Thank you for your effort. It looks promising.
Btw, any chance to get source code. Thanks

#12
Pasa Yildirim

Pasa Yildirim

    InsanelyMac Protégé

  • Members
  • Pip
  • 49 posts
Have you got the sources? Using similar HP model (8710p), and has the same bug as VoodooBattery: shows "power source: battery" while the battery is disconnected (just on AC). Also, measurement is much slower, and it does not detects properly switching between AC/battery.

#13
gsly

gsly

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 141 posts
  • Gender:Male
  • Location:The Great White North
I've been working on an update that includes:

  • ACPI 4.0a compliant _BIX method that returns more data than _BIF
  • Non-standard _BIX method that returns temperature, etc.
  • Info.plist options to enable/disable the above functions.
  • Other fixes to make it behave like AppleSmartBattery (using MacBookPro6,2 as template)
I will update the thread in the next few weeks when I'm happy with it. The next task is to try and make this driver obsolete and get the native AppleSmartBattery kext working without OS modification.

#14
manmal

manmal

    InsanelyMac Sage

  • Members
  • PipPipPipPipPipPip
  • 432 posts

I've been working on an update that includes:

  • ACPI 4.0a compliant _BIX method that returns more data than _BIF
  • Non-standard _BIX method that returns temperature, etc.
  • Info.plist options to enable/disable the above functions.
  • Other fixes to make it behave like AppleSmartBattery (using MacBookPro6,2 as template)
I will update the thread in the next few weeks when I'm happy with it. The next task is to try and make this driver obsolete and get the native AppleSmartBattery kext working without OS modification.


WOW! Thanks glsy!! That's GREAT news!

#15
MaLd0n

MaLd0n

    ...filling veins with juice of chaos...

  • Moderators
  • 11,132 posts
  • Gender:Male
  • Location:Rio de Janeiro
great Job
:P

#16
Pasa Yildirim

Pasa Yildirim

    InsanelyMac Protégé

  • Members
  • Pip
  • 49 posts

I've been working on an update that includes:

  • ACPI 4.0a compliant _BIX method that returns more data than _BIF
  • Non-standard _BIX method that returns temperature, etc.
  • Info.plist options to enable/disable the above functions.
  • Other fixes to make it behave like AppleSmartBattery (using MacBookPro6,2 as template)
I will update the thread in the next few weeks when I'm happy with it. The next task is to try and make this driver obsolete and get the native AppleSmartBattery kext working without OS modification.


Well, about AppleSmartBattery: it uses SMB device, so you need to add this to your \_SB_.PCI0.EC (\_SB_.C003.C006 for Compaq):
Device (SMB0){	Name (_HID, "ACPI0001")	Name (_EC, 0x2010) // <-- LOOK HERE		Device (SBS0)	{		Name (_HID, "ACPI0002")		Name (_SBS, 0x01)	}}

If you analyze ACPI spec, you'll see that SMB controller is located within EC at _EC query/offset. Now, my DSDT does not contain SMB, and Windows detects batteries as Control Method, although BIOS supports SmartBattery (and HP also said that all their new models have SMBatteries). Also, yout BAT0 device makes (probably) communication with EC in _BIF/_STA methods. So, we could succeed?

Now, problem is ... what is our _EC? I'll try to find it (there is open source implementation in Linux). Second, and worse: according to AppleSmartBattery source, this information is hardcoded:
// Register address is 0x29 + SMB base 0x20ecBehaviorsAddress.addr64 = 0x20 + 0x29; // <-- _EC = 0x2029 ?!


So, no vanilla battery :( ? If you succeed somehow, please share knowledge :) I wish you good luck :)

#17
NIXin

NIXin

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 114 posts
  • Gender:Male
  • Location:Krakow, Poland
Maybe we can just change the hardcoded address in AppleSmartBattery and recompile it for our purpose? It wouldn't be totally vanilla, but still native functionality.

#18
Pasa Yildirim

Pasa Yildirim

    InsanelyMac Protégé

  • Members
  • Pip
  • 49 posts

Maybe we can just change the hardcoded address in AppleSmartBattery and recompile it for our purpose? It wouldn't be totally vanilla, but still native functionality.

If we get out _EC offset. That's still "the hard part", at least for me :)

#19
gsly

gsly

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 141 posts
  • Gender:Male
  • Location:The Great White North

Maybe we can just change the hardcoded address in AppleSmartBattery and recompile it for our purpose? It wouldn't be totally vanilla, but still native functionality.

Been down this road. Apple does not provide the source code that implements an SMBus transaction class that is used by AppleSmartBattery to talk to the EC. I started to build my own class for this, but I'm thinking it might be easier to code on the other side (DSDT) and leave the vanilla driver alone...

I can tell you that in an initial experiment, I was able to get the vanilla AppleSmartBattery driver to load and talk to the Smart Battery Subsystem (SBS) and see the information in IOReg with just DSDT code, however it appears the driver stopped polling after a bit. I think I need some logic on the DSDT side to intercept some of the non-standard SBS calls that AppleSmartBattery makes and fake that return information and keeps the kext happy and polling.

#20
sw170

sw170

    InsanelyMac Geek

  • Members
  • PipPipPipPip
  • 212 posts
  • Gender:Male
  • Location:UK
Hi 'gsly'

AppleACPIBatteryManager with your DSDT mod works great on my system, thanks for that mate,

have just one issue and wonder if you could help - after unplugging AC adapter I have about 10-15sec delay from system to switch to battery icon and dim the display, when plugging back AC adapter icon change and display lit up is almost instant.

any ideas ?

thanks
s





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

© 2014 InsanelyMac  |   News  |   Forum  |   Downloads  |   OSx86 Wiki  |   Mac Netbook  |   Web hosting by CatN  |   Designed by Ed Gain  |   Logo by irfan  |   Privacy Policy