At the moment, our driver relies on 'wacom_battery_get_property()' to
determine the most likely battery state (e.g charging, discharging, or
full) based on the information available. It is not always possible
for the function to properly determine this, however. For instance,
whenever an AES pen leaves proximity the battery state becomes
indeterminite. This commit adds the ability to provide it with explict
state information if desired. Whenever explicit state is not required
(the majority of circumstances), WACOM_POWER_SUPPLY_STATUS_AUTO can
be used in its place.
Three uses of explicit battery status are added: two wireless disconnect
paths and the AES case mentioned above.
Signed-off-by: Jason Gerecke <***@wacom.com>
Reviewed-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (16e4598905)]
Signed-off-by: Jason Gerecke <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (2658324)]
Signed-off-by: Jason Gerecke <***@wacom.com>
---
2.6.38/wacom.h | 1 +
2.6.38/wacom_sys.c | 4 +++-
2.6.38/wacom_wac.c | 34 +++++++++++++++++-------------
2.6.38/wacom_wac.h | 1 +
3.17/wacom.h | 1 +
3.17/wacom_sys.c | 4 +++-
3.17/wacom_wac.c | 62 +++++++++++++++++++++++++++++++++---------------------
3.17/wacom_wac.h | 3 +++
3.7/wacom.h | 1 +
3.7/wacom_sys.c | 4 +++-
3.7/wacom_wac.c | 34 +++++++++++++++++-------------
3.7/wacom_wac.h | 1 +
12 files changed, 93 insertions(+), 57 deletions(-)
diff --git a/2.6.38/wacom.h b/2.6.38/wacom.h
index 0ccfcc1..357f5e8 100644
--- a/2.6.38/wacom.h
+++ b/2.6.38/wacom.h
@@ -124,6 +124,7 @@ struct wacom_battery {
struct power_supply ac;
char bat_name[WACOM_NAME_MAX];
char ac_name[WACOM_NAME_MAX];
+ int bat_status;
int battery_capacity;
int bat_charging;
int bat_connected;
diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 865e5aa..d8ea686 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1219,7 +1219,9 @@ static int wacom_battery_get_property(struct power_supply *psy,
val->intval = battery->battery_capacity;
break;
case POWER_SUPPLY_PROP_STATUS:
- if (battery->bat_charging)
+ if (battery->bat_status != WACOM_POWER_SUPPLY_STATUS_AUTO)
+ val->intval = battery->bat_status;
+ else if (battery->bat_charging)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else if (battery->battery_capacity == 100 &&
battery->ps_connected)
diff --git a/2.6.38/wacom_wac.c b/2.6.38/wacom_wac.c
index ee8dda3..991459e 100644
--- a/2.6.38/wacom_wac.c
+++ b/2.6.38/wacom_wac.c
@@ -46,15 +46,17 @@ static void wacom_report_numbered_buttons(struct input_dev *input_dev,
int button_cout, int mask);
static void __wacom_notify_battery(struct wacom_battery *battery,
- int bat_capacity, bool bat_charging, bool bat_connected,
- bool ps_connected)
+ int bat_status, int bat_capacity, bool bat_charging,
+ bool bat_connected, bool ps_connected)
{
- bool changed = battery->battery_capacity != bat_capacity ||
+ bool changed = battery->bat_status != bat_status ||
+ battery->battery_capacity != bat_capacity ||
battery->bat_charging != bat_charging ||
battery->bat_connected != bat_connected ||
battery->ps_connected != ps_connected;
if (changed) {
+ battery->bat_status = bat_status;
battery->battery_capacity = bat_capacity;
battery->bat_charging = bat_charging;
battery->bat_connected = bat_connected;
@@ -66,13 +68,13 @@ static void __wacom_notify_battery(struct wacom_battery *battery,
}
static void wacom_notify_battery(struct wacom_wac *wacom_wac,
- int bat_capacity, bool bat_charging, bool bat_connected,
- bool ps_connected)
+ int bat_status, int bat_capacity, bool bat_charging,
+ bool bat_connected, bool ps_connected)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- __wacom_notify_battery(&wacom->battery, bat_capacity, bat_charging,
- bat_connected, ps_connected);
+ __wacom_notify_battery(&wacom->battery, bat_status, bat_capacity,
+ bat_charging, bat_connected, ps_connected);
}
static int wacom_penpartner_irq(struct wacom_wac *wacom)
@@ -1007,7 +1009,8 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
wacom->led.select[i] = touch_ring_mode;
}
- __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
+ __wacom_notify_battery(&remote->remotes[index].battery,
+ WACOM_POWER_SUPPLY_STATUS_AUTO, bat_percent,
bat_charging, 1, bat_charging);
out:
@@ -1699,13 +1702,14 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
}
- wacom_notify_battery(wacom, battery, charging, 1, 0);
+ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
+ battery, charging, 1, 0);
} else if (wacom->pid != 0) {
/* disconnected while previously connected */
wacom->pid = 0;
wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
- wacom_notify_battery(wacom, 0, 0, 0, 0);
+ wacom_notify_battery(wacom, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
}
return 0;
@@ -1733,8 +1737,8 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
int battery = (data[8] & 0x3f) * 100 / 31;
bool charging = !!(data[8] & 0x80);
- wacom_notify_battery(wacom_wac, battery, charging,
- battery || charging, 1);
+ wacom_notify_battery(wacom_wac, WACOM_POWER_SUPPLY_STATUS_AUTO,
+ battery, charging, battery || charging, 1);
if (!wacom->battery.battery.dev &&
!(features->quirks & WACOM_QUIRK_BATTERY)) {
@@ -1746,7 +1750,7 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
wacom->battery.battery.dev) {
features->quirks &= ~WACOM_QUIRK_BATTERY;
wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
- wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
+ wacom_notify_battery(wacom_wac, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
}
return 0;
}
@@ -1768,8 +1772,8 @@ static int wacom_mspro_device_irq(struct wacom_wac *wacom)
wacom_schedule_work(wacom, WACOM_WORKER_BATTERY);
}
- wacom_notify_battery(wacom, battery_level, bat_charging, 1,
- bat_charging);
+ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
+ battery_level, bat_charging, 1, bat_charging);
return 0;
}
diff --git a/2.6.38/wacom_wac.h b/2.6.38/wacom_wac.h
index 156406a..44001f1 100644
--- a/2.6.38/wacom_wac.h
+++ b/2.6.38/wacom_wac.h
@@ -90,6 +90,7 @@
#define WACOM_QUIRK_BATTERY 0x0008
#define WACOM_INTUOSP2_RING_UNTOUCHED 0x7f
+#define WACOM_POWER_SUPPLY_STATUS_AUTO -1
enum {
PENPARTNER = 0,
GRAPHIRE,
diff --git a/3.17/wacom.h b/3.17/wacom.h
index 6d3cb5e..5ae636a 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -140,6 +140,7 @@ struct wacom_battery {
struct power_supply battery;
#endif
char bat_name[WACOM_NAME_MAX];
+ int bat_status;
int battery_capacity;
int bat_charging;
int bat_connected;
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index bbfa9a1..772dfb2 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1321,7 +1321,9 @@ static int wacom_battery_get_property(struct power_supply *psy,
val->intval = battery->battery_capacity;
break;
case POWER_SUPPLY_PROP_STATUS:
- if (battery->bat_charging)
+ if (battery->bat_status != WACOM_POWER_SUPPLY_STATUS_AUTO)
+ val->intval = battery->bat_status;
+ else if (battery->bat_charging)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else if (battery->battery_capacity == 100 &&
battery->ps_connected)
diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 56de142..58dac28 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -63,15 +63,18 @@ static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
static void __wacom_notify_battery(struct wacom_battery *battery,
- int bat_capacity, bool bat_charging,
- bool bat_connected, bool ps_connected)
+ int bat_status, int bat_capacity,
+ bool bat_charging, bool bat_connected,
+ bool ps_connected)
{
- bool changed = battery->battery_capacity != bat_capacity ||
+ bool changed = battery->bat_status != bat_status ||
+ battery->battery_capacity != bat_capacity ||
battery->bat_charging != bat_charging ||
battery->bat_connected != bat_connected ||
battery->ps_connected != ps_connected;
if (changed) {
+ battery->bat_status = bat_status;
battery->battery_capacity = bat_capacity;
battery->bat_charging = bat_charging;
battery->bat_connected = bat_connected;
@@ -83,13 +86,13 @@ static void __wacom_notify_battery(struct wacom_battery *battery,
}
static void wacom_notify_battery(struct wacom_wac *wacom_wac,
- int bat_capacity, bool bat_charging, bool bat_connected,
- bool ps_connected)
+ int bat_status, int bat_capacity, bool bat_charging,
+ bool bat_connected, bool ps_connected)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- __wacom_notify_battery(&wacom->battery, bat_capacity, bat_charging,
- bat_connected, ps_connected);
+ __wacom_notify_battery(&wacom->battery, bat_status, bat_capacity,
+ bat_charging, bat_connected, ps_connected);
}
static int wacom_penpartner_irq(struct wacom_wac *wacom)
@@ -454,8 +457,9 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
rw = (data[7] >> 2 & 0x07);
battery_capacity = batcap_gr[rw];
ps_connected = rw == 7;
- wacom_notify_battery(wacom, battery_capacity, ps_connected,
- 1, ps_connected);
+ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
+ battery_capacity, ps_connected, 1,
+ ps_connected);
}
exit:
return retval;
@@ -1079,7 +1083,8 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
wacom->led.groups[i].select = touch_ring_mode;
}
- __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
+ __wacom_notify_battery(&remote->remotes[index].battery,
+ WACOM_POWER_SUPPLY_STATUS_AUTO, bat_percent,
bat_charging, 1, bat_charging);
@@ -1166,7 +1171,8 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
bat_charging = (power_raw & 0x08) ? 1 : 0;
ps_connected = (power_raw & 0x10) ? 1 : 0;
battery_capacity = batcap_i4[power_raw & 0x07];
- wacom_notify_battery(wacom, battery_capacity, bat_charging,
+ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
+ battery_capacity, bat_charging,
battery_capacity || bat_charging,
ps_connected);
break;
@@ -1343,7 +1349,8 @@ static void wacom_intuos_pro2_bt_battery(struct wacom_wac *wacom)
bool chg = data[284] & 0x80;
int battery_status = data[284] & 0x7F;
- wacom_notify_battery(wacom, battery_status, chg, 1, chg);
+ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
+ battery_status, chg, 1, chg);
}
static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
@@ -1825,6 +1832,7 @@ static void wacom_wac_pad_battery_event(struct hid_device *hdev, struct hid_fiel
value = value * 100 / (field->logical_maximum - field->logical_minimum);
wacom_wac->hid_data.battery_capacity = value;
wacom_wac->hid_data.bat_connected = 1;
+ wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
break;
case WACOM_HID_WD_BATTERY_CHARGING:
@@ -1915,13 +1923,14 @@ static void wacom_wac_pad_battery_report(struct hid_device *hdev,
struct wacom_features *features = &wacom_wac->features;
if (features->quirks & WACOM_QUIRK_BATTERY) {
+ int status = wacom_wac->hid_data.bat_status;
int capacity = wacom_wac->hid_data.battery_capacity;
bool charging = wacom_wac->hid_data.bat_charging;
bool connected = wacom_wac->hid_data.bat_connected;
bool powered = wacom_wac->hid_data.ps_connected;
- wacom_notify_battery(wacom_wac, capacity, charging,
- connected, powered);
+ wacom_notify_battery(wacom_wac, status, capacity,
+ charging, connected, powered);
}
}
@@ -2046,11 +2055,15 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
wacom_wac->hid_data.sense_state = value;
return;
case HID_DG_BATTERYSTRENGTH:
- if (value == 0) /* "not available" */
- break;
- value = value * 100 / (field->logical_maximum - field->logical_minimum);
- wacom_wac->hid_data.battery_capacity = value;
- wacom_wac->hid_data.bat_connected = 1;
+ if (value == 0) {
+ wacom_wac->hid_data.bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
+ }
+ else {
+ value = value * 100 / (field->logical_maximum - field->logical_minimum);
+ wacom_wac->hid_data.battery_capacity = value;
+ wacom_wac->hid_data.bat_connected = 1;
+ wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
+ }
break;
case HID_DG_INVERT:
wacom_wac->hid_data.invert_state = value;
@@ -2828,13 +2841,14 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
}
- wacom_notify_battery(wacom, battery, charging, 1, 0);
+ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
+ battery, charging, 1, 0);
} else if (wacom->pid != 0) {
/* disconnected while previously connected */
wacom->pid = 0;
wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
- wacom_notify_battery(wacom, 0, 0, 0, 0);
+ wacom_notify_battery(wacom, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
}
return 0;
@@ -2862,8 +2876,8 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
int battery = (data[8] & 0x3f) * 100 / 31;
bool charging = !!(data[8] & 0x80);
- wacom_notify_battery(wacom_wac, battery, charging,
- battery || charging, 1);
+ wacom_notify_battery(wacom_wac, WACOM_POWER_SUPPLY_STATUS_AUTO,
+ battery, charging, battery || charging, 1);
if (!WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery) &&
!(features->quirks & WACOM_QUIRK_BATTERY)) {
@@ -2875,7 +2889,7 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery)) {
features->quirks &= ~WACOM_QUIRK_BATTERY;
wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
- wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
+ wacom_notify_battery(wacom_wac, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
}
return 0;
}
diff --git a/3.17/wacom_wac.h b/3.17/wacom_wac.h
index e7dcb0b..e09f073 100644
--- a/3.17/wacom_wac.h
+++ b/3.17/wacom_wac.h
@@ -112,6 +112,8 @@
#define HID_DG_TWIST (HID_UP_DIGITIZER | 0x41)
#endif
+#define WACOM_POWER_SUPPLY_STATUS_AUTO -1
+
#define WACOM_HID_UP_WACOMDIGITIZER 0xff0d0000
#define WACOM_HID_SP_PAD 0x00040000
#define WACOM_HID_SP_BUTTON 0x00090000
@@ -313,6 +315,7 @@ struct hid_data {
int last_slot_field;
int num_expected;
int num_received;
+ int bat_status;
int battery_capacity;
int bat_charging;
int bat_connected;
diff --git a/3.7/wacom.h b/3.7/wacom.h
index c6fc12c..2b34203 100644
--- a/3.7/wacom.h
+++ b/3.7/wacom.h
@@ -120,6 +120,7 @@ struct wacom_battery {
struct power_supply ac;
char bat_name[WACOM_NAME_MAX];
char ac_name[WACOM_NAME_MAX];
+ int bat_status;
int battery_capacity;
int bat_charging;
int bat_connected;
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index c90a68f..dec456c 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1215,7 +1215,9 @@ static int wacom_battery_get_property(struct power_supply *psy,
val->intval = battery->battery_capacity;
break;
case POWER_SUPPLY_PROP_STATUS:
- if (battery->bat_charging)
+ if (battery->bat_status != WACOM_POWER_SUPPLY_STATUS_AUTO)
+ val->intval = battery->bat_status;
+ else if (battery->bat_charging)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else if (battery->battery_capacity == 100 &&
battery->ps_connected)
diff --git a/3.7/wacom_wac.c b/3.7/wacom_wac.c
index 7a60462..1fdb1f3 100644
--- a/3.7/wacom_wac.c
+++ b/3.7/wacom_wac.c
@@ -46,15 +46,17 @@ static void wacom_report_numbered_buttons(struct input_dev *input_dev,
int button_cout, int mask);
static void __wacom_notify_battery(struct wacom_battery *battery,
- int bat_capacity, bool bat_charging, bool bat_connected,
- bool ps_connected)
+ int bat_status, int bat_capacity, bool bat_charging,
+ bool bat_connected, bool ps_connected)
{
- bool changed = battery->battery_capacity != bat_capacity ||
+ bool changed = battery->bat_status != bat_status ||
+ battery->battery_capacity != bat_capacity ||
battery->bat_charging != bat_charging ||
battery->bat_connected != bat_connected ||
battery->ps_connected != ps_connected;
if (changed) {
+ battery->bat_status = bat_status;
battery->battery_capacity = bat_capacity;
battery->bat_charging = bat_charging;
battery->bat_connected = bat_connected;
@@ -66,13 +68,13 @@ static void __wacom_notify_battery(struct wacom_battery *battery,
}
static void wacom_notify_battery(struct wacom_wac *wacom_wac,
- int bat_capacity, bool bat_charging, bool bat_connected,
- bool ps_connected)
+ int bat_status, int bat_capacity, bool bat_charging,
+ bool bat_connected, bool ps_connected)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- __wacom_notify_battery(&wacom->battery, bat_capacity, bat_charging,
- bat_connected, ps_connected);
+ __wacom_notify_battery(&wacom->battery, bat_status, bat_capacity,
+ bat_charging, bat_connected, ps_connected);
}
static int wacom_penpartner_irq(struct wacom_wac *wacom)
@@ -1007,7 +1009,8 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
wacom->led.select[i] = touch_ring_mode;
}
- __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
+ __wacom_notify_battery(&remote->remotes[index].battery,
+ WACOM_POWER_SUPPLY_STATUS_AUTO, bat_percent,
bat_charging, 1, bat_charging);
out:
@@ -1679,13 +1682,14 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
}
- wacom_notify_battery(wacom, battery, charging, 1, 0);
+ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
+ battery, charging, 1, 0);
} else if (wacom->pid != 0) {
/* disconnected while previously connected */
wacom->pid = 0;
wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
- wacom_notify_battery(wacom, 0, 0, 0, 0);
+ wacom_notify_battery(wacom, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
}
return 0;
@@ -1713,8 +1717,8 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
int battery = (data[8] & 0x3f) * 100 / 31;
bool charging = !!(data[8] & 0x80);
- wacom_notify_battery(wacom_wac, battery, charging,
- battery || charging, 1);
+ wacom_notify_battery(wacom_wac, WACOM_POWER_SUPPLY_STATUS_AUTO,
+ battery, charging, battery || charging, 1);
if (!wacom->battery.battery.dev &&
!(features->quirks & WACOM_QUIRK_BATTERY)) {
@@ -1726,7 +1730,7 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
wacom->battery.battery.dev) {
features->quirks &= ~WACOM_QUIRK_BATTERY;
wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
- wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
+ wacom_notify_battery(wacom_wac, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
}
return 0;
}
@@ -1748,8 +1752,8 @@ static int wacom_mspro_device_irq(struct wacom_wac *wacom)
wacom_schedule_work(wacom, WACOM_WORKER_BATTERY);
}
- wacom_notify_battery(wacom, battery_level, bat_charging, 1,
- bat_charging);
+ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
+ battery_level, bat_charging, 1, bat_charging);
return 0;
}
diff --git a/3.7/wacom_wac.h b/3.7/wacom_wac.h
index 5081753..06bd4ba 100644
--- a/3.7/wacom_wac.h
+++ b/3.7/wacom_wac.h
@@ -90,6 +90,7 @@
#define WACOM_QUIRK_BATTERY 0x0008
#define WACOM_INTUOSP2_RING_UNTOUCHED 0x7f
+#define WACOM_POWER_SUPPLY_STATUS_AUTO -1
enum {
PENPARTNER = 0,
GRAPHIRE,
--
2.12.2