2 * Copyright © 2010 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 #include <IOKit/usb/USBspec.h>
26 #include <sys/param.h>
39 io_iterator_t iterator;
43 get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
45 CFTypeRef entry_as_string;
48 entry_as_string = IORegistryEntrySearchCFProperty (object,
52 kIORegistryIterateRecursively);
53 if (entry_as_string) {
54 got_string = CFStringGetCString(entry_as_string,
56 kCFStringEncodingASCII);
58 CFRelease(entry_as_string);
77 altos_list_start(void)
79 struct altos_list *list = calloc (sizeof (struct altos_list), 1);
80 CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice");
81 UInt32 vendor = 0xfffe, product = 0x000a;
82 CFNumberRef vendor_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor);
83 CFNumberRef product_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product);
84 io_iterator_t tdIterator;
87 CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBVendorID), vendor_ref);
88 CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBProductID), product_ref);
90 IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
92 CFRelease(vendor_ref);
93 CFRelease(product_ref);
98 altos_list_next(struct altos_list *list, struct altos_device *device)
101 char serial_string[128];
104 object = IOIteratorNext(list->iterator);
108 if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) &&
109 get_string (object, CFSTR("USB Product Name"), device->product, sizeof (device->product)) &&
110 get_string (object, CFSTR("USB Serial Number"), serial_string, sizeof (serial_string))) {
111 device->serial = atoi(serial_string);
118 altos_list_finish(struct altos_list *list)
120 IOObjectRelease (list->iterator);
125 #define USB_BUF_SIZE 64
129 unsigned char out_data[USB_BUF_SIZE];
131 unsigned char in_data[USB_BUF_SIZE];
137 altos_test(char *path)
144 fd = open(path, O_RDWR | O_NOCTTY);
149 if (ioctl(fd, TIOCEXCL, (char *) 0) < 0) {
155 n = tcgetattr(fd, &term);
163 term.c_cc[VTIME] = 1;
164 n = tcsetattr(fd, TCSAFLUSH, &term);
170 write(fd, "\n?\n", 3);
172 n = read(fd, buf, sizeof (buf));
185 altos_open(struct altos_device *device)
187 struct altos_file *file = calloc (sizeof (struct altos_file), 1);
194 file->fd = open(device->path, O_RDWR | O_NOCTTY);
196 perror(device->path);
200 ret = tcgetattr(file->fd, &term);
209 term.c_cc[VTIME] = 1;
210 ret = tcsetattr(file->fd, TCSAFLUSH, &term);
221 altos_close(struct altos_file *file)
228 altos_putchar(struct altos_file *file, char c)
232 if (file->out_used == USB_BUF_SIZE) {
233 ret = altos_flush(file);
237 file->out_data[file->out_used++] = c;
238 if (file->out_used == USB_BUF_SIZE)
239 return altos_flush(file);
244 altos_flush(struct altos_file *file)
246 while (file->out_used) {
249 ret = write (file->fd, file->out_data, file->out_used);
253 memmove(file->out_data, file->out_data + ret,
254 file->out_used - ret);
255 file->out_used -= ret;
261 altos_getchar(struct altos_file *file, int timeout)
263 while (file->in_read == file->in_used) {
267 ret = read(file->fd, file->in_data, USB_BUF_SIZE);
273 return file->in_data[file->in_read++];
276 #endif /* USE_DARWIN */
284 libusb_context *usb_context;
289 ret = libusb_init(&usb_context);
292 libusb_set_debug(usb_context, 3);
296 void altos_fini(void)
298 libusb_exit(usb_context);
302 static libusb_device **list;
303 static ssize_t num, current;
305 int altos_list_start(void)
310 num = libusb_get_device_list(usb_context, &list);
319 int altos_list_next(struct altos_device *device)
321 while (current < num) {
322 struct libusb_device_descriptor descriptor;
323 libusb_device *usb_device = list[current++];
325 if (libusb_get_device_descriptor(usb_device, &descriptor) == 0) {
326 if (descriptor.idVendor == 0xfffe)
328 libusb_device_handle *handle;
329 if (libusb_open(usb_device, &handle) == 0) {
330 char serial_number[256];
331 libusb_get_string_descriptor_ascii(handle, descriptor.iProduct,
333 sizeof(device->product));
334 libusb_get_string_descriptor_ascii(handle, descriptor.iSerialNumber,
336 sizeof (serial_number));
337 libusb_close(handle);
338 device->serial = atoi(serial_number);
339 device->device = usb_device;
348 void altos_list_finish(void)
351 libusb_free_device_list(list, 1);
356 #define USB_BUF_SIZE 64
359 struct libusb_device *device;
360 struct libusb_device_handle *handle;
365 unsigned char out_data[USB_BUF_SIZE];
367 unsigned char in_data[USB_BUF_SIZE];
373 altos_open(struct altos_device *device)
375 struct altos_file *file;
376 struct libusb_device_handle *handle;
377 if (libusb_open(device->device, &handle) == 0) {
380 ret = libusb_claim_interface(handle, 1);
383 libusb_close(handle);
387 ret = libusb_detach_kernel_driver(handle, 1);
390 libusb_close(handle);
395 file = calloc(sizeof (struct altos_file), 1);
396 file->device = libusb_ref_device(device->device);
397 file->handle = handle;
398 /* XXX should get these from the endpoint descriptors */
399 file->out_ep = 4 | LIBUSB_ENDPOINT_OUT;
401 file->in_ep = 5 | LIBUSB_ENDPOINT_IN;
410 altos_close(struct altos_file *file)
412 libusb_close(file->handle);
413 libusb_unref_device(file->device);
419 altos_putchar(struct altos_file *file, char c)
423 if (file->out_used == file->out_size) {
424 ret = altos_flush(file);
428 file->out_data[file->out_used++] = c;
429 if (file->out_used == file->out_size)
430 return altos_flush(file);
435 altos_flush(struct altos_file *file)
437 while (file->out_used) {
441 ret = libusb_bulk_transfer(file->handle,
450 memmove(file->out_data, file->out_data + transferred,
451 file->out_used - transferred);
452 file->out_used -= transferred;
458 altos_getchar(struct altos_file *file, int timeout)
460 while (file->in_read == file->in_used) {
465 ret = libusb_bulk_transfer(file->handle,
470 (unsigned int) timeout);
474 file->in_used = transferred;
476 return file->in_data[file->in_read++];
479 #endif /* USE_LIBUSB */