diff options
Diffstat (limited to 'ao-view/aoview_dev.c')
| -rw-r--r-- | ao-view/aoview_dev.c | 208 | 
1 files changed, 208 insertions, 0 deletions
| diff --git a/ao-view/aoview_dev.c b/ao-view/aoview_dev.c new file mode 100644 index 00000000..9b8cc19e --- /dev/null +++ b/ao-view/aoview_dev.c @@ -0,0 +1,208 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" +#include <ctype.h> +#include <dirent.h> + +static char * +load_string(char *dir, char *file) +{ +	char	*full = aoview_fullname(dir, file); +	char	line[4096]; +	char	*r; +	FILE	*f; +	int	rlen; + +	f = fopen(full, "r"); +	free(full); +	if (!f) +		return NULL; +	r = fgets(line, sizeof (line), f); +	fclose(f); +	if (!r) +		return NULL; +	rlen = strlen(r); +	if (r[rlen-1] == '\n') +		r[rlen-1] = '\0'; +	return strdup(r); +} + +static int +load_hex(char *dir, char *file) +{ +	char	*line; +	char	*end; +	long	i; + +	line = load_string(dir, file); +	if (!line) +		return -1; +	i = strtol(line, &end, 16); +	free(line); +	if (end == line) +		return -1; +	return i; +} + +static int +dir_filter_tty_colon(const struct dirent *d) +{ +	return strncmp(d->d_name, "tty:", 4) == 0; +} + +static int +dir_filter_tty(const struct dirent *d) +{ +	return strncmp(d->d_name, "tty", 3) == 0; +} + +static char * +usb_tty(char *sys) +{ +	char *base; +	int num_configs; +	int config; +	struct dirent **namelist; +	int interface; +	int num_interfaces; +	char endpoint_base[20]; +	char *endpoint_full; +	char *tty_dir; +	int ntty; +	char *tty; + +	base = aoview_basename(sys); +	num_configs = load_hex(sys, "bNumConfigurations"); +	num_interfaces = load_hex(sys, "bNumInterfaces"); +	for (config = 1; config <= num_configs; config++) { +		for (interface = 0; interface < num_interfaces; interface++) { +			sprintf(endpoint_base, "%s:%d.%d", +				base, config, interface); +			endpoint_full = aoview_fullname(sys, endpoint_base); + +			/* Check for tty:ttyACMx style names +			 */ +			ntty = scandir(endpoint_full, &namelist, +				       dir_filter_tty_colon, +				       alphasort); +			if (ntty > 0) { +				free(endpoint_full); +				tty = aoview_fullname("/dev", namelist[0]->d_name + 4); +				free(namelist); +				return tty; +			} + +			/* Check for tty/ttyACMx style names +			 */ +			tty_dir = aoview_fullname(endpoint_full, "tty"); +			free(endpoint_full); +			ntty = scandir(tty_dir, &namelist, +				       dir_filter_tty, +				       alphasort); +			free (tty_dir); +			if (ntty > 0) { +				tty = aoview_fullname("/dev", namelist[0]->d_name); +				free(namelist); +				return tty; +			} +		} +	} +	return NULL; +} + +static struct usbdev * +usb_scan_device(char *sys) +{ +	struct usbdev *usbdev; + +	usbdev = calloc(1, sizeof (struct usbdev)); +	if (!usbdev) +		return NULL; +	usbdev->sys = strdup(sys); +	usbdev->manufacturer = load_string(sys, "manufacturer"); +	usbdev->product = load_string(sys, "product"); +	usbdev->serial = load_string(sys, "serial"); +	usbdev->idProduct = load_hex(sys, "idProduct"); +	usbdev->idVendor = load_hex(sys, "idVendor"); +	usbdev->tty = usb_tty(sys); +	return usbdev; +} + +void +aoview_usbdev_free(struct usbdev *usbdev) +{ +	free(usbdev->sys); +	free(usbdev->manufacturer); +	free(usbdev->product); +	free(usbdev->serial); +	free(usbdev->tty); +	free(usbdev); +} + +#define USB_DEVICES	"/sys/bus/usb/devices" + +static int +dir_filter_dev(const struct dirent *d) +{ +	const char	*n = d->d_name; +	char	c; + +	while ((c = *n++)) { +		if (isdigit(c)) +			continue; +		if (c == '-') +			continue; +		if (c == '.' && n != d->d_name + 1) +			continue; +		return 0; +	} +	return 1; +} + +int +aoview_usb_scan(struct usbdev ***devs_ret) +{ +	int		n; +	int		ndev = 0; +	int		e; +	struct dirent	**ents; +	char		*dir; +	struct usbdev	**devs = NULL; +	struct usbdev	*dev; + +	n = scandir (USB_DEVICES, &ents, +		     dir_filter_dev, +		     alphasort); +	if (!n) +		return 0; +	for (e = 0; e < n; e++) { +		dir = aoview_fullname(USB_DEVICES, ents[e]->d_name); +		dev = usb_scan_device(dir); +		free(dir); +		if (dev->idVendor == 0xfffe && dev->tty) { +			if (devs) +				devs = realloc(devs, ndev + 1 * sizeof (struct usbdev *)); +			else +				devs = malloc (sizeof (struct usbdev *)); +			devs[ndev++] = dev; +		} +	} +	free(ents); +	*devs_ret = devs; +	return ndev; +} | 
