Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Jun 2002 07:46:45 -0400 (EDT)
From:      Bryan Liesner <bleez@bellatlantic.net>
To:        freebsd-stable@freebsd.org
Subject:   D-Link DSB-R100 and the ufm driver
Message-ID:  <20020625073327.D708-200000@gravy.kishka.net>

index | next in thread | raw e-mail

[-- Attachment #1 --]

I just finished compiling ufm support into the kernel, and grabbed
NetBSD's dsbr100 port to control my DSB-R100 device.  With a little
tweaking I got the port to compile, but when I run it I get
inappropriate ioctl errors for USB_GET_DEVICEINFO and
USB_DO_REQUEST.

I think the device node may be wrong but here's what I have:
crw-r--r--  1 root  operator  200,   0 Jun 25 00:55 /dev/ufm0
dmesg shows:
ufm0: GemTek Corp USB FM Radio, rev 1.00/4.10, addr 2

I'm definitely not a USB guru, and need a bit of help getting this
thing to work.  The source is small enough, so it's attached.

Thanks!

==========================================================
= Bryan D. Liesner         LeezSoft Communications, Inc. =
=                          A subsidiary of LeezSoft Inc. =
= bleez@bellatlantic.net   Home of the Gipper            =
==========================================================

[-- Attachment #2 --]
/*
 * Copyright (c) 2000 Lennart Augustsson <augustss@netbsd.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/* 
 * A driver for the D-Link DSB-R100 USB radio.  The radio plugs
 * into both the USB and an analog audio input.  The USB part
 * only deals with initialisation and frequency setting, the
 * audio data has to be handled by a sound driver.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <err.h>
#include <dev/usb/usb.h>
#include <sys/ioctl.h>

#define VENDOR 0x04b4
#define PRODUCT 0x1002

int debug = 0;
int verbose = 0;
int autotune = 1;

int delta = 50;
int minstep = 10;

int sleeptime = 300000;

#define DEFAULT_DEV "/dev/ufm0"

int
radio_req(int f, int ureq, int value, int index)
{
	struct usb_ctl_request req;
	u_char data;
	int r;

	req.ucr_request.bmRequestType = UT_READ_VENDOR_DEVICE;
	req.ucr_request.bRequest = ureq;
	USETW(req.ucr_request.wValue, value);
	USETW(req.ucr_request.wIndex, index);
	USETW(req.ucr_request.wLength, 1);
	req.ucr_data = &data;
	req.ucr_flags = 0; //USBD_SHORT_XFER_OK;
	r = ioctl(f, USB_DO_REQUEST, &req);
	if (r < 0)
		err(1, "USB_DO_REQUEST");
	if (debug > 1)
		printf("%#x %#x %#x %#x len=%d\n", ureq, UT_READ_VENDOR_DEVICE,
		       value, index, req.ucr_actlen);
	return !(data & 1);
}

void
radio_start(int f)
{
	radio_req(f, 0x00, 0x0000, 0x00c7);
	radio_req(f, 0x02, 0x0001, 0x0000);
}

void
radio_stop(int f)
{
	radio_req(f, 0x00, 0x0016, 0x001c);
	radio_req(f, 0x02, 0x0000, 0x0000);
}

void
radio_setfreq(int f, int freq)
{
	if (debug > 1) printf("setfreq=%d\n", freq);
	freq = freq * 80 / 1000 + 856;
	if (debug > 2) printf("freq = %#x\n", freq);
	radio_req(f, 0x01, (freq >> 8) & 0xff, freq & 0xff);
	radio_req(f, 0x00, 0x0096, 0x00b7);
	radio_req(f, 0x00, 0x0000, 0x0024);
}

int
radio_status(int f)
{
	return radio_req(f, 0x00, 0x0000, 0x0024);
}

void
usage(void)
{
	extern char *__progname;

	fprintf(stderr, "Usage: %s [-f device] [-v] start\n", __progname);
	fprintf(stderr, "       %s [-f device] [-v] stop\n", __progname);
	fprintf(stderr, "       %s [-f device] [-v] status\n", __progname);
	fprintf(stderr, "       %s [-f device] [-v] [-n] <freq>\n", __progname);
	fprintf(stderr, "       %s [-f device] [-v] [-n] scan <lo> <hi>\n", __progname);
	fprintf(stderr, "       %s [-f device] [-v] [-n] search <lo> <hi>\n", __progname);
	exit(1);
}

void
setfreq(int f, int fr)
{
	int s, slo, shi;
	int nacc, acc;

	if (!autotune) {
		radio_setfreq(f, fr);
		usleep(sleeptime);
		return;
	}

	slo = fr - 4 * delta / 2;
	shi = fr + 4 * delta / 2;
	acc = fr;
	nacc = 1;
	for (s = slo; s <= shi; s += minstep) {
		radio_setfreq(f, s);
		usleep(sleeptime);
		if(debug)
			printf("try freq=%d stereo=%d\n", s, radio_status(f));
		if (radio_status(f)) {
			acc += s;
			nacc++;
		}
	}
	acc /= nacc;
	if (debug)
		printf("freq=%d\n", acc);
	radio_setfreq(f, acc);
	usleep(sleeptime);
}

void
scan(int f, int lo, int hi, int cont)
{
	int fr;

	for (;;) {
		for (fr = lo; fr < hi; fr += delta) {
			if (verbose)
				printf("\r%.2f", fr / 1000.0), fflush(stdout);
			radio_setfreq(f, fr);
			usleep(sleeptime);
			if (radio_status(f)) {
				setfreq(f, fr + delta);
				if (verbose)
					printf("\n");
				else
					printf("%.2f\n", fr / 1000.0);
				if (!cont)
					return;
				sleep(5);
			}
			fr += 3 * delta;
		}
	}
}

int
main(int argc, char **argv)
{
	char *dev = 0;
	char devbuf[1024];
	int f, ch;
	double freq, lo, hi;
	struct usb_device_info di;

	while ((ch = getopt(argc, argv, "df:nv")) != -1) {
		switch(ch) {
		case 'd':
			debug++;
			break;
		case 'f':
			dev = optarg;
			break;
		case 'n':
			autotune = 0;
			break;
		case 'v':
			verbose++;
			break;
		case '?':
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;
	if (!dev)
		dev = DEFAULT_DEV;

	f = open(dev, O_RDWR);
	if (f < 0) {
		if (dev[0] != '/') {
			sprintf(devbuf, "/dev/%s", dev);
			f = open(devbuf, O_RDWR);
		} else
			strcpy(devbuf, dev);
		if (f < 0) {
			if (!strchr(devbuf, '.')) {
				strcat(devbuf, ".00");
				f = open(devbuf, O_RDWR);
			}
		}
	}
	if (f < 0)
		err(1, "%s", dev);


	if (ioctl(f, USB_GET_DEVICEINFO, &di) != 0)
		err(1, "USB_GET_DEVICEINFO");
	if (verbose > 1) {
		printf("Product: %s\n", di.udi_product);
		printf("Vendor:  %s\n", di.udi_vendor);
	}
	if (di.udi_vendorNo != VENDOR || di.udi_productNo != PRODUCT)
		errx(1, "The device is not a DSB-R100 radio\n");

	if (argc == 1 && strcmp(argv[0], "start") == 0)
		radio_start(f);
	else if (argc == 1 && strcmp(argv[0], "stop") == 0)
		radio_stop(f);
	else if (argc == 1 && sscanf(argv[0], "%lf", &freq) == 1) {
		setfreq(f, (int)(freq * 1000));
		if(verbose)
			printf("%s\n", radio_status(f) ? "stereo" : "mono");
	} else if (argc == 3 && strcmp(argv[0], "scan") == 0 &&
		 sscanf(argv[1], "%lf", &lo) == 1 &&
		 sscanf(argv[2], "%lf", &hi) == 1) {
		scan(f, lo * 1000, hi * 1000, 1);
	} else if (argc == 3 && strcmp(argv[0], "search") == 0 &&
		 sscanf(argv[1], "%lf", &lo) == 1 &&
		 sscanf(argv[2], "%lf", &hi) == 1) {
		scan(f, lo * 1000, hi * 1000, 0);
	} else if (argc == 1 && strcmp(argv[0], "status") == 0)
		printf("%s\n", radio_status(f) ? "stereo" : "mono");
	else
		usage();

	close(f);

	exit(0);
}
home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020625073327.D708-200000>