/* * si470x_usb_driver_disconnect - disconnect the device */ static void si470x_usb_driver_disconnect(struct usb_interface *intf) { struct si470x_device *radio = usb_get_intfdata(intf); mutex_lock(&radio->disconnect_lock); radio->disconnected = 1; cancel_delayed_work_sync(&radio->work); usb_set_intfdata(intf, NULL); if (radio->users == 0) { /* set led to disconnect state */ si470x_set_led_state(radio, BLINK_ORANGE_LED); video_unregister_device(radio->videodev); kfree(radio->buffer); kfree(radio); } mutex_unlock(&radio->disconnect_lock); }
static void si470x_usb_driver_disconnect(struct usb_interface *intf) { struct si470x_device *radio = usb_get_intfdata(intf); mutex_lock(&radio->lock); radio->disconnected = 1; usb_set_intfdata(intf, NULL); if (radio->users == 0) { /* */ si470x_set_led_state(radio, BLINK_ORANGE_LED); /* */ usb_free_urb(radio->int_in_urb); kfree(radio->int_in_buffer); video_unregister_device(radio->videodev); kfree(radio->buffer); mutex_unlock(&radio->lock); kfree(radio); } else { mutex_unlock(&radio->lock); } }
/* * si470x_usb_driver_probe - probe for the device */ static int si470x_usb_driver_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct si470x_device *radio; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; int i, int_end_size, retval = 0; unsigned char version_warning = 0; /* private data allocation and initialization */ radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); if (!radio) { retval = -ENOMEM; goto err_initial; } radio->usb_buf = kmalloc(MAX_REPORT_SIZE, GFP_KERNEL); if (radio->usb_buf == NULL) { retval = -ENOMEM; goto err_radio; } radio->usbdev = interface_to_usbdev(intf); radio->intf = intf; radio->band = 1; /* Default to 76 - 108 MHz */ mutex_init(&radio->lock); init_completion(&radio->completion); iface_desc = intf->cur_altsetting; /* Set up interrupt endpoint information. */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; if (usb_endpoint_is_int_in(endpoint)) radio->int_in_endpoint = endpoint; } if (!radio->int_in_endpoint) { dev_info(&intf->dev, "could not find interrupt in endpoint\n"); retval = -EIO; goto err_usbbuf; } int_end_size = le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize); radio->int_in_buffer = kmalloc(int_end_size, GFP_KERNEL); if (!radio->int_in_buffer) { dev_info(&intf->dev, "could not allocate int_in_buffer"); retval = -ENOMEM; goto err_usbbuf; } radio->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!radio->int_in_urb) { retval = -ENOMEM; goto err_intbuffer; } radio->v4l2_dev.release = si470x_usb_release; /* * The si470x SiLabs reference design uses the same USB IDs as * 'Thanko's Raremono' si4734 based receiver. So check here which we * have: attempt to read the device ID from the si470x: the lower 12 * bits should be 0x0242 for the si470x. * * We use this check to determine which device we are dealing with. */ if (id->idVendor == 0x10c4 && id->idProduct == 0x818a) { retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), HID_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 1, 2, radio->usb_buf, 3, 500); if (retval != 3 || (get_unaligned_be16(&radio->usb_buf[1]) & 0xfff) != 0x0242) { dev_info(&intf->dev, "this is not a si470x device.\n"); retval = -ENODEV; goto err_urb; } } retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); if (retval < 0) { dev_err(&intf->dev, "couldn't register v4l2_device\n"); goto err_urb; } v4l2_ctrl_handler_init(&radio->hdl, 2); v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 15, 1, 15); if (radio->hdl.error) { retval = radio->hdl.error; dev_err(&intf->dev, "couldn't register control\n"); goto err_dev; } radio->videodev = si470x_viddev_template; radio->videodev.ctrl_handler = &radio->hdl; radio->videodev.lock = &radio->lock; radio->videodev.v4l2_dev = &radio->v4l2_dev; radio->videodev.release = video_device_release_empty; video_set_drvdata(&radio->videodev, radio); /* get device and chip versions */ if (si470x_get_all_registers(radio) < 0) { retval = -EIO; goto err_ctrl; } dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", radio->registers[DEVICEID], radio->registers[SI_CHIPID]); if ((radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE) < RADIO_FW_VERSION) { dev_warn(&intf->dev, "This driver is known to work with firmware version %hu,\n", RADIO_FW_VERSION); dev_warn(&intf->dev, "but the device has firmware version %hu.\n", radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE); version_warning = 1; } /* get software and hardware versions */ if (si470x_get_scratch_page_versions(radio) < 0) { retval = -EIO; goto err_ctrl; } dev_info(&intf->dev, "software version %d, hardware version %d\n", radio->software_version, radio->hardware_version); if (radio->hardware_version < RADIO_HW_VERSION) { dev_warn(&intf->dev, "This driver is known to work with hardware version %hu,\n", RADIO_HW_VERSION); dev_warn(&intf->dev, "but the device has hardware version %hu.\n", radio->hardware_version); version_warning = 1; } /* give out version warning */ if (version_warning == 1) { dev_warn(&intf->dev, "If you have some trouble using this driver,\n"); dev_warn(&intf->dev, "please report to V4L ML at [email protected]\n"); } /* set led to connect state */ si470x_set_led_state(radio, BLINK_GREEN_LED); /* rds buffer allocation */ radio->buf_size = rds_buf * 3; radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); if (!radio->buffer) { retval = -EIO; goto err_ctrl; } /* rds buffer configuration */ radio->wr_index = 0; radio->rd_index = 0; init_waitqueue_head(&radio->read_queue); usb_set_intfdata(intf, radio); /* start radio */ retval = si470x_start_usb(radio); if (retval < 0) goto err_all; /* set initial frequency */ si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ /* register video device */ retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr); if (retval) { dev_err(&intf->dev, "Could not register video device\n"); goto err_all; } return 0; err_all: kfree(radio->buffer); err_ctrl: v4l2_ctrl_handler_free(&radio->hdl); err_dev: v4l2_device_unregister(&radio->v4l2_dev); err_urb: usb_free_urb(radio->int_in_urb); err_intbuffer: kfree(radio->int_in_buffer); err_usbbuf: kfree(radio->usb_buf); err_radio: kfree(radio); err_initial: return retval; }
/* * si470x_usb_driver_probe - probe for the device */ static int si470x_usb_driver_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct si470x_device *radio; int retval = 0; /* private data allocation and initialization */ radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); if (!radio) { retval = -ENOMEM; goto err_initial; } radio->users = 0; radio->disconnected = 0; radio->usbdev = interface_to_usbdev(intf); radio->intf = intf; mutex_init(&radio->disconnect_lock); mutex_init(&radio->lock); /* video device allocation and initialization */ radio->videodev = video_device_alloc(); if (!radio->videodev) { retval = -ENOMEM; goto err_radio; } memcpy(radio->videodev, &si470x_viddev_template, sizeof(si470x_viddev_template)); video_set_drvdata(radio->videodev, radio); /* show some infos about the specific si470x device */ if (si470x_get_all_registers(radio) < 0) { retval = -EIO; goto err_video; } printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", radio->registers[DEVICEID], radio->registers[CHIPID]); /* get software and hardware versions */ if (si470x_get_scratch_page_versions(radio) < 0) { retval = -EIO; goto err_video; } printk(KERN_INFO DRIVER_NAME ": software version %d, hardware version %d\n", radio->software_version, radio->hardware_version); /* check if device and firmware is current */ if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) < RADIO_SW_VERSION_CURRENT) { printk(KERN_WARNING DRIVER_NAME ": This driver is known to work with " "firmware version %hu,\n", RADIO_SW_VERSION_CURRENT); printk(KERN_WARNING DRIVER_NAME ": but the device has firmware version %hu.\n", radio->registers[CHIPID] & CHIPID_FIRMWARE); printk(KERN_WARNING DRIVER_NAME ": If you have some trouble using this driver,\n"); printk(KERN_WARNING DRIVER_NAME ": please report to V4L ML at " "[email protected]\n"); } /* set initial frequency */ si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ /* set led to connect state */ si470x_set_led_state(radio, BLINK_GREEN_LED); /* rds buffer allocation */ radio->buf_size = rds_buf * 3; radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); if (!radio->buffer) { retval = -EIO; goto err_video; } /* rds buffer configuration */ radio->wr_index = 0; radio->rd_index = 0; init_waitqueue_head(&radio->read_queue); /* prepare rds work function */ INIT_DELAYED_WORK(&radio->work, si470x_work); /* register video device */ retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); if (retval) { printk(KERN_WARNING DRIVER_NAME ": Could not register video device\n"); goto err_all; } usb_set_intfdata(intf, radio); return 0; err_all: kfree(radio->buffer); err_video: video_device_release(radio->videodev); err_radio: kfree(radio); err_initial: return retval; }
static int si470x_usb_driver_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct si470x_device *radio; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; int i, int_end_size, retval = 0; unsigned char version_warning = 0; /* */ radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); if (!radio) { retval = -ENOMEM; goto err_initial; } radio->users = 0; radio->disconnected = 0; radio->usbdev = interface_to_usbdev(intf); radio->intf = intf; mutex_init(&radio->lock); iface_desc = intf->cur_altsetting; /* */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) radio->int_in_endpoint = endpoint; } if (!radio->int_in_endpoint) { dev_info(&intf->dev, "could not find interrupt in endpoint\n"); retval = -EIO; goto err_radio; } int_end_size = le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize); radio->int_in_buffer = kmalloc(int_end_size, GFP_KERNEL); if (!radio->int_in_buffer) { dev_info(&intf->dev, "could not allocate int_in_buffer"); retval = -ENOMEM; goto err_radio; } radio->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!radio->int_in_urb) { dev_info(&intf->dev, "could not allocate int_in_urb"); retval = -ENOMEM; goto err_intbuffer; } /* */ radio->videodev = video_device_alloc(); if (!radio->videodev) { retval = -ENOMEM; goto err_urb; } memcpy(radio->videodev, &si470x_viddev_template, sizeof(si470x_viddev_template)); video_set_drvdata(radio->videodev, radio); /* */ if (si470x_get_all_registers(radio) < 0) { retval = -EIO; goto err_video; } dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", radio->registers[DEVICEID], radio->registers[CHIPID]); if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) < RADIO_FW_VERSION) { dev_warn(&intf->dev, "This driver is known to work with " "firmware version %hu,\n", RADIO_FW_VERSION); dev_warn(&intf->dev, "but the device has firmware version %hu.\n", radio->registers[CHIPID] & CHIPID_FIRMWARE); version_warning = 1; } /* */ if (si470x_get_scratch_page_versions(radio) < 0) { retval = -EIO; goto err_video; } dev_info(&intf->dev, "software version %d, hardware version %d\n", radio->software_version, radio->hardware_version); if (radio->software_version < RADIO_SW_VERSION) { dev_warn(&intf->dev, "This driver is known to work with " "software version %hu,\n", RADIO_SW_VERSION); dev_warn(&intf->dev, "but the device has software version %hu.\n", radio->software_version); version_warning = 1; } if (radio->hardware_version < RADIO_HW_VERSION) { dev_warn(&intf->dev, "This driver is known to work with " "hardware version %hu,\n", RADIO_HW_VERSION); dev_warn(&intf->dev, "but the device has hardware version %hu.\n", radio->hardware_version); version_warning = 1; } /* */ if (version_warning == 1) { dev_warn(&intf->dev, "If you have some trouble using this driver,\n"); dev_warn(&intf->dev, "please report to V4L ML at " "[email protected]\n"); } /* */ si470x_set_freq(radio, 87.5 * FREQ_MUL); /* */ /* */ si470x_set_led_state(radio, BLINK_GREEN_LED); /* */ radio->buf_size = rds_buf * 3; radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); if (!radio->buffer) { retval = -EIO; goto err_video; } /* */ radio->wr_index = 0; radio->rd_index = 0; init_waitqueue_head(&radio->read_queue); /* */ retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); if (retval) { dev_warn(&intf->dev, "Could not register video device\n"); goto err_all; } usb_set_intfdata(intf, radio); return 0; err_all: kfree(radio->buffer); err_video: video_device_release(radio->videodev); err_urb: usb_free_urb(radio->int_in_urb); err_intbuffer: kfree(radio->int_in_buffer); err_radio: kfree(radio); err_initial: return retval; }