1 /* $OpenBSD: uberry.c,v 1.25 2024/05/23 03:21:09 jsg Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Theo de Raadt <deraadt@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 23 #include <machine/bus.h> 24 25 #include <dev/usb/usb.h> 26 #include <dev/usb/usbdi.h> 27 #include <dev/usb/usbdivar.h> 28 #include <dev/usb/usbdi_util.h> 29 #include <dev/usb/usbdevs.h> 30 31 struct uberry_softc { 32 struct device sc_dev; 33 struct usbd_device *sc_udev; 34 struct usbd_interface *sc_iface; 35 }; 36 37 #define UBERRY_INTERFACE_NO 0 38 #define UBERRY_CONFIG_NO 1 39 40 /* 41 * Do not match on the following device, because it is type umass 42 * { USB_VENDOR_RIM, USB_PRODUCT_RIM_PEARL_DUAL }, 43 */ 44 struct usb_devno const uberry_devices[] = { 45 { USB_VENDOR_RIM, USB_PRODUCT_RIM_BLACKBERRY }, 46 { USB_VENDOR_RIM, USB_PRODUCT_RIM_PEARL } 47 }; 48 49 int uberry_match(struct device *, void *, void *); 50 void uberry_attach(struct device *, struct device *, void *); 51 int uberry_detach(struct device *, int); 52 53 void uberry_pearlmode(struct uberry_softc *); 54 void uberry_charge(struct uberry_softc *); 55 56 struct cfdriver uberry_cd = { 57 NULL, "uberry", DV_DULL 58 }; 59 60 const struct cfattach uberry_ca = { 61 sizeof(struct uberry_softc), uberry_match, uberry_attach, uberry_detach 62 }; 63 64 int 65 uberry_match(struct device *parent, void *match, void *aux) 66 { 67 struct usb_attach_arg *uaa = aux; 68 69 if (uaa->iface == NULL || uaa->configno != UBERRY_CONFIG_NO) 70 return UMATCH_NONE; 71 72 return (usb_lookup(uberry_devices, uaa->vendor, uaa->product) != NULL) ? 73 UMATCH_VENDOR_PRODUCT : UMATCH_NONE; 74 } 75 76 void 77 uberry_attach(struct device *parent, struct device *self, void *aux) 78 { 79 struct uberry_softc *sc = (struct uberry_softc *)self; 80 struct usb_attach_arg *uaa = aux; 81 usb_device_descriptor_t *dd; 82 83 sc->sc_udev = uaa->device; 84 85 dd = usbd_get_device_descriptor(uaa->device); 86 87 printf("%s: Charging at %dmA", sc->sc_dev.dv_xname, 88 sc->sc_udev->power); 89 if (sc->sc_udev->power >= 250) 90 printf("\n"); 91 else { 92 printf("... requesting higher-power charging\n"); 93 uberry_charge(sc); 94 /* 95 * Older berry's will disconnect/reconnect at this 96 * point, and come back requesting higher power 97 */ 98 } 99 100 /* On the Pearl, request a change to Dual mode */ 101 if (UGETW(dd->idProduct) == USB_PRODUCT_RIM_PEARL) 102 uberry_pearlmode(sc); 103 104 /* Enable the device, then it cannot idle, and will charge */ 105 if (usbd_set_config_no(sc->sc_udev, UBERRY_CONFIG_NO, 1) != 0) { 106 printf("%s: could not set configuration no\n", 107 sc->sc_dev.dv_xname); 108 return; 109 } 110 111 if (UGETW(dd->idProduct) == USB_PRODUCT_RIM_PEARL) { 112 /* 113 * Pearl does not disconnect/reconnect by itself, 114 * and therefore needs to be told to reset, so that 115 * it can come back in Dual mode. 116 */ 117 usb_needs_reattach(sc->sc_udev); 118 } 119 } 120 121 int 122 uberry_detach(struct device *self, int flags) 123 { 124 /* struct uberry_softc *sc = (struct uberry_softc *)self; */ 125 126 return 0; 127 } 128 129 void 130 uberry_pearlmode(struct uberry_softc *sc) 131 { 132 usb_device_request_t req; 133 char buffer[256]; 134 135 req.bmRequestType = UT_READ_VENDOR_DEVICE; 136 req.bRequest = 0xa9; 137 USETW(req.wValue, 1); 138 USETW(req.wIndex, 1); 139 USETW(req.wLength, 2); 140 (void) usbd_do_request(sc->sc_udev, &req, &buffer); 141 } 142 143 void 144 uberry_charge(struct uberry_softc *sc) 145 { 146 usb_device_request_t req; 147 char buffer[256]; 148 149 req.bmRequestType = UT_READ_VENDOR_DEVICE; 150 req.bRequest = 0xa5; 151 USETW(req.wValue, 0); 152 USETW(req.wIndex, 1); 153 USETW(req.wLength, 2); 154 (void) usbd_do_request(sc->sc_udev, &req, &buffer); 155 156 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 157 req.bRequest = 0xa2; 158 USETW(req.wValue, 0); 159 USETW(req.wIndex, 1); 160 USETW(req.wLength, 0); 161 (void) usbd_do_request(sc->sc_udev, &req, &buffer); 162 } 163