dvb-usb-init.c 5.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * DVB USB library - provides a generic interface for a DVB USB device driver.
 *
 * dvb-usb-init.c
 *
 * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
 *
 *	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.
 *
 * see Documentation/dvb/README.dvb-usb for more information
 */
#include "dvb-usb-common.h"

/* debug */
int dvb_usb_debug;
module_param_named(debug,dvb_usb_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." DVB_USB_DEBUG_STATUS);

21 22 23 24
int dvb_usb_disable_rc_polling;
module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644);
MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0).");

25
/* general initialization functions */
26
static int dvb_usb_exit(struct dvb_usb_device *d)
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
{
	deb_info("state before exiting everything: %x\n",d->state);
	dvb_usb_remote_exit(d);
	dvb_usb_fe_exit(d);
	dvb_usb_i2c_exit(d);
	dvb_usb_dvb_exit(d);
	dvb_usb_urb_exit(d);
	deb_info("state should be zero now: %x\n",d->state);
	d->state = DVB_USB_STATE_INIT;
	kfree(d->priv);
	kfree(d);
	return 0;
}

static int dvb_usb_init(struct dvb_usb_device *d)
{
	int ret = 0;

	sema_init(&d->usb_sem, 1);
	sema_init(&d->i2c_sem, 1);

	d->state = DVB_USB_STATE_INIT;

50
/* check the capabilities and set appropriate variables */
51 52 53

/* speed - when running at FULL speed we need a HW PID filter */
	if (d->udev->speed == USB_SPEED_FULL && !(d->props.caps & DVB_USB_HAS_PID_FILTER)) {
54
		err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
55 56 57 58 59
		return -ENODEV;
	}

	if ((d->udev->speed == USB_SPEED_FULL && d->props.caps & DVB_USB_HAS_PID_FILTER) ||
		(d->props.caps & DVB_USB_NEED_PID_FILTERING)) {
60
		info("will use the device's hardware PID filter (table count: %d).",d->props.pid_filter_count);
61 62 63
		d->pid_filtering = 1;
		d->max_feed_count = d->props.pid_filter_count;
	} else {
64
		info("will pass the complete MPEG2 transport stream to the software demuxer.");
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
		d->pid_filtering = 0;
		d->max_feed_count = 255;
	}

	if (d->props.power_ctrl)
		d->props.power_ctrl(d,1);

	if ((ret = dvb_usb_urb_init(d)) ||
		(ret = dvb_usb_dvb_init(d)) ||
		(ret = dvb_usb_i2c_init(d)) ||
		(ret = dvb_usb_fe_init(d))) {
		dvb_usb_exit(d);
		return ret;
	}

	if ((ret = dvb_usb_remote_init(d)))
		err("could not initialize remote control.");

	if (d->props.power_ctrl)
		d->props.power_ctrl(d,0);

	return 0;
}

/* determine the name and the state of the just found USB device */
static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_properties *props, int *cold)
{
	int i,j;
	struct dvb_usb_device_description *desc = NULL;
	*cold = -1;

	for (i = 0; i < props->num_device_descs; i++) {

		for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) {
			deb_info("check for cold %x %x\n",props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
			if (props->devices[i].cold_ids[j]->idVendor  == le16_to_cpu(udev->descriptor.idVendor) &&
				props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
				*cold = 1;
				desc = &props->devices[i];
				break;
			}
		}

		if (desc != NULL)
			break;

		for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) {
			deb_info("check for warm %x %x\n",props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
			if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
				props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
				*cold = 0;
				desc = &props->devices[i];
				break;
			}
		}
	}

	if (desc != NULL && props->identify_state != NULL)
		props->identify_state(udev,props,&desc,cold);

	return desc;
}

/*
 * USB
 */
131 132 133

int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
		*props, struct module *owner,struct dvb_usb_device **du)
134 135 136 137 138 139 140
{
	struct usb_device *udev = interface_to_usbdev(intf);
	struct dvb_usb_device *d = NULL;
	struct dvb_usb_device_description *desc = NULL;

	int ret = -ENOMEM,cold=0;

141 142 143
	if (du != NULL)
		*du = NULL;

144 145 146 147 148 149 150
	if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
		deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
		return -ENODEV;
	}

	if (cold) {
		info("found a '%s' in cold state, will try to load a firmware",desc->name);
151 152
		ret = dvb_usb_download_firmware(udev,props);
		if (!props->no_reconnect)
153
			return ret;
154 155 156
	}

	info("found a '%s' in warm state.",desc->name);
P
 
Panagiotis Issaris 已提交
157
		d = kzalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
158 159 160 161 162 163 164 165 166 167 168
	if (d == NULL) {
		err("no memory for 'struct dvb_usb_device'");
		return ret;
	}

	d->udev = udev;
	memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
	d->desc = desc;
	d->owner = owner;

	if (d->props.size_of_priv > 0) {
P
 
Panagiotis Issaris 已提交
169
			d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL);
170 171 172 173
		if (d->priv == NULL) {
			err("no memory for priv in 'struct dvb_usb_device'");
			kfree(d);
			return -ENOMEM;
174
		}
175
	}
176

177
	usb_set_intfdata(intf, d);
178

179 180
	if (du != NULL)
		*du = d;
181

182
	ret = dvb_usb_init(d);
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210

	if (ret == 0)
		info("%s successfully initialized and connected.",desc->name);
	else
		info("%s error while loading driver (%d)",desc->name,ret);
	return ret;
}
EXPORT_SYMBOL(dvb_usb_device_init);

void dvb_usb_device_exit(struct usb_interface *intf)
{
	struct dvb_usb_device *d = usb_get_intfdata(intf);
	const char *name = "generic DVB-USB module";

	usb_set_intfdata(intf,NULL);
	if (d != NULL && d->desc != NULL) {
		name = d->desc->name;
		dvb_usb_exit(d);
	}
	info("%s successfully deinitialized and disconnected.",name);

}
EXPORT_SYMBOL(dvb_usb_device_exit);

MODULE_VERSION("0.3");
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices");
MODULE_LICENSE("GPL");