1 /* $OpenBSD: uvisor.c,v 1.3 2001/05/03 02:20:35 aaron Exp $ */ 2 /* $NetBSD: uvisor.c,v 1.11 2001/01/23 21:56:17 augustss Exp $ */ 3 4 /* 5 * Copyright (c) 2000 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Lennart Augustsson (lennart@augustsson.net) at 10 * Carlstedt Research & Technology. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the NetBSD 23 * Foundation, Inc. and its contributors. 24 * 4. Neither the name of The NetBSD Foundation nor the names of its 25 * contributors may be used to endorse or promote products derived 26 * from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 /* 42 * Handspring Visor (Palmpilot compatible PDA) driver 43 */ 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/kernel.h> 48 #include <sys/device.h> 49 #include <sys/conf.h> 50 #include <sys/tty.h> 51 52 #include <dev/usb/usb.h> 53 #include <dev/usb/usbhid.h> 54 55 #include <dev/usb/usbdi.h> 56 #include <dev/usb/usbdi_util.h> 57 #include <dev/usb/usbdevs.h> 58 59 #include <dev/usb/ucomvar.h> 60 61 #ifdef UVISOR_DEBUG 62 #define DPRINTF(x) if (uvisordebug) printf x 63 #define DPRINTFN(n,x) if (uvisordebug>(n)) printf x 64 int uvisordebug = 0; 65 #else 66 #define DPRINTF(x) 67 #define DPRINTFN(n,x) 68 #endif 69 70 #define UVISOR_CONFIG_INDEX 0 71 #define UVISOR_IFACE_INDEX 0 72 73 /* From the Linux driver */ 74 /* 75 * UVISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that 76 * are available to be transfered to the host for the specified endpoint. 77 * Currently this is not used, and always returns 0x0001 78 */ 79 #define UVISOR_REQUEST_BYTES_AVAILABLE 0x01 80 81 /* 82 * UVISOR_CLOSE_NOTIFICATION is set to the device to notify it that the host 83 * is now closing the pipe. An empty packet is sent in response. 84 */ 85 #define UVISOR_CLOSE_NOTIFICATION 0x02 86 87 /* 88 * UVISOR_GET_CONNECTION_INFORMATION is sent by the host during enumeration to 89 * get the endpoints used by the connection. 90 */ 91 #define UVISOR_GET_CONNECTION_INFORMATION 0x03 92 93 94 /* 95 * UVISOR_GET_CONNECTION_INFORMATION returns data in the following format 96 */ 97 #define UVISOR_MAX_CONN 8 98 struct uvisor_connection_info { 99 uWord num_ports; 100 struct { 101 uByte port_function_id; 102 uByte port; 103 } connections[UVISOR_MAX_CONN]; 104 }; 105 #define UVISOR_CONNECTION_INFO_SIZE 18 106 107 108 /* struct uvisor_connection_info.connection[x].port_function_id defines: */ 109 #define UVISOR_FUNCTION_GENERIC 0x00 110 #define UVISOR_FUNCTION_DEBUGGER 0x01 111 #define UVISOR_FUNCTION_HOTSYNC 0x02 112 #define UVISOR_FUNCTION_CONSOLE 0x03 113 #define UVISOR_FUNCTION_REMOTE_FILE_SYS 0x04 114 115 116 #define UVISORIBUFSIZE 1024 117 #define UVISOROBUFSIZE 1024 118 119 struct uvisor_softc { 120 USBBASEDEVICE sc_dev; /* base device */ 121 usbd_device_handle sc_udev; /* device */ 122 usbd_interface_handle sc_iface; /* interface */ 123 124 device_ptr_t sc_subdevs[UVISOR_MAX_CONN]; 125 int sc_numcon; 126 127 u_char sc_dying; 128 }; 129 130 Static usbd_status uvisor_init(struct uvisor_softc *, 131 struct uvisor_connection_info *); 132 133 Static void uvisor_close(void *, int); 134 135 136 struct ucom_methods uvisor_methods = { 137 NULL, 138 NULL, 139 NULL, 140 NULL, 141 NULL, 142 uvisor_close, 143 NULL, 144 NULL, 145 }; 146 147 USB_DECLARE_DRIVER(uvisor); 148 149 USB_MATCH(uvisor) 150 { 151 USB_MATCH_START(uvisor, uaa); 152 153 if (uaa->iface != NULL) 154 return (UMATCH_NONE); 155 156 DPRINTFN(20,("uvisor: vendor=0x%x, product=0x%x\n", 157 uaa->vendor, uaa->product)); 158 159 if (uaa->vendor == USB_VENDOR_HANDSPRING && 160 uaa->product == USB_PRODUCT_HANDSPRING_VISOR) 161 return (UMATCH_VENDOR_PRODUCT); 162 163 return (UMATCH_NONE); 164 } 165 166 USB_ATTACH(uvisor) 167 { 168 USB_ATTACH_START(uvisor, sc, uaa); 169 usbd_device_handle dev = uaa->device; 170 usbd_interface_handle iface; 171 usb_interface_descriptor_t *id; 172 struct uvisor_connection_info coninfo; 173 usb_endpoint_descriptor_t *ed; 174 char devinfo[1024]; 175 char *devname = USBDEVNAME(sc->sc_dev); 176 int i, j, hasin, hasout, port; 177 usbd_status err; 178 struct ucom_attach_args uca; 179 180 DPRINTFN(10,("\nuvisor_attach: sc=%p\n", sc)); 181 182 /* Move the device into the configured state. */ 183 err = usbd_set_config_index(dev, UVISOR_CONFIG_INDEX, 1); 184 if (err) { 185 printf("\n%s: failed to set configuration, err=%s\n", 186 devname, usbd_errstr(err)); 187 goto bad; 188 } 189 190 err = usbd_device2interface_handle(dev, UVISOR_IFACE_INDEX, &iface); 191 if (err) { 192 printf("\n%s: failed to get interface, err=%s\n", 193 devname, usbd_errstr(err)); 194 goto bad; 195 } 196 197 usbd_devinfo(dev, 0, devinfo); 198 USB_ATTACH_SETUP; 199 printf("%s: %s\n", devname, devinfo); 200 201 id = usbd_get_interface_descriptor(iface); 202 203 sc->sc_udev = dev; 204 sc->sc_iface = iface; 205 206 uca.ibufsize = UVISORIBUFSIZE; 207 uca.obufsize = UVISOROBUFSIZE; 208 uca.ibufsizepad = UVISORIBUFSIZE; 209 uca.opkthdrlen = 0; 210 uca.device = dev; 211 uca.iface = iface; 212 uca.methods = &uvisor_methods; 213 uca.arg = sc; 214 215 err = uvisor_init(sc, &coninfo); 216 if (err) { 217 printf("%s: init failed, %s\n", USBDEVNAME(sc->sc_dev), 218 usbd_errstr(err)); 219 goto bad; 220 } 221 222 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, 223 USBDEV(sc->sc_dev)); 224 225 sc->sc_numcon = UGETW(coninfo.num_ports); 226 if (sc->sc_numcon > UVISOR_MAX_CONN) 227 sc->sc_numcon = UVISOR_MAX_CONN; 228 229 /* Attach a ucom for each connection. */ 230 for (i = 0; i < sc->sc_numcon; ++i) { 231 switch (coninfo.connections[i].port_function_id) { 232 case UVISOR_FUNCTION_GENERIC: 233 uca.info = "Generic"; 234 break; 235 case UVISOR_FUNCTION_DEBUGGER: 236 uca.info = "Debugger"; 237 break; 238 case UVISOR_FUNCTION_HOTSYNC: 239 uca.info = "HotSync"; 240 break; 241 case UVISOR_FUNCTION_REMOTE_FILE_SYS: 242 uca.info = "Remote File System"; 243 break; 244 default: 245 uca.info = "unknown"; 246 break; 247 } 248 port = coninfo.connections[i].port; 249 uca.portno = port; 250 uca.bulkin = port | UE_DIR_IN; 251 uca.bulkout = port | UE_DIR_OUT; 252 /* Verify that endpoints exist. */ 253 for (hasin = hasout = j = 0; j < id->bNumEndpoints; j++) { 254 ed = usbd_interface2endpoint_descriptor(iface, j); 255 if (ed == NULL) 256 break; 257 if (UE_GET_ADDR(ed->bEndpointAddress) == port && 258 (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { 259 if (UE_GET_DIR(ed->bEndpointAddress) 260 == UE_DIR_IN) 261 hasin++; 262 else 263 hasout++; 264 } 265 } 266 if (hasin == 1 && hasout == 1) 267 sc->sc_subdevs[i] = config_found_sm(self, &uca, 268 ucomprint, ucomsubmatch); 269 else 270 printf("%s: no proper endpoints for port %d (%d,%d)\n", 271 USBDEVNAME(sc->sc_dev), port, hasin, hasout); 272 } 273 274 USB_ATTACH_SUCCESS_RETURN; 275 276 bad: 277 DPRINTF(("uvisor_attach: ATTACH ERROR\n")); 278 sc->sc_dying = 1; 279 USB_ATTACH_ERROR_RETURN; 280 } 281 282 int 283 uvisor_activate(device_ptr_t self, enum devact act) 284 { 285 struct uvisor_softc *sc = (struct uvisor_softc *)self; 286 int rv = 0; 287 int i; 288 289 switch (act) { 290 case DVACT_ACTIVATE: 291 return (EOPNOTSUPP); 292 break; 293 294 case DVACT_DEACTIVATE: 295 for (i = 0; i < sc->sc_numcon; i++) 296 if (sc->sc_subdevs[i] != NULL) 297 rv = config_deactivate(sc->sc_subdevs[i]); 298 sc->sc_dying = 1; 299 break; 300 } 301 return (rv); 302 } 303 304 int 305 uvisor_detach(device_ptr_t self, int flags) 306 { 307 struct uvisor_softc *sc = (struct uvisor_softc *)self; 308 int rv = 0; 309 int i; 310 311 DPRINTF(("uvisor_detach: sc=%p flags=%d\n", sc, flags)); 312 sc->sc_dying = 1; 313 for (i = 0; i < sc->sc_numcon; i++) { 314 if (sc->sc_subdevs[i] != NULL) { 315 rv |= config_detach(sc->sc_subdevs[i], flags); 316 sc->sc_subdevs[i] = NULL; 317 } 318 } 319 320 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, 321 USBDEV(sc->sc_dev)); 322 323 return (rv); 324 } 325 326 usbd_status 327 uvisor_init(struct uvisor_softc *sc, struct uvisor_connection_info *ci) 328 { 329 usbd_status err; 330 usb_device_request_t req; 331 int actlen; 332 uWord avail; 333 334 DPRINTF(("uvisor_init: getting connection info\n")); 335 req.bmRequestType = UT_READ_VENDOR_ENDPOINT; 336 req.bRequest = UVISOR_GET_CONNECTION_INFORMATION; 337 USETW(req.wValue, 0); 338 USETW(req.wIndex, 0); 339 USETW(req.wLength, UVISOR_CONNECTION_INFO_SIZE); 340 err = usbd_do_request_flags(sc->sc_udev, &req, ci, 341 USBD_SHORT_XFER_OK, &actlen); 342 if (err) 343 return (err); 344 345 DPRINTF(("uvisor_init: getting available bytes\n")); 346 req.bmRequestType = UT_READ_VENDOR_ENDPOINT; 347 req.bRequest = UVISOR_REQUEST_BYTES_AVAILABLE; 348 USETW(req.wValue, 0); 349 USETW(req.wIndex, 5); 350 USETW(req.wLength, sizeof avail); 351 err = usbd_do_request(sc->sc_udev, &req, &avail); 352 if (err) 353 return (err); 354 DPRINTF(("uvisor_init: avail=%d\n", UGETW(avail))); 355 356 DPRINTF(("uvisor_init: done\n")); 357 return (err); 358 } 359 360 void 361 uvisor_close(void *addr, int portno) 362 { 363 struct uvisor_softc *sc = addr; 364 usb_device_request_t req; 365 struct uvisor_connection_info coninfo; /* XXX ? */ 366 int actlen; 367 368 if (sc->sc_dying) 369 return; 370 371 req.bmRequestType = UT_READ_VENDOR_ENDPOINT; /* XXX read? */ 372 req.bRequest = UVISOR_CLOSE_NOTIFICATION; 373 USETW(req.wValue, 0); 374 USETW(req.wIndex, 0); 375 USETW(req.wLength, UVISOR_CONNECTION_INFO_SIZE); 376 (void)usbd_do_request_flags(sc->sc_udev, &req, &coninfo, 377 USBD_SHORT_XFER_OK, &actlen); 378 } 379