.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * DVB USB library - provides a generic interface for a DVB USB device driver. |
---|
3 | 4 | * |
---|
.. | .. |
---|
5 | 6 | * |
---|
6 | 7 | * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de) |
---|
7 | 8 | * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify it |
---|
9 | | - * under the terms of the GNU General Public License as published by the Free |
---|
10 | | - * Software Foundation, version 2. |
---|
11 | | - * |
---|
12 | | - * see Documentation/media/dvb-drivers/dvb-usb.rst for more information |
---|
| 9 | + * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information |
---|
13 | 10 | */ |
---|
14 | 11 | #include "dvb-usb-common.h" |
---|
15 | 12 | |
---|
.. | .. |
---|
104 | 101 | |
---|
105 | 102 | /* |
---|
106 | 103 | * when reloading the driver w/o replugging the device |
---|
107 | | - * sometimes a timeout occures, this helps |
---|
| 104 | + * sometimes a timeout occurs, this helps |
---|
108 | 105 | */ |
---|
109 | 106 | if (d->props.generic_bulk_ctrl_endpoint != 0) { |
---|
110 | 107 | usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); |
---|
.. | .. |
---|
145 | 142 | dvb_usb_i2c_exit(d); |
---|
146 | 143 | deb_info("state should be zero now: %x\n", d->state); |
---|
147 | 144 | d->state = DVB_USB_STATE_INIT; |
---|
| 145 | + |
---|
| 146 | + if (d->priv != NULL && d->props.priv_destroy != NULL) |
---|
| 147 | + d->props.priv_destroy(d); |
---|
| 148 | + |
---|
148 | 149 | kfree(d->priv); |
---|
149 | 150 | kfree(d); |
---|
150 | 151 | return 0; |
---|
.. | .. |
---|
166 | 167 | err("no memory for priv in 'struct dvb_usb_device'"); |
---|
167 | 168 | return -ENOMEM; |
---|
168 | 169 | } |
---|
| 170 | + |
---|
| 171 | + if (d->props.priv_init != NULL) { |
---|
| 172 | + ret = d->props.priv_init(d); |
---|
| 173 | + if (ret != 0) |
---|
| 174 | + goto err_priv_init; |
---|
| 175 | + } |
---|
169 | 176 | } |
---|
170 | 177 | |
---|
171 | 178 | /* check the capabilities and set appropriate variables */ |
---|
172 | 179 | dvb_usb_device_power_ctrl(d, 1); |
---|
173 | 180 | |
---|
174 | | - if ((ret = dvb_usb_i2c_init(d)) || |
---|
175 | | - (ret = dvb_usb_adapter_init(d, adapter_nums))) { |
---|
176 | | - dvb_usb_exit(d); |
---|
177 | | - return ret; |
---|
178 | | - } |
---|
| 181 | + ret = dvb_usb_i2c_init(d); |
---|
| 182 | + if (ret) |
---|
| 183 | + goto err_i2c_init; |
---|
| 184 | + ret = dvb_usb_adapter_init(d, adapter_nums); |
---|
| 185 | + if (ret) |
---|
| 186 | + goto err_adapter_init; |
---|
179 | 187 | |
---|
180 | 188 | if ((ret = dvb_usb_remote_init(d))) |
---|
181 | 189 | err("could not initialize remote control."); |
---|
.. | .. |
---|
183 | 191 | dvb_usb_device_power_ctrl(d, 0); |
---|
184 | 192 | |
---|
185 | 193 | return 0; |
---|
| 194 | + |
---|
| 195 | +err_adapter_init: |
---|
| 196 | + dvb_usb_adapter_exit(d); |
---|
| 197 | + dvb_usb_i2c_exit(d); |
---|
| 198 | +err_i2c_init: |
---|
| 199 | + if (d->priv && d->props.priv_destroy) |
---|
| 200 | + d->props.priv_destroy(d); |
---|
| 201 | +err_priv_init: |
---|
| 202 | + kfree(d->priv); |
---|
| 203 | + d->priv = NULL; |
---|
| 204 | + return ret; |
---|
186 | 205 | } |
---|
187 | 206 | |
---|
188 | 207 | /* determine the name and the state of the just found USB device */ |
---|
189 | | -static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold) |
---|
| 208 | +static const struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, const struct dvb_usb_device_properties *props, int *cold) |
---|
190 | 209 | { |
---|
191 | 210 | int i, j; |
---|
192 | | - struct dvb_usb_device_description *desc = NULL; |
---|
| 211 | + const struct dvb_usb_device_description *desc = NULL; |
---|
193 | 212 | |
---|
194 | 213 | *cold = -1; |
---|
195 | 214 | |
---|
.. | .. |
---|
244 | 263 | * USB |
---|
245 | 264 | */ |
---|
246 | 265 | int dvb_usb_device_init(struct usb_interface *intf, |
---|
247 | | - struct dvb_usb_device_properties *props, |
---|
| 266 | + const struct dvb_usb_device_properties *props, |
---|
248 | 267 | struct module *owner, struct dvb_usb_device **du, |
---|
249 | 268 | short *adapter_nums) |
---|
250 | 269 | { |
---|
251 | 270 | struct usb_device *udev = interface_to_usbdev(intf); |
---|
252 | 271 | struct dvb_usb_device *d = NULL; |
---|
253 | | - struct dvb_usb_device_description *desc = NULL; |
---|
| 272 | + const struct dvb_usb_device_description *desc = NULL; |
---|
254 | 273 | |
---|
255 | 274 | int ret = -ENOMEM, cold = 0; |
---|
256 | 275 | |
---|
257 | 276 | if (du != NULL) |
---|
258 | 277 | *du = NULL; |
---|
259 | 278 | |
---|
260 | | - if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) { |
---|
| 279 | + d = kzalloc(sizeof(*d), GFP_KERNEL); |
---|
| 280 | + if (!d) { |
---|
| 281 | + err("no memory for 'struct dvb_usb_device'"); |
---|
| 282 | + return -ENOMEM; |
---|
| 283 | + } |
---|
| 284 | + |
---|
| 285 | + memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); |
---|
| 286 | + |
---|
| 287 | + desc = dvb_usb_find_device(udev, &d->props, &cold); |
---|
| 288 | + if (!desc) { |
---|
261 | 289 | deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); |
---|
262 | | - return -ENODEV; |
---|
| 290 | + ret = -ENODEV; |
---|
| 291 | + goto error; |
---|
263 | 292 | } |
---|
264 | 293 | |
---|
265 | 294 | if (cold) { |
---|
266 | 295 | info("found a '%s' in cold state, will try to load a firmware", desc->name); |
---|
267 | 296 | ret = dvb_usb_download_firmware(udev, props); |
---|
268 | 297 | if (!props->no_reconnect || ret != 0) |
---|
269 | | - return ret; |
---|
| 298 | + goto error; |
---|
270 | 299 | } |
---|
271 | 300 | |
---|
272 | 301 | info("found a '%s' in warm state.", desc->name); |
---|
273 | | - d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); |
---|
274 | | - if (d == NULL) { |
---|
275 | | - err("no memory for 'struct dvb_usb_device'"); |
---|
276 | | - return -ENOMEM; |
---|
277 | | - } |
---|
278 | | - |
---|
279 | 302 | d->udev = udev; |
---|
280 | | - memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); |
---|
281 | 303 | d->desc = desc; |
---|
282 | 304 | d->owner = owner; |
---|
283 | 305 | |
---|
284 | 306 | usb_set_intfdata(intf, d); |
---|
285 | 307 | |
---|
286 | | - if (du != NULL) |
---|
| 308 | + ret = dvb_usb_init(d, adapter_nums); |
---|
| 309 | + if (ret) { |
---|
| 310 | + info("%s error while loading driver (%d)", desc->name, ret); |
---|
| 311 | + goto error; |
---|
| 312 | + } |
---|
| 313 | + |
---|
| 314 | + if (du) |
---|
287 | 315 | *du = d; |
---|
288 | 316 | |
---|
289 | | - ret = dvb_usb_init(d, adapter_nums); |
---|
| 317 | + info("%s successfully initialized and connected.", desc->name); |
---|
| 318 | + return 0; |
---|
290 | 319 | |
---|
291 | | - if (ret == 0) |
---|
292 | | - info("%s successfully initialized and connected.", desc->name); |
---|
293 | | - else |
---|
294 | | - info("%s error while loading driver (%d)", desc->name, ret); |
---|
| 320 | + error: |
---|
| 321 | + usb_set_intfdata(intf, NULL); |
---|
| 322 | + kfree(d); |
---|
295 | 323 | return ret; |
---|
296 | 324 | } |
---|
297 | 325 | EXPORT_SYMBOL(dvb_usb_device_init); |
---|