Line data Source code
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 0 : uberry_match(struct device *parent, void *match, void *aux)
74 : {
75 0 : struct usb_attach_arg *uaa = aux;
76 :
77 0 : if (uaa->iface == NULL || uaa->configno != UBERRY_CONFIG_NO)
78 0 : return UMATCH_NONE;
79 :
80 0 : return (usb_lookup(uberry_devices, uaa->vendor, uaa->product) != NULL) ?
81 : UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
82 0 : }
83 :
84 : void
85 0 : uberry_attach(struct device *parent, struct device *self, void *aux)
86 : {
87 0 : struct uberry_softc *sc = (struct uberry_softc *)self;
88 0 : struct usb_attach_arg *uaa = aux;
89 : usb_device_descriptor_t *dd;
90 :
91 0 : sc->sc_udev = uaa->device;
92 :
93 0 : dd = usbd_get_device_descriptor(uaa->device);
94 :
95 0 : printf("%s: Charging at %dmA", sc->sc_dev.dv_xname,
96 0 : sc->sc_udev->power);
97 0 : if (sc->sc_udev->power >= 250)
98 0 : printf("\n");
99 : else {
100 0 : printf("... requesting higher-power charging\n");
101 0 : 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 0 : if (UGETW(dd->idProduct) == USB_PRODUCT_RIM_PEARL)
110 0 : uberry_pearlmode(sc);
111 :
112 : /* Enable the device, then it cannot idle, and will charge */
113 0 : if (usbd_set_config_no(sc->sc_udev, UBERRY_CONFIG_NO, 1) != 0) {
114 0 : printf("%s: could not set configuration no\n",
115 : sc->sc_dev.dv_xname);
116 0 : return;
117 : }
118 :
119 0 : 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 0 : usb_needs_reattach(sc->sc_udev);
126 0 : }
127 0 : }
128 :
129 : int
130 0 : uberry_detach(struct device *self, int flags)
131 : {
132 : /* struct uberry_softc *sc = (struct uberry_softc *)self; */
133 :
134 0 : return 0;
135 : }
136 :
137 : void
138 0 : uberry_pearlmode(struct uberry_softc *sc)
139 : {
140 0 : usb_device_request_t req;
141 0 : char buffer[256];
142 :
143 0 : req.bmRequestType = UT_READ_VENDOR_DEVICE;
144 0 : req.bRequest = 0xa9;
145 0 : USETW(req.wValue, 1);
146 0 : USETW(req.wIndex, 1);
147 0 : USETW(req.wLength, 2);
148 0 : (void) usbd_do_request(sc->sc_udev, &req, &buffer);
149 0 : }
150 :
151 : void
152 0 : uberry_charge(struct uberry_softc *sc)
153 : {
154 0 : usb_device_request_t req;
155 0 : char buffer[256];
156 :
157 0 : req.bmRequestType = UT_READ_VENDOR_DEVICE;
158 0 : req.bRequest = 0xa5;
159 0 : USETW(req.wValue, 0);
160 0 : USETW(req.wIndex, 1);
161 0 : USETW(req.wLength, 2);
162 0 : (void) usbd_do_request(sc->sc_udev, &req, &buffer);
163 :
164 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
165 0 : req.bRequest = 0xa2;
166 0 : USETW(req.wValue, 0);
167 0 : USETW(req.wIndex, 1);
168 0 : USETW(req.wLength, 0);
169 0 : (void) usbd_do_request(sc->sc_udev, &req, &buffer);
170 0 : }
|