1 | /* $NetBSD: uberry.c,v 1.10 2016/04/23 10:15:32 skrll Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Christos Zoulas. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. All advertising materials mentioning features or use of this software |
19 | * must display the following acknowledgement: |
20 | * This product includes software developed by the NetBSD |
21 | * Foundation, Inc. and its contributors. |
22 | * 4. Neither the name of The NetBSD Foundation nor the names of its |
23 | * contributors may be used to endorse or promote products derived |
24 | * from this software without specific pberryr written permission. |
25 | * |
26 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
27 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
28 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
29 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
30 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
35 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
36 | * POSSIBILITY OF SUCH DAMAGE. |
37 | */ |
38 | |
39 | #include <sys/cdefs.h> |
40 | __KERNEL_RCSID(0, "$NetBSD: uberry.c,v 1.10 2016/04/23 10:15:32 skrll Exp $" ); |
41 | |
42 | #include <sys/param.h> |
43 | #include <sys/systm.h> |
44 | #include <sys/kernel.h> |
45 | #include <sys/device.h> |
46 | #include <sys/ioctl.h> |
47 | #include <sys/conf.h> |
48 | #include <sys/file.h> |
49 | #include <sys/select.h> |
50 | #include <sys/proc.h> |
51 | #include <sys/vnode.h> |
52 | #include <sys/poll.h> |
53 | #include <sys/bus.h> |
54 | |
55 | #include <dev/usb/usb.h> |
56 | #include <dev/usb/usbdi.h> |
57 | #include <dev/usb/usbdi_util.h> |
58 | #include <dev/usb/usbdivar.h> |
59 | |
60 | #include <dev/usb/usbdevs.h> |
61 | |
62 | #ifdef UBERRY_DEBUG |
63 | #define DPRINTF(x) if (uberrydebug) printf x |
64 | #define DPRINTFN(n, x) if (uberrydebug > n) printf x |
65 | int uberrydebug = 0; |
66 | #else |
67 | #define DPRINTF(x) |
68 | #define DPRINTFN(n, x) |
69 | #endif |
70 | |
71 | struct uberry_softc { |
72 | device_t sc_dev; |
73 | struct usbd_device * sc_udev; |
74 | }; |
75 | |
76 | /* |
77 | * Note that we do not attach to USB_PRODUCT_RIM_BLACKBERRY_PEARL_DUAL |
78 | * as we let umass claim the device instead. |
79 | */ |
80 | static const struct usb_devno uberry_devs[] = { |
81 | { USB_VENDOR_RIM, USB_PRODUCT_RIM_BLACKBERRY }, |
82 | { USB_VENDOR_RIM, USB_PRODUCT_RIM_BLACKBERRY_PEARL }, |
83 | }; |
84 | |
85 | #define uberry_lookup(v, p) usb_lookup(uberry_devs, v, p) |
86 | #define UBERRY_CONFIG_NO 1 |
87 | |
88 | int uberry_match(device_t, cfdata_t, void *); |
89 | void uberry_attach(device_t, device_t, void *); |
90 | int uberry_detach(device_t, int); |
91 | int uberry_activate(device_t, enum devact); |
92 | extern struct cfdriver uberry_cd; |
93 | CFATTACH_DECL_NEW(uberry, sizeof(struct uberry_softc), uberry_match, |
94 | uberry_attach, uberry_detach, NULL); |
95 | |
96 | static void |
97 | uberry_cmd(struct uberry_softc *sc, uint8_t requestType, uint8_t reqno, |
98 | uint8_t value, uint8_t index, void *data, uint8_t length) |
99 | { |
100 | usb_device_request_t req; |
101 | usbd_status err; |
102 | |
103 | DPRINTF(("berry cmd type=%x, number=%x, value=%d, index=%d, len=%d\n" , |
104 | requestType, reqno, value, index, length)); |
105 | req.bmRequestType = requestType; |
106 | req.bRequest = reqno; |
107 | USETW(req.wValue, value); |
108 | USETW(req.wIndex, index); |
109 | USETW(req.wLength, length); |
110 | |
111 | if ((err = usbd_do_request(sc->sc_udev, &req, data)) != 0) |
112 | aprint_error_dev(sc->sc_dev, "sending command failed %d\n" , |
113 | err); |
114 | } |
115 | |
116 | static void |
117 | uberry_charge(struct uberry_softc *sc) |
118 | { |
119 | char dummy[2]; |
120 | usbd_status err; |
121 | |
122 | if (sc->sc_udev->ud_power != USB_MAX_POWER) { |
123 | uberry_cmd(sc, UT_READ | UT_VENDOR, 0xa5, 0, 1, dummy, 2); |
124 | uberry_cmd(sc, UT_WRITE | UT_VENDOR, 0xa2, 0, 1, dummy, 0); |
125 | } |
126 | |
127 | err = usbd_set_config_no(sc->sc_udev, UBERRY_CONFIG_NO, 1); |
128 | if (err) { |
129 | aprint_error_dev(sc->sc_dev, "failed to set configuration" |
130 | ", err=%s\n" , usbd_errstr(err)); |
131 | return; |
132 | } |
133 | } |
134 | |
135 | /* |
136 | * Expose both the USB mass storage interface and the database access one |
137 | */ |
138 | static void |
139 | uberry_dual_mode(struct uberry_softc *sc) |
140 | { |
141 | char dummy[2]; |
142 | usbd_status err; |
143 | |
144 | uberry_cmd(sc, UT_READ | UT_VENDOR, 0xa9, 1, 1, dummy, 2); |
145 | |
146 | err = usbd_set_config_no(sc->sc_udev, UBERRY_CONFIG_NO, 1); |
147 | if (err) { |
148 | aprint_error_dev(sc->sc_dev, "failed to set configuration" |
149 | ", err=%s\n" , usbd_errstr(err)); |
150 | return; |
151 | } |
152 | } |
153 | |
154 | |
155 | int |
156 | uberry_match(device_t parent, cfdata_t match, void *aux) |
157 | { |
158 | struct usb_attach_arg *uaa = aux; |
159 | |
160 | DPRINTFN(50, ("uberry_match\n" )); |
161 | return (uberry_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? |
162 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE); |
163 | } |
164 | |
165 | void |
166 | uberry_attach(device_t parent, device_t self, void *aux) |
167 | { |
168 | struct uberry_softc *sc = device_private(self); |
169 | struct usb_attach_arg *uaa = aux; |
170 | struct usbd_device * dev = uaa->uaa_device; |
171 | char *devinfop; |
172 | |
173 | DPRINTFN(10,("uberry_attach: sc=%p\n" , sc)); |
174 | |
175 | sc->sc_dev = self; |
176 | sc->sc_udev = dev; |
177 | |
178 | aprint_naive("\n" ); |
179 | aprint_normal("\n" ); |
180 | |
181 | devinfop = usbd_devinfo_alloc(dev, 0); |
182 | aprint_normal_dev(self, "%s\n" , devinfop); |
183 | usbd_devinfo_free(devinfop); |
184 | |
185 | uberry_charge(sc); |
186 | if (uaa->uaa_product == USB_PRODUCT_RIM_BLACKBERRY_PEARL) |
187 | uberry_dual_mode(sc); |
188 | |
189 | DPRINTFN(10, ("uberry_attach: %p\n" , sc->sc_udev)); |
190 | |
191 | if (!pmf_device_register(self, NULL, NULL)) |
192 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
193 | |
194 | usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); |
195 | return; |
196 | } |
197 | |
198 | int |
199 | uberry_detach(device_t self, int flags) |
200 | { |
201 | struct uberry_softc *sc = device_private(self); |
202 | DPRINTF(("uberry_detach: sc=%p flags=%d\n" , sc, flags)); |
203 | |
204 | pmf_device_deregister(self); |
205 | |
206 | usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); |
207 | |
208 | return (0); |
209 | } |
210 | |