1*81508fe3Sjsg /* $OpenBSD: uberry.c,v 1.25 2024/05/23 03:21:09 jsg Exp $ */
2297adcccSderaadt
3297adcccSderaadt /*-
4297adcccSderaadt * Copyright (c) 2006 Theo de Raadt <deraadt@openbsd.org>
5297adcccSderaadt *
6297adcccSderaadt * Permission to use, copy, modify, and distribute this software for any
7297adcccSderaadt * purpose with or without fee is hereby granted, provided that the above
8297adcccSderaadt * copyright notice and this permission notice appear in all copies.
9297adcccSderaadt *
10297adcccSderaadt * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11297adcccSderaadt * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12297adcccSderaadt * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13297adcccSderaadt * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14297adcccSderaadt * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15297adcccSderaadt * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16297adcccSderaadt * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17297adcccSderaadt */
18297adcccSderaadt
19297adcccSderaadt #include <sys/param.h>
20297adcccSderaadt #include <sys/systm.h>
21297adcccSderaadt #include <sys/device.h>
22297adcccSderaadt
23297adcccSderaadt #include <machine/bus.h>
24297adcccSderaadt
25297adcccSderaadt #include <dev/usb/usb.h>
26297adcccSderaadt #include <dev/usb/usbdi.h>
2701e61936Sderaadt #include <dev/usb/usbdivar.h>
28297adcccSderaadt #include <dev/usb/usbdi_util.h>
29297adcccSderaadt #include <dev/usb/usbdevs.h>
30297adcccSderaadt
31297adcccSderaadt struct uberry_softc {
328c5d01eeSmk struct device sc_dev;
33ab0b1be7Smglocker struct usbd_device *sc_udev;
34ab0b1be7Smglocker struct usbd_interface *sc_iface;
35297adcccSderaadt };
36297adcccSderaadt
37fdedb769Sderaadt #define UBERRY_INTERFACE_NO 0
3801e61936Sderaadt #define UBERRY_CONFIG_NO 1
39297adcccSderaadt
40f0462a21Sderaadt /*
41f0462a21Sderaadt * Do not match on the following device, because it is type umass
42f0462a21Sderaadt * { USB_VENDOR_RIM, USB_PRODUCT_RIM_PEARL_DUAL },
43f0462a21Sderaadt */
4478315254Smbalmer struct usb_devno const uberry_devices[] = {
4501e61936Sderaadt { USB_VENDOR_RIM, USB_PRODUCT_RIM_BLACKBERRY },
4601e61936Sderaadt { USB_VENDOR_RIM, USB_PRODUCT_RIM_PEARL }
47297adcccSderaadt };
48297adcccSderaadt
499f5f6d50Smbalmer int uberry_match(struct device *, void *, void *);
509f5f6d50Smbalmer void uberry_attach(struct device *, struct device *, void *);
519f5f6d50Smbalmer int uberry_detach(struct device *, int);
529f5f6d50Smbalmer
5301e61936Sderaadt void uberry_pearlmode(struct uberry_softc *);
5401e61936Sderaadt void uberry_charge(struct uberry_softc *);
5501e61936Sderaadt
569f5f6d50Smbalmer struct cfdriver uberry_cd = {
579f5f6d50Smbalmer NULL, "uberry", DV_DULL
589f5f6d50Smbalmer };
599f5f6d50Smbalmer
609f5f6d50Smbalmer const struct cfattach uberry_ca = {
61cf8c8cdaSmpi sizeof(struct uberry_softc), uberry_match, uberry_attach, uberry_detach
629f5f6d50Smbalmer };
63297adcccSderaadt
64de5d9ff0Sjsg int
uberry_match(struct device * parent,void * match,void * aux)65de5d9ff0Sjsg uberry_match(struct device *parent, void *match, void *aux)
66297adcccSderaadt {
67de5d9ff0Sjsg struct usb_attach_arg *uaa = aux;
68297adcccSderaadt
69f4b7d08eSmpi if (uaa->iface == NULL || uaa->configno != UBERRY_CONFIG_NO)
70297adcccSderaadt return UMATCH_NONE;
71297adcccSderaadt
72297adcccSderaadt return (usb_lookup(uberry_devices, uaa->vendor, uaa->product) != NULL) ?
73297adcccSderaadt UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
74297adcccSderaadt }
75297adcccSderaadt
76de5d9ff0Sjsg void
uberry_attach(struct device * parent,struct device * self,void * aux)77de5d9ff0Sjsg uberry_attach(struct device *parent, struct device *self, void *aux)
78297adcccSderaadt {
79de5d9ff0Sjsg struct uberry_softc *sc = (struct uberry_softc *)self;
80de5d9ff0Sjsg struct usb_attach_arg *uaa = aux;
8101e61936Sderaadt usb_device_descriptor_t *dd;
82297adcccSderaadt
83297adcccSderaadt sc->sc_udev = uaa->device;
84297adcccSderaadt
8501e61936Sderaadt dd = usbd_get_device_descriptor(uaa->device);
8601e61936Sderaadt
8701e61936Sderaadt printf("%s: Charging at %dmA", sc->sc_dev.dv_xname,
8801e61936Sderaadt sc->sc_udev->power);
8901e61936Sderaadt if (sc->sc_udev->power >= 250)
9001e61936Sderaadt printf("\n");
9101e61936Sderaadt else {
9201e61936Sderaadt printf("... requesting higher-power charging\n");
9301e61936Sderaadt uberry_charge(sc);
94fdedb769Sderaadt /*
95fdedb769Sderaadt * Older berry's will disconnect/reconnect at this
96fdedb769Sderaadt * point, and come back requesting higher power
97fdedb769Sderaadt */
98fdedb769Sderaadt }
99fdedb769Sderaadt
100fdedb769Sderaadt /* On the Pearl, request a change to Dual mode */
101fdedb769Sderaadt if (UGETW(dd->idProduct) == USB_PRODUCT_RIM_PEARL)
102fdedb769Sderaadt uberry_pearlmode(sc);
103fdedb769Sderaadt
104fdedb769Sderaadt /* Enable the device, then it cannot idle, and will charge */
105fdedb769Sderaadt if (usbd_set_config_no(sc->sc_udev, UBERRY_CONFIG_NO, 1) != 0) {
106fdedb769Sderaadt printf("%s: could not set configuration no\n",
107fdedb769Sderaadt sc->sc_dev.dv_xname);
108fdedb769Sderaadt return;
10901e61936Sderaadt }
11001e61936Sderaadt
11101e61936Sderaadt if (UGETW(dd->idProduct) == USB_PRODUCT_RIM_PEARL) {
112fdedb769Sderaadt /*
113fdedb769Sderaadt * Pearl does not disconnect/reconnect by itself,
114fdedb769Sderaadt * and therefore needs to be told to reset, so that
115fdedb769Sderaadt * it can come back in Dual mode.
116fdedb769Sderaadt */
11701e61936Sderaadt usb_needs_reattach(sc->sc_udev);
11801e61936Sderaadt }
119297adcccSderaadt }
120297adcccSderaadt
121de5d9ff0Sjsg int
uberry_detach(struct device * self,int flags)122de5d9ff0Sjsg uberry_detach(struct device *self, int flags)
123297adcccSderaadt {
1240036ea2dSjakemsr /* struct uberry_softc *sc = (struct uberry_softc *)self; */
125f9bafeb6Smiod
126297adcccSderaadt return 0;
127297adcccSderaadt }
128297adcccSderaadt
12901e61936Sderaadt void
uberry_pearlmode(struct uberry_softc * sc)13001e61936Sderaadt uberry_pearlmode(struct uberry_softc *sc)
13101e61936Sderaadt {
13201e61936Sderaadt usb_device_request_t req;
13301e61936Sderaadt char buffer[256];
13401e61936Sderaadt
13501e61936Sderaadt req.bmRequestType = UT_READ_VENDOR_DEVICE;
13601e61936Sderaadt req.bRequest = 0xa9;
13701e61936Sderaadt USETW(req.wValue, 1);
13801e61936Sderaadt USETW(req.wIndex, 1);
13901e61936Sderaadt USETW(req.wLength, 2);
14001e61936Sderaadt (void) usbd_do_request(sc->sc_udev, &req, &buffer);
14101e61936Sderaadt }
14201e61936Sderaadt
14301e61936Sderaadt void
uberry_charge(struct uberry_softc * sc)14401e61936Sderaadt uberry_charge(struct uberry_softc *sc)
14501e61936Sderaadt {
14601e61936Sderaadt usb_device_request_t req;
14701e61936Sderaadt char buffer[256];
14801e61936Sderaadt
14901e61936Sderaadt req.bmRequestType = UT_READ_VENDOR_DEVICE;
15001e61936Sderaadt req.bRequest = 0xa5;
15101e61936Sderaadt USETW(req.wValue, 0);
15201e61936Sderaadt USETW(req.wIndex, 1);
15301e61936Sderaadt USETW(req.wLength, 2);
15401e61936Sderaadt (void) usbd_do_request(sc->sc_udev, &req, &buffer);
15501e61936Sderaadt
15601e61936Sderaadt req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
15701e61936Sderaadt req.bRequest = 0xa2;
15801e61936Sderaadt USETW(req.wValue, 0);
15901e61936Sderaadt USETW(req.wIndex, 1);
16001e61936Sderaadt USETW(req.wLength, 0);
16101e61936Sderaadt (void) usbd_do_request(sc->sc_udev, &req, &buffer);
16201e61936Sderaadt }
163