1 /* $OpenBSD: uberry.c,v 1.24 2016/11/06 12:58:01 mpi 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/sockio.h> 21 #include <sys/mbuf.h> 22 #include <sys/kernel.h> 23 #include <sys/socket.h> 24 #include <sys/systm.h> 25 #include <sys/timeout.h> 26 #include <sys/conf.h> 27 #include <sys/device.h> 28 #include <sys/endian.h> 29 30 #include <machine/bus.h> 31 #include <machine/intr.h> 32 33 #include <dev/usb/usb.h> 34 #include <dev/usb/usbdi.h> 35 #include <dev/usb/usbdivar.h> 36 #include <dev/usb/usbdi_util.h> 37 #include <dev/usb/usbdevs.h> 38 39 struct uberry_softc { 40 struct device sc_dev; 41 struct usbd_device *sc_udev; 42 struct usbd_interface *sc_iface; 43 }; 44 45 #define UBERRY_INTERFACE_NO 0 46 #define UBERRY_CONFIG_NO 1 47 48 /* 49 * Do not match on the following device, because it is type umass 50 * { USB_VENDOR_RIM, USB_PRODUCT_RIM_PEARL_DUAL }, 51 */ 52 struct usb_devno const uberry_devices[] = { 53 { USB_VENDOR_RIM, USB_PRODUCT_RIM_BLACKBERRY }, 54 { USB_VENDOR_RIM, USB_PRODUCT_RIM_PEARL } 55 }; 56 57 int uberry_match(struct device *, void *, void *); 58 void uberry_attach(struct device *, struct device *, void *); 59 int uberry_detach(struct device *, int); 60 61 void uberry_pearlmode(struct uberry_softc *); 62 void uberry_charge(struct uberry_softc *); 63 64 struct cfdriver uberry_cd = { 65 NULL, "uberry", DV_DULL 66 }; 67 68 const struct cfattach uberry_ca = { 69 sizeof(struct uberry_softc), uberry_match, uberry_attach, uberry_detach 70 }; 71 72 int 73 uberry_match(struct device *parent, void *match, void *aux) 74 { 75 struct usb_attach_arg *uaa = aux; 76 77 if (uaa->iface == NULL || uaa->configno != UBERRY_CONFIG_NO) 78 return UMATCH_NONE; 79 80 return (usb_lookup(uberry_devices, uaa->vendor, uaa->product) != NULL) ? 81 UMATCH_VENDOR_PRODUCT : UMATCH_NONE; 82 } 83 84 void 85 uberry_attach(struct device *parent, struct device *self, void *aux) 86 { 87 struct uberry_softc *sc = (struct uberry_softc *)self; 88 struct usb_attach_arg *uaa = aux; 89 usb_device_descriptor_t *dd; 90 91 sc->sc_udev = uaa->device; 92 93 dd = usbd_get_device_descriptor(uaa->device); 94 95 printf("%s: Charging at %dmA", sc->sc_dev.dv_xname, 96 sc->sc_udev->power); 97 if (sc->sc_udev->power >= 250) 98 printf("\n"); 99 else { 100 printf("... requesting higher-power charging\n"); 101 uberry_charge(sc); 102 /* 103 * Older berry's will disconnect/reconnect at this 104 * point, and come back requesting higher power 105 */ 106 } 107 108 /* On the Pearl, request a change to Dual mode */ 109 if (UGETW(dd->idProduct) == USB_PRODUCT_RIM_PEARL) 110 uberry_pearlmode(sc); 111 112 /* Enable the device, then it cannot idle, and will charge */ 113 if (usbd_set_config_no(sc->sc_udev, UBERRY_CONFIG_NO, 1) != 0) { 114 printf("%s: could not set configuration no\n", 115 sc->sc_dev.dv_xname); 116 return; 117 } 118 119 if (UGETW(dd->idProduct) == USB_PRODUCT_RIM_PEARL) { 120 /* 121 * Pearl does not disconnect/reconnect by itself, 122 * and therefore needs to be told to reset, so that 123 * it can come back in Dual mode. 124 */ 125 usb_needs_reattach(sc->sc_udev); 126 } 127 } 128 129 int 130 uberry_detach(struct device *self, int flags) 131 { 132 /* struct uberry_softc *sc = (struct uberry_softc *)self; */ 133 134 return 0; 135 } 136 137 void 138 uberry_pearlmode(struct uberry_softc *sc) 139 { 140 usb_device_request_t req; 141 char buffer[256]; 142 143 req.bmRequestType = UT_READ_VENDOR_DEVICE; 144 req.bRequest = 0xa9; 145 USETW(req.wValue, 1); 146 USETW(req.wIndex, 1); 147 USETW(req.wLength, 2); 148 (void) usbd_do_request(sc->sc_udev, &req, &buffer); 149 } 150 151 void 152 uberry_charge(struct uberry_softc *sc) 153 { 154 usb_device_request_t req; 155 char buffer[256]; 156 157 req.bmRequestType = UT_READ_VENDOR_DEVICE; 158 req.bRequest = 0xa5; 159 USETW(req.wValue, 0); 160 USETW(req.wIndex, 1); 161 USETW(req.wLength, 2); 162 (void) usbd_do_request(sc->sc_udev, &req, &buffer); 163 164 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 165 req.bRequest = 0xa2; 166 USETW(req.wValue, 0); 167 USETW(req.wIndex, 1); 168 USETW(req.wLength, 0); 169 (void) usbd_do_request(sc->sc_udev, &req, &buffer); 170 } 171