core-cdev.c revision 385ab5bcd4be586dffdba550b310308d89eade71
1c781c06d119d04601727f2fbc30151e6760d536dKristian Høgsberg/* 2c781c06d119d04601727f2fbc30151e6760d536dKristian Høgsberg * Char device for device raw access 319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * 4c781c06d119d04601727f2fbc30151e6760d536dKristian Høgsberg * Copyright (C) 2005-2007 Kristian Hoegsberg <krh@bitplanet.net> 519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * 619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * This program is free software; you can redistribute it and/or modify 719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * it under the terms of the GNU General Public License as published by 819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * the Free Software Foundation; either version 2 of the License, or 919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * (at your option) any later version. 1019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * 1119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * This program is distributed in the hope that it will be useful, 1219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * but WITHOUT ANY WARRANTY; without even the implied warranty of 1319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * GNU General Public License for more details. 1519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * 1619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * You should have received a copy of the GNU General Public License 1719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * along with this program; if not, write to the Free Software Foundation, 1819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 1919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg */ 2019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 21be5bbd6756b44602a3f281af05c2f416fa9bd1c6Stefan Richter#include <linux/compat.h> 22be5bbd6756b44602a3f281af05c2f416fa9bd1c6Stefan Richter#include <linux/delay.h> 23be5bbd6756b44602a3f281af05c2f416fa9bd1c6Stefan Richter#include <linux/device.h> 24be5bbd6756b44602a3f281af05c2f416fa9bd1c6Stefan Richter#include <linux/errno.h> 2577c9a5daa9c4d9b37812c9c69c7bcbb3f9399c3cStefan Richter#include <linux/firewire.h> 26be5bbd6756b44602a3f281af05c2f416fa9bd1c6Stefan Richter#include <linux/firewire-cdev.h> 27be5bbd6756b44602a3f281af05c2f416fa9bd1c6Stefan Richter#include <linux/idr.h> 284a9bde9b8ab55a2bb51b57cad215a97bcf80bae2Stefan Richter#include <linux/irqflags.h> 29b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter#include <linux/jiffies.h> 3019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg#include <linux/kernel.h> 31fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter#include <linux/kref.h> 32be5bbd6756b44602a3f281af05c2f416fa9bd1c6Stefan Richter#include <linux/mm.h> 33be5bbd6756b44602a3f281af05c2f416fa9bd1c6Stefan Richter#include <linux/module.h> 34d67cfb9613f373d76daa2c8d209629601424ca12Stefan Richter#include <linux/mutex.h> 3519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg#include <linux/poll.h> 36a99bbaf5ee6bad1aca0c88ea65ec6e5373e86184Alexey Dobriyan#include <linux/sched.h> 37cf417e5494582453c033d8cac9e1352e74215435Jay Fenlason#include <linux/spinlock.h> 38281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter#include <linux/string.h> 39be5bbd6756b44602a3f281af05c2f416fa9bd1c6Stefan Richter#include <linux/time.h> 40e034d242593f12533c11742ce38c245a33e57dc7Stefan Richter#include <linux/uaccess.h> 41be5bbd6756b44602a3f281af05c2f416fa9bd1c6Stefan Richter#include <linux/vmalloc.h> 42be5bbd6756b44602a3f281af05c2f416fa9bd1c6Stefan Richter#include <linux/wait.h> 43b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter#include <linux/workqueue.h> 44be5bbd6756b44602a3f281af05c2f416fa9bd1c6Stefan Richter 45a64408b96b5f67c2778958a230b5cfa3408a4a81Stefan Richter#include <asm/system.h> 46be5bbd6756b44602a3f281af05c2f416fa9bd1c6Stefan Richter 4777c9a5daa9c4d9b37812c9c69c7bcbb3f9399c3cStefan Richter#include "core.h" 4819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 4919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsbergstruct client { 50344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg u32 version; 5119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct fw_device *device; 5245ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason 5319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg spinlock_t lock; 5445ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason bool in_shutdown; 5545ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason struct idr resource_idr; 5619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct list_head event_list; 5719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg wait_queue_head_t wait; 58da8ecffaed434a12930f652898f9e86d1c2abc3eKristian Høgsberg u64 bus_reset_closure; 599aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg 6019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct fw_iso_context *iso_context; 61abaa5743e340c23922d92c9a5a6753ea3ae71e58Kristian Høgsberg u64 iso_closure; 629aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg struct fw_iso_buffer buffer; 639aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg unsigned long vm_start; 6497bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg 6597bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg struct list_head link; 66fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter struct kref kref; 6719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg}; 6819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 69fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richterstatic inline void client_get(struct client *client) 70fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter{ 71fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter kref_get(&client->kref); 72fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter} 73fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter 74fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richterstatic void client_release(struct kref *kref) 75fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter{ 76fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter struct client *client = container_of(kref, struct client, kref); 77fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter 78fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter fw_device_put(client->device); 79fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter kfree(client); 80fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter} 81fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter 82fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richterstatic void client_put(struct client *client) 83fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter{ 84fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter kref_put(&client->kref, client_release); 85fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter} 86fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter 8797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richterstruct client_resource; 8897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richtertypedef void (*client_resource_release_fn_t)(struct client *, 8997c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct client_resource *); 9097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richterstruct client_resource { 9197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter client_resource_release_fn_t release; 9297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter int handle; 9397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter}; 9497c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter 9597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richterstruct address_handler_resource { 9697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct client_resource resource; 9797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct fw_address_handler handler; 9897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter __u64 closure; 9997c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct client *client; 10097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter}; 10197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter 10297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richterstruct outbound_transaction_resource { 10397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct client_resource resource; 10497c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct fw_transaction transaction; 10597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter}; 10697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter 10797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richterstruct inbound_transaction_resource { 10897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct client_resource resource; 10997c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct fw_request *request; 11097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter void *data; 11197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter size_t length; 11297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter}; 11397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter 11497c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richterstruct descriptor_resource { 11597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct client_resource resource; 11697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct fw_descriptor descriptor; 11797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter u32 data[0]; 11897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter}; 11997c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter 120b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richterstruct iso_resource { 121b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter struct client_resource resource; 122b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter struct client *client; 123b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter /* Schedule work and access todo only with client->lock held. */ 124b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter struct delayed_work work; 1251ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter enum {ISO_RES_ALLOC, ISO_RES_REALLOC, ISO_RES_DEALLOC, 1261ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter ISO_RES_ALLOC_ONCE, ISO_RES_DEALLOC_ONCE,} todo; 127b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter int generation; 128b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter u64 channels; 129b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter s32 bandwidth; 1306fdc03709433ccc2005f0f593ae9d9dd04f7b485Stefan Richter __be32 transaction_data[2]; 131b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter struct iso_resource_event *e_alloc, *e_dealloc; 132b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter}; 133b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 134b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richterstatic void release_iso_resource(struct client *, struct client_resource *); 135b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1369fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richterstatic void schedule_iso_resource(struct iso_resource *r, unsigned long delay) 1379fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter{ 1389fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter client_get(r->client); 1399fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter if (!schedule_delayed_work(&r->work, delay)) 1409fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter client_put(r->client); 1419fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter} 1429fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter 1439fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richterstatic void schedule_if_iso_resource(struct client_resource *resource) 1449fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter{ 1459fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter if (resource->release == release_iso_resource) 1469fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter schedule_iso_resource(container_of(resource, 1479fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter struct iso_resource, resource), 0); 1489fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter} 1499fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter 15097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter/* 15197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter * dequeue_event() just kfree()'s the event, so the event has to be 15297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter * the first field in a struct XYZ_event. 15397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter */ 15497c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richterstruct event { 15597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct { void *data; size_t size; } v[2]; 15697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct list_head link; 15797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter}; 15897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter 15997c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richterstruct bus_reset_event { 16097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct event event; 16197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct fw_cdev_event_bus_reset reset; 16297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter}; 16397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter 16497c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richterstruct outbound_transaction_event { 16597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct event event; 16697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct client *client; 16797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct outbound_transaction_resource r; 16897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct fw_cdev_event_response response; 16997c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter}; 17097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter 17197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richterstruct inbound_transaction_event { 17297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct event event; 17397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct fw_cdev_event_request request; 17497c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter}; 17597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter 17697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richterstruct iso_interrupt_event { 17797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct event event; 17897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct fw_cdev_event_iso_interrupt interrupt; 17997c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter}; 18097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter 181b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richterstruct iso_resource_event { 182b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter struct event event; 183e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter struct fw_cdev_event_iso_resource iso_resource; 184b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter}; 185b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 18653dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic inline void __user *u64_to_uptr(__u64 value) 18719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 18819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return (void __user *)(unsigned long)value; 18919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 19019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 19153dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic inline __u64 uptr_to_u64(void __user *ptr) 19219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 19319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return (__u64)(unsigned long)ptr; 19419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 19519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 19619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsbergstatic int fw_device_op_open(struct inode *inode, struct file *file) 19719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 19819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct fw_device *device; 19919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct client *client; 20019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 20196b19062e741b715cf399312c30e0672d8889569Stefan Richter device = fw_device_get_by_devt(inode->i_rdev); 202a3aca3dabbcf00f2088d472f27755c29acaa992eKristian Høgsberg if (device == NULL) 203a3aca3dabbcf00f2088d472f27755c29acaa992eKristian Høgsberg return -ENODEV; 20419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 205551f4cb9de716ffcdaf968c99a450c22ff12e8c3Jay Fenlason if (fw_device_is_shutdown(device)) { 206551f4cb9de716ffcdaf968c99a450c22ff12e8c3Jay Fenlason fw_device_put(device); 207551f4cb9de716ffcdaf968c99a450c22ff12e8c3Jay Fenlason return -ENODEV; 208551f4cb9de716ffcdaf968c99a450c22ff12e8c3Jay Fenlason } 209551f4cb9de716ffcdaf968c99a450c22ff12e8c3Jay Fenlason 2102d826cc5c791bdc5f5651324c485746be9492be0Kristian Høgsberg client = kzalloc(sizeof(*client), GFP_KERNEL); 21196b19062e741b715cf399312c30e0672d8889569Stefan Richter if (client == NULL) { 21296b19062e741b715cf399312c30e0672d8889569Stefan Richter fw_device_put(device); 21319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return -ENOMEM; 21496b19062e741b715cf399312c30e0672d8889569Stefan Richter } 21519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 21696b19062e741b715cf399312c30e0672d8889569Stefan Richter client->device = device; 21719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg spin_lock_init(&client->lock); 21845ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason idr_init(&client->resource_idr); 21945ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason INIT_LIST_HEAD(&client->event_list); 22019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg init_waitqueue_head(&client->wait); 221fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter kref_init(&client->kref); 22219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 22319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg file->private_data = client; 22419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 225d67cfb9613f373d76daa2c8d209629601424ca12Stefan Richter mutex_lock(&device->client_list_mutex); 22697bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg list_add_tail(&client->link, &device->client_list); 227d67cfb9613f373d76daa2c8d209629601424ca12Stefan Richter mutex_unlock(&device->client_list_mutex); 22897bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg 22919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return 0; 23019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 23119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 23219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsbergstatic void queue_event(struct client *client, struct event *event, 23319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg void *data0, size_t size0, void *data1, size_t size1) 23419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 23519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg unsigned long flags; 23619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 23719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg event->v[0].data = data0; 23819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg event->v[0].size = size0; 23919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg event->v[1].data = data1; 24019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg event->v[1].size = size1; 24119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 24219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg spin_lock_irqsave(&client->lock, flags); 24345ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason if (client->in_shutdown) 24445ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason kfree(event); 24545ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason else 24645ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason list_add_tail(&event->link, &client->event_list); 24719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg spin_unlock_irqrestore(&client->lock, flags); 24883431cba3d847fc2296d3f38ce7feb623a1cfc45Jay Fenlason 24983431cba3d847fc2296d3f38ce7feb623a1cfc45Jay Fenlason wake_up_interruptible(&client->wait); 25019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 25119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 25253dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic int dequeue_event(struct client *client, 25353dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter char __user *buffer, size_t count) 25419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 25519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct event *event; 25619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg size_t size, total; 2572dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter int i, ret; 25819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 2592dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter ret = wait_event_interruptible(client->wait, 2602dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter !list_empty(&client->event_list) || 2612dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter fw_device_is_shutdown(client->device)); 2622dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter if (ret < 0) 2632dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter return ret; 26419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 2652603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg if (list_empty(&client->event_list) && 2662603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg fw_device_is_shutdown(client->device)) 2672603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg return -ENODEV; 26819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 2693ba949868a6dc082b24cba5c3bf3f50de7391433Stefan Richter spin_lock_irq(&client->lock); 270a459b8ab9c176143fecef8ace4b70d6dbd7a8113Stefan Richter event = list_first_entry(&client->event_list, struct event, link); 27119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg list_del(&event->link); 2723ba949868a6dc082b24cba5c3bf3f50de7391433Stefan Richter spin_unlock_irq(&client->lock); 27319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 27419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg total = 0; 27519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg for (i = 0; i < ARRAY_SIZE(event->v) && total < count; i++) { 27619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg size = min(event->v[i].size, count - total); 2772603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg if (copy_to_user(buffer + total, event->v[i].data, size)) { 2782dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter ret = -EFAULT; 27919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg goto out; 2802603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg } 28119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg total += size; 28219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg } 2832dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter ret = total; 28419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 28519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg out: 28619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg kfree(event); 28719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 2882dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter return ret; 28919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 29019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 29153dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic ssize_t fw_device_op_read(struct file *file, char __user *buffer, 29253dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter size_t count, loff_t *offset) 29319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 29419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct client *client = file->private_data; 29519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 29619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return dequeue_event(client, buffer, count); 29719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 29819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 29953dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic void fill_bus_reset_event(struct fw_cdev_event_bus_reset *event, 30053dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter struct client *client) 301344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg{ 302da8ecffaed434a12930f652898f9e86d1c2abc3eKristian Høgsberg struct fw_card *card = client->device->card; 303cf417e5494582453c033d8cac9e1352e74215435Jay Fenlason 3043ba949868a6dc082b24cba5c3bf3f50de7391433Stefan Richter spin_lock_irq(&card->lock); 305344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg 306da8ecffaed434a12930f652898f9e86d1c2abc3eKristian Høgsberg event->closure = client->bus_reset_closure; 307344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg event->type = FW_CDEV_EVENT_BUS_RESET; 308cf5a56ac8083dd04ffe8b9b2ec7895e9bcff44bcStefan Richter event->generation = client->device->generation; 309da8ecffaed434a12930f652898f9e86d1c2abc3eKristian Høgsberg event->node_id = client->device->node_id; 310344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg event->local_node_id = card->local_node->node_id; 311344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg event->bm_node_id = 0; /* FIXME: We don't track the BM. */ 312344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg event->irm_node_id = card->irm_node->node_id; 313344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg event->root_node_id = card->root_node->node_id; 314cf417e5494582453c033d8cac9e1352e74215435Jay Fenlason 3153ba949868a6dc082b24cba5c3bf3f50de7391433Stefan Richter spin_unlock_irq(&card->lock); 316344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg} 317344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg 31853dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic void for_each_client(struct fw_device *device, 31953dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter void (*callback)(struct client *client)) 3202603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg{ 3212603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg struct client *c; 3222603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg 323d67cfb9613f373d76daa2c8d209629601424ca12Stefan Richter mutex_lock(&device->client_list_mutex); 3242603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg list_for_each_entry(c, &device->client_list, link) 3252603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg callback(c); 326d67cfb9613f373d76daa2c8d209629601424ca12Stefan Richter mutex_unlock(&device->client_list_mutex); 3272603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg} 3282603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg 329b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richterstatic int schedule_reallocations(int id, void *p, void *data) 330b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter{ 3319fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter schedule_if_iso_resource(p); 332b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 333b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter return 0; 334b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter} 335b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 33653dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic void queue_bus_reset_event(struct client *client) 33797bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg{ 33897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct bus_reset_event *e; 33997bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg 34097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter e = kzalloc(sizeof(*e), GFP_KERNEL); 34197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter if (e == NULL) { 34297bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg fw_notify("Out of memory when allocating bus reset event\n"); 34397bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg return; 34497bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg } 34597bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg 34697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter fill_bus_reset_event(&e->reset, client); 34797bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg 34897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter queue_event(client, &e->event, 34997c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter &e->reset, sizeof(e->reset), NULL, 0); 350b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 351b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter spin_lock_irq(&client->lock); 352b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter idr_for_each(&client->resource_idr, schedule_reallocations, client); 353b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter spin_unlock_irq(&client->lock); 35497bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg} 35597bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg 35697bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsbergvoid fw_device_cdev_update(struct fw_device *device) 35797bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg{ 3582603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg for_each_client(device, queue_bus_reset_event); 3592603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg} 36097bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg 3612603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsbergstatic void wake_up_client(struct client *client) 3622603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg{ 3632603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg wake_up_interruptible(&client->wait); 3642603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg} 36597bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg 3662603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsbergvoid fw_device_cdev_remove(struct fw_device *device) 3672603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg{ 3682603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg for_each_client(device, wake_up_client); 36997bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg} 37097bd9efa5a4d8a70b3bafe0d1e3e1a814fdac5bcKristian Høgsberg 3716e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterunion ioctl_arg { 3726e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_get_info get_info; 3736e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_send_request send_request; 3746e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_allocate allocate; 3756e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_deallocate deallocate; 3766e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_send_response send_response; 3776e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_initiate_bus_reset initiate_bus_reset; 3786e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_add_descriptor add_descriptor; 3796e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_remove_descriptor remove_descriptor; 3806e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_create_iso_context create_iso_context; 3816e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_queue_iso queue_iso; 3826e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_start_iso start_iso; 3836e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_stop_iso stop_iso; 3846e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_get_cycle_timer get_cycle_timer; 3856e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_allocate_iso_resource allocate_iso_resource; 3866e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_send_stream_packet send_stream_packet; 3876e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_get_cycle_timer2 get_cycle_timer2; 3886e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter}; 3896e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter 3906e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_get_info(struct client *client, union ioctl_arg *arg) 39119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 3926e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_get_info *a = &arg->get_info; 393344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg struct fw_cdev_event_bus_reset bus_reset; 394c9755e14a01987ada4063e8b4c50c2b6738d879eStefan Richter unsigned long ret = 0; 395344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg 3966e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter client->version = a->version; 3976e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->version = FW_CDEV_VERSION; 3986e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->card = client->device->card->index; 399344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg 400c9755e14a01987ada4063e8b4c50c2b6738d879eStefan Richter down_read(&fw_device_rwsem); 401c9755e14a01987ada4063e8b4c50c2b6738d879eStefan Richter 4026e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (a->rom != 0) { 4036e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter size_t want = a->rom_length; 404d84702a5d7b500ead8db129ddea789c88764f357Stefan Richter size_t have = client->device->config_rom_length * 4; 405344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg 4066e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter ret = copy_to_user(u64_to_uptr(a->rom), 4076e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter client->device->config_rom, min(want, have)); 408344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg } 4096e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->rom_length = client->device->config_rom_length * 4; 410344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg 411c9755e14a01987ada4063e8b4c50c2b6738d879eStefan Richter up_read(&fw_device_rwsem); 412c9755e14a01987ada4063e8b4c50c2b6738d879eStefan Richter 413c9755e14a01987ada4063e8b4c50c2b6738d879eStefan Richter if (ret != 0) 414c9755e14a01987ada4063e8b4c50c2b6738d879eStefan Richter return -EFAULT; 415c9755e14a01987ada4063e8b4c50c2b6738d879eStefan Richter 4166e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter client->bus_reset_closure = a->bus_reset_closure; 4176e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (a->bus_reset != 0) { 418da8ecffaed434a12930f652898f9e86d1c2abc3eKristian Høgsberg fill_bus_reset_event(&bus_reset, client); 4196e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (copy_to_user(u64_to_uptr(a->bus_reset), 4206e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter &bus_reset, sizeof(bus_reset))) 421344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg return -EFAULT; 422344bbc4de14e70d03f09bff04bb7d161b8a0d28cKristian Høgsberg } 42319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 42419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return 0; 42519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 42619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 42753dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic int add_client_resource(struct client *client, 42853dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter struct client_resource *resource, gfp_t gfp_mask) 4293964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg{ 4303964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg unsigned long flags; 43145ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason int ret; 43245ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason 43345ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason retry: 43445ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason if (idr_pre_get(&client->resource_idr, gfp_mask) == 0) 43545ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason return -ENOMEM; 4363964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 4373964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg spin_lock_irqsave(&client->lock, flags); 43845ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason if (client->in_shutdown) 43945ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason ret = -ECANCELED; 44045ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason else 44145ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason ret = idr_get_new(&client->resource_idr, resource, 44245ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason &resource->handle); 443b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (ret >= 0) { 444fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter client_get(client); 4459fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter schedule_if_iso_resource(resource); 446b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } 4473964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg spin_unlock_irqrestore(&client->lock, flags); 44845ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason 44945ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason if (ret == -EAGAIN) 45045ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason goto retry; 45145ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason 45245ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason return ret < 0 ? ret : 0; 4533964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg} 4543964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 45553dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic int release_client_resource(struct client *client, u32 handle, 45653dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter client_resource_release_fn_t release, 457e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter struct client_resource **return_resource) 4583964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg{ 459e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter struct client_resource *resource; 4603964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 4613ba949868a6dc082b24cba5c3bf3f50de7391433Stefan Richter spin_lock_irq(&client->lock); 46245ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason if (client->in_shutdown) 463e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter resource = NULL; 46445ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason else 465e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter resource = idr_find(&client->resource_idr, handle); 466e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter if (resource && resource->release == release) 46745ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason idr_remove(&client->resource_idr, handle); 4683ba949868a6dc082b24cba5c3bf3f50de7391433Stefan Richter spin_unlock_irq(&client->lock); 4693964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 470e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter if (!(resource && resource->release == release)) 4713964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg return -EINVAL; 4723964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 473e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter if (return_resource) 474e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter *return_resource = resource; 4753964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg else 476e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter resource->release(client, resource); 4773964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 478fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter client_put(client); 479fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter 4803964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg return 0; 4813964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg} 4823964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 48353dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic void release_transaction(struct client *client, 48453dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter struct client_resource *resource) 4853964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg{ 48697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct outbound_transaction_resource *r = container_of(resource, 48797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct outbound_transaction_resource, resource); 4883964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 48997c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter fw_cancel_transaction(client->device->card, &r->transaction); 4903964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg} 4913964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 49253dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic void complete_transaction(struct fw_card *card, int rcode, 49353dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter void *payload, size_t length, void *data) 49419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 49597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct outbound_transaction_event *e = data; 49697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct fw_cdev_event_response *rsp = &e->response; 49797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct client *client = e->client; 49828cf6a04c82857d562968dc3a8a89726e6ac3dcbKristian Høgsberg unsigned long flags; 49919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 50097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter if (length < rsp->length) 50197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter rsp->length = length; 50219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg if (rcode == RCODE_COMPLETE) 50397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter memcpy(rsp->data, payload, rsp->length); 50419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 50528cf6a04c82857d562968dc3a8a89726e6ac3dcbKristian Høgsberg spin_lock_irqsave(&client->lock, flags); 50645ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason /* 507fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter * 1. If called while in shutdown, the idr tree must be left untouched. 508fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter * The idr handle will be removed and the client reference will be 509fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter * dropped later. 510fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter * 2. If the call chain was release_client_resource -> 511fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter * release_transaction -> complete_transaction (instead of a normal 512fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter * conclusion of the transaction), i.e. if this resource was already 513fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter * unregistered from the idr, the client reference will be dropped 514fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter * by release_client_resource and we must not drop it here. 51545ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason */ 516fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter if (!client->in_shutdown && 51797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter idr_find(&client->resource_idr, e->r.resource.handle)) { 51897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter idr_remove(&client->resource_idr, e->r.resource.handle); 519fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter /* Drop the idr's reference */ 520fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter client_put(client); 521fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter } 52228cf6a04c82857d562968dc3a8a89726e6ac3dcbKristian Høgsberg spin_unlock_irqrestore(&client->lock, flags); 52328cf6a04c82857d562968dc3a8a89726e6ac3dcbKristian Høgsberg 52497c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter rsp->type = FW_CDEV_EVENT_RESPONSE; 52597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter rsp->rcode = rcode; 5268401d92ba46a1e859464cbd9c9ee304f6e361da3David Moore 5278401d92ba46a1e859464cbd9c9ee304f6e361da3David Moore /* 52897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter * In the case that sizeof(*rsp) doesn't align with the position of the 5298401d92ba46a1e859464cbd9c9ee304f6e361da3David Moore * data, and the read is short, preserve an extra copy of the data 5308401d92ba46a1e859464cbd9c9ee304f6e361da3David Moore * to stay compatible with a pre-2.6.27 bug. Since the bug is harmless 5318401d92ba46a1e859464cbd9c9ee304f6e361da3David Moore * for short reads and some apps depended on it, this is both safe 5328401d92ba46a1e859464cbd9c9ee304f6e361da3David Moore * and prudent for compatibility. 5338401d92ba46a1e859464cbd9c9ee304f6e361da3David Moore */ 53497c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter if (rsp->length <= sizeof(*rsp) - offsetof(typeof(*rsp), data)) 53597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter queue_event(client, &e->event, rsp, sizeof(*rsp), 53697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter rsp->data, rsp->length); 5378401d92ba46a1e859464cbd9c9ee304f6e361da3David Moore else 53897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length, 5398401d92ba46a1e859464cbd9c9ee304f6e361da3David Moore NULL, 0); 540fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter 541fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter /* Drop the transaction callback's reference */ 542fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter client_put(client); 54319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 54419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 545acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richterstatic int init_request(struct client *client, 546acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter struct fw_cdev_send_request *request, 547acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter int destination_id, int speed) 54819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 54997c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct outbound_transaction_event *e; 5501f3125af8ed7410cc0ebcc0acd59bbfc1ae0057aStefan Richter int ret; 55119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 55218e9b10fcdc090d3a38606958167d5923c7099b7Stefan Richter if (request->tcode != TCODE_STREAM_DATA && 55318e9b10fcdc090d3a38606958167d5923c7099b7Stefan Richter (request->length > 4096 || request->length > 512 << speed)) 5545d3fd692a7196a9045fb606f891f5987959b65a0Stefan Richter return -EIO; 55519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 55697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL); 55797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter if (e == NULL) 55819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return -ENOMEM; 55919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 56097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter e->client = client; 56197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter e->response.length = request->length; 56297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter e->response.closure = request->closure; 56319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 5644f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg if (request->data && 56597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter copy_from_user(e->response.data, 5664f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg u64_to_uptr(request->data), request->length)) { 5671f3125af8ed7410cc0ebcc0acd59bbfc1ae0057aStefan Richter ret = -EFAULT; 56845ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason goto failed; 5691f3125af8ed7410cc0ebcc0acd59bbfc1ae0057aStefan Richter } 5701f3125af8ed7410cc0ebcc0acd59bbfc1ae0057aStefan Richter 57197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter e->r.resource.release = release_transaction; 57297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter ret = add_client_resource(client, &e->r.resource, GFP_KERNEL); 57345ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason if (ret < 0) 57445ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason goto failed; 57528cf6a04c82857d562968dc3a8a89726e6ac3dcbKristian Høgsberg 576fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter /* Get a reference for the transaction callback */ 577fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter client_get(client); 578fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter 579acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter fw_send_request(client->device->card, &e->r.transaction, 580664d8010b170ae8b3ce9268b4f4da934d27b0491Stefan Richter request->tcode, destination_id, request->generation, 581664d8010b170ae8b3ce9268b4f4da934d27b0491Stefan Richter speed, request->offset, e->response.data, 582664d8010b170ae8b3ce9268b4f4da934d27b0491Stefan Richter request->length, complete_transaction, e); 583664d8010b170ae8b3ce9268b4f4da934d27b0491Stefan Richter return 0; 58419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 58545ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason failed: 58697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter kfree(e); 5871f3125af8ed7410cc0ebcc0acd59bbfc1ae0057aStefan Richter 5881f3125af8ed7410cc0ebcc0acd59bbfc1ae0057aStefan Richter return ret; 58919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 59019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 5916e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_send_request(struct client *client, union ioctl_arg *arg) 592acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter{ 5936e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter switch (arg->send_request.tcode) { 594acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter case TCODE_WRITE_QUADLET_REQUEST: 595acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter case TCODE_WRITE_BLOCK_REQUEST: 596acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter case TCODE_READ_QUADLET_REQUEST: 597acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter case TCODE_READ_BLOCK_REQUEST: 598acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter case TCODE_LOCK_MASK_SWAP: 599acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter case TCODE_LOCK_COMPARE_SWAP: 600acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter case TCODE_LOCK_FETCH_ADD: 601acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter case TCODE_LOCK_LITTLE_ADD: 602acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter case TCODE_LOCK_BOUNDED_ADD: 603acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter case TCODE_LOCK_WRAP_ADD: 604acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter case TCODE_LOCK_VENDOR_DEPENDENT: 605acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter break; 606acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter default: 607acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter return -EINVAL; 608acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter } 609acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter 6106e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter return init_request(client, &arg->send_request, client->device->node_id, 611acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter client->device->max_speed); 612acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter} 613acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter 614281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richterstatic inline bool is_fcp_request(struct fw_request *request) 615281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter{ 616281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter return request == NULL; 617281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter} 618281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter 61953dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic void release_request(struct client *client, 62053dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter struct client_resource *resource) 6213964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg{ 62297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct inbound_transaction_resource *r = container_of(resource, 62397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct inbound_transaction_resource, resource); 6243964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 625281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter if (is_fcp_request(r->request)) 626281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter kfree(r->data); 627281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter else 628db5d247ae811f49185a71e703b65acad845e4b18Clemens Ladisch fw_send_response(client->device->card, r->request, 629db5d247ae811f49185a71e703b65acad845e4b18Clemens Ladisch RCODE_CONFLICT_ERROR); 63097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter kfree(r); 6313964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg} 6323964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 63397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richterstatic void handle_request(struct fw_card *card, struct fw_request *request, 63453dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter int tcode, int destination, int source, 63553dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter int generation, int speed, 63653dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter unsigned long long offset, 63753dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter void *payload, size_t length, void *callback_data) 63819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 63997c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct address_handler_resource *handler = callback_data; 64097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct inbound_transaction_resource *r; 64197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct inbound_transaction_event *e; 642281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter void *fcp_frame = NULL; 64345ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason int ret; 64419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 64597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter r = kmalloc(sizeof(*r), GFP_ATOMIC); 6462d826cc5c791bdc5f5651324c485746be9492be0Kristian Høgsberg e = kmalloc(sizeof(*e), GFP_ATOMIC); 64797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter if (r == NULL || e == NULL) 64845ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason goto failed; 64919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 65097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter r->request = request; 65197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter r->data = payload; 65297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter r->length = length; 65319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 654281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter if (is_fcp_request(request)) { 655281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter /* 656281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter * FIXME: Let core-transaction.c manage a 657281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter * single reference-counted copy? 658281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter */ 659281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter fcp_frame = kmemdup(payload, length, GFP_ATOMIC); 660281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter if (fcp_frame == NULL) 661281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter goto failed; 662281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter 663281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter r->data = fcp_frame; 664281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter } 665281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter 66697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter r->resource.release = release_request; 66797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC); 66845ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason if (ret < 0) 66945ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason goto failed; 67019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 67119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg e->request.type = FW_CDEV_EVENT_REQUEST; 67219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg e->request.tcode = tcode; 67319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg e->request.offset = offset; 67419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg e->request.length = length; 67597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter e->request.handle = r->resource.handle; 67619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg e->request.closure = handler->closure; 67719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 67897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter queue_event(handler->client, &e->event, 679281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter &e->request, sizeof(e->request), r->data, length); 68045ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason return; 68145ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason 68245ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason failed: 68397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter kfree(r); 68445ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason kfree(e); 685281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter kfree(fcp_frame); 686281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter 687281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter if (!is_fcp_request(request)) 688db5d247ae811f49185a71e703b65acad845e4b18Clemens Ladisch fw_send_response(card, request, RCODE_CONFLICT_ERROR); 68919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 69019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 69153dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic void release_address_handler(struct client *client, 69253dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter struct client_resource *resource) 6933964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg{ 69497c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct address_handler_resource *r = 69597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter container_of(resource, struct address_handler_resource, resource); 6963964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 69797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter fw_core_remove_address_handler(&r->handler); 69897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter kfree(r); 6993964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg} 7003964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 7016e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_allocate(struct client *client, union ioctl_arg *arg) 70219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 7036e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_allocate *a = &arg->allocate; 70497c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct address_handler_resource *r; 70519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct fw_address_region region; 70645ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason int ret; 70719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 70897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter r = kmalloc(sizeof(*r), GFP_KERNEL); 70997c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter if (r == NULL) 71019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return -ENOMEM; 71119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 7126e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter region.start = a->offset; 7136e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter region.end = a->offset + a->length; 7146e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter r->handler.length = a->length; 71597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter r->handler.address_callback = handle_request; 7166e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter r->handler.callback_data = r; 7176e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter r->closure = a->closure; 7186e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter r->client = client; 71919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 72097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter ret = fw_core_add_address_handler(&r->handler, ®ion); 7213e0b5f0d7cb5fef402517e41eebff5a0f0e65a13Stefan Richter if (ret < 0) { 72297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter kfree(r); 7233e0b5f0d7cb5fef402517e41eebff5a0f0e65a13Stefan Richter return ret; 72419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg } 72519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 72697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter r->resource.release = release_address_handler; 72797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter ret = add_client_resource(client, &r->resource, GFP_KERNEL); 72845ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason if (ret < 0) { 72997c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter release_address_handler(client, &r->resource); 73045ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason return ret; 73145ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason } 7326e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->handle = r->resource.handle; 73319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 73419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return 0; 73519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 73619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 7376e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_deallocate(struct client *client, union ioctl_arg *arg) 7389472316b6eab3500ded544f6e86700c33541ef4eKristian Høgsberg{ 7396e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter return release_client_resource(client, arg->deallocate.handle, 74045ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason release_address_handler, NULL); 7419472316b6eab3500ded544f6e86700c33541ef4eKristian Høgsberg} 7429472316b6eab3500ded544f6e86700c33541ef4eKristian Høgsberg 7436e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_send_response(struct client *client, union ioctl_arg *arg) 74419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 7456e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_send_response *a = &arg->send_response; 7463964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg struct client_resource *resource; 74797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct inbound_transaction_resource *r; 7487e44c0b56b07a5e34de9943cfb2fee72e71a9f0eStefan Richter int ret = 0; 74919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 7506e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (release_client_resource(client, a->handle, 75145ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason release_request, &resource) < 0) 75219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return -EINVAL; 75345ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason 75497c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter r = container_of(resource, struct inbound_transaction_resource, 75597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter resource); 756281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter if (is_fcp_request(r->request)) 757281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter goto out; 758281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter 7596e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (a->length < r->length) 7606e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter r->length = a->length; 7616e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (copy_from_user(r->data, u64_to_uptr(a->data), r->length)) { 762281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter ret = -EFAULT; 763281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter kfree(r->request); 764281e20323ab72180137824a298ee9e21e6f9acf6Stefan Richter goto out; 7657e44c0b56b07a5e34de9943cfb2fee72e71a9f0eStefan Richter } 7666e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter fw_send_response(client->device->card, r->request, a->rcode); 7677e44c0b56b07a5e34de9943cfb2fee72e71a9f0eStefan Richter out: 76819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg kfree(r); 76919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 7707e44c0b56b07a5e34de9943cfb2fee72e71a9f0eStefan Richter return ret; 77119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 77219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 7736e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_initiate_bus_reset(struct client *client, union ioctl_arg *arg) 7745371842b723dd04df57171f2c74660966901380cKristian Høgsberg{ 7756e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter return fw_core_initiate_bus_reset(client->device->card, 7766e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter arg->initiate_bus_reset.type == FW_CDEV_SHORT_RESET); 7775371842b723dd04df57171f2c74660966901380cKristian Høgsberg} 7785371842b723dd04df57171f2c74660966901380cKristian Høgsberg 7793964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsbergstatic void release_descriptor(struct client *client, 7803964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg struct client_resource *resource) 7813964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg{ 78297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct descriptor_resource *r = 78397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter container_of(resource, struct descriptor_resource, resource); 7843964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 78597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter fw_core_remove_descriptor(&r->descriptor); 78697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter kfree(r); 7873964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg} 7883964a4496eaa4cb84772e8dfc6c3a72ec4ddca7aKristian Høgsberg 7896e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_add_descriptor(struct client *client, union ioctl_arg *arg) 79066dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg{ 7916e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_add_descriptor *a = &arg->add_descriptor; 79297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct descriptor_resource *r; 79345ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason int ret; 79466dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg 795de487da8ca5839d057e1f4b57ee3f387e180b800Stefan Richter /* Access policy: Allow this ioctl only on local nodes' device files. */ 79692368890d551794ee8d7e90477d8498bb7f82a9bStefan Richter if (!client->device->is_local) 797de487da8ca5839d057e1f4b57ee3f387e180b800Stefan Richter return -ENOSYS; 798de487da8ca5839d057e1f4b57ee3f387e180b800Stefan Richter 7996e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (a->length > 256) 80066dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg return -EINVAL; 80166dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg 8026e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter r = kmalloc(sizeof(*r) + a->length * 4, GFP_KERNEL); 80397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter if (r == NULL) 80466dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg return -ENOMEM; 80566dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg 8066e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (copy_from_user(r->data, u64_to_uptr(a->data), a->length * 4)) { 80745ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason ret = -EFAULT; 80845ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason goto failed; 80966dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg } 81066dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg 8116e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter r->descriptor.length = a->length; 8126e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter r->descriptor.immediate = a->immediate; 8136e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter r->descriptor.key = a->key; 81497c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter r->descriptor.data = r->data; 81566dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg 81697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter ret = fw_core_add_descriptor(&r->descriptor); 81745ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason if (ret < 0) 81845ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason goto failed; 81966dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg 82097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter r->resource.release = release_descriptor; 82197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter ret = add_client_resource(client, &r->resource, GFP_KERNEL); 82245ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason if (ret < 0) { 82397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter fw_core_remove_descriptor(&r->descriptor); 82445ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason goto failed; 82545ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason } 8266e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->handle = r->resource.handle; 82766dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg 82866dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg return 0; 82945ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason failed: 83097c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter kfree(r); 83145ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason 83245ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason return ret; 83366dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg} 83466dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg 8356e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_remove_descriptor(struct client *client, union ioctl_arg *arg) 83666dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg{ 8376e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter return release_client_resource(client, arg->remove_descriptor.handle, 83845ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason release_descriptor, NULL); 83966dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg} 84066dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg 84153dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic void iso_callback(struct fw_iso_context *context, u32 cycle, 84253dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter size_t header_length, void *header, void *data) 84319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 84419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct client *client = data; 84597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter struct iso_interrupt_event *e; 84619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 84797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter e = kzalloc(sizeof(*e) + header_length, GFP_ATOMIC); 84897c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter if (e == NULL) 84919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return; 85019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 85197c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT; 85297c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter e->interrupt.closure = client->iso_closure; 85397c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter e->interrupt.cycle = cycle; 85497c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter e->interrupt.header_length = header_length; 85597c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter memcpy(e->interrupt.header, header, header_length); 85697c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter queue_event(client, &e->event, &e->interrupt, 85797c18b7fd6df4ae0d32509f292a2eb0d4b26d623Stefan Richter sizeof(e->interrupt) + header_length, NULL, 0); 85819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 85919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 8606e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg) 86119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 8626e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_create_iso_context *a = &arg->create_iso_context; 86324315c5e6f508edd84e996d67daef3d1bcc72f8bKristian Høgsberg struct fw_iso_context *context; 86419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 865fae603121428ba83b7343c88e68a7144525ab3ebStefan Richter /* We only support one context at this time. */ 866fae603121428ba83b7343c88e68a7144525ab3ebStefan Richter if (client->iso_context != NULL) 867fae603121428ba83b7343c88e68a7144525ab3ebStefan Richter return -EBUSY; 868fae603121428ba83b7343c88e68a7144525ab3ebStefan Richter 8696e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (a->channel > 63) 87021efb3cfc6ed49991638000f58bb23b838c76e25Kristian Høgsberg return -EINVAL; 87121efb3cfc6ed49991638000f58bb23b838c76e25Kristian Høgsberg 8726e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter switch (a->type) { 873c70dc788fd8d3870b41231b6a53a64afb98cfd13Kristian Høgsberg case FW_ISO_CONTEXT_RECEIVE: 8746e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (a->header_size < 4 || (a->header_size & 3)) 875c70dc788fd8d3870b41231b6a53a64afb98cfd13Kristian Høgsberg return -EINVAL; 876c70dc788fd8d3870b41231b6a53a64afb98cfd13Kristian Høgsberg break; 877c70dc788fd8d3870b41231b6a53a64afb98cfd13Kristian Høgsberg 878c70dc788fd8d3870b41231b6a53a64afb98cfd13Kristian Høgsberg case FW_ISO_CONTEXT_TRANSMIT: 8796e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (a->speed > SCODE_3200) 880c70dc788fd8d3870b41231b6a53a64afb98cfd13Kristian Høgsberg return -EINVAL; 881c70dc788fd8d3870b41231b6a53a64afb98cfd13Kristian Høgsberg break; 882c70dc788fd8d3870b41231b6a53a64afb98cfd13Kristian Høgsberg 883c70dc788fd8d3870b41231b6a53a64afb98cfd13Kristian Høgsberg default: 88421efb3cfc6ed49991638000f58bb23b838c76e25Kristian Høgsberg return -EINVAL; 885c70dc788fd8d3870b41231b6a53a64afb98cfd13Kristian Høgsberg } 886c70dc788fd8d3870b41231b6a53a64afb98cfd13Kristian Høgsberg 8876e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter context = fw_iso_context_create(client->device->card, a->type, 8886e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->channel, a->speed, a->header_size, 8896e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter iso_callback, client); 89024315c5e6f508edd84e996d67daef3d1bcc72f8bKristian Høgsberg if (IS_ERR(context)) 89124315c5e6f508edd84e996d67daef3d1bcc72f8bKristian Høgsberg return PTR_ERR(context); 89224315c5e6f508edd84e996d67daef3d1bcc72f8bKristian Høgsberg 8936e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter client->iso_closure = a->closure; 89424315c5e6f508edd84e996d67daef3d1bcc72f8bKristian Høgsberg client->iso_context = context; 89519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 896abaa5743e340c23922d92c9a5a6753ea3ae71e58Kristian Høgsberg /* We only support one context at this time. */ 8976e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->handle = 0; 898abaa5743e340c23922d92c9a5a6753ea3ae71e58Kristian Høgsberg 89919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return 0; 90019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 90119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 9021ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg/* Macros for decoding the iso packet control header. */ 9031ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg#define GET_PAYLOAD_LENGTH(v) ((v) & 0xffff) 9041ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg#define GET_INTERRUPT(v) (((v) >> 16) & 0x01) 9051ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg#define GET_SKIP(v) (((v) >> 17) & 0x01) 9067a1003449c693f0d57443c8786bbf19717921ae0Stefan Richter#define GET_TAG(v) (((v) >> 18) & 0x03) 9077a1003449c693f0d57443c8786bbf19717921ae0Stefan Richter#define GET_SY(v) (((v) >> 20) & 0x0f) 9081ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg#define GET_HEADER_LENGTH(v) (((v) >> 24) & 0xff) 9091ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg 9106e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_queue_iso(struct client *client, union ioctl_arg *arg) 91119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 9126e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_queue_iso *a = &arg->queue_iso; 91319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct fw_cdev_iso_packet __user *p, *end, *next; 9149b32d5f3074e9b1afaa39a360a59fd77a2214783Kristian Høgsberg struct fw_iso_context *ctx = client->iso_context; 915ef370ee74b7a9cb769d50bfb73b4023ee3e37719Kristian Høgsberg unsigned long payload, buffer_end, header_length; 9161ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg u32 control; 91719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg int count; 91819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct { 91919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct fw_iso_packet packet; 92019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg u8 header[256]; 92119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg } u; 92219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 9236e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (ctx == NULL || a->handle != 0) 92419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return -EINVAL; 92519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 926c781c06d119d04601727f2fbc30151e6760d536dKristian Høgsberg /* 927c781c06d119d04601727f2fbc30151e6760d536dKristian Høgsberg * If the user passes a non-NULL data pointer, has mmap()'ed 92819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * the iso buffer, and the pointer points inside the buffer, 92919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * we setup the payload pointers accordingly. Otherwise we 9309aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg * set them both to 0, which will still let packets with 93119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * payload_length == 0 through. In other words, if no packets 93219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg * use the indirect payload, the iso buffer need not be mapped 9336e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter * and the a->data pointer is ignored. 934c781c06d119d04601727f2fbc30151e6760d536dKristian Høgsberg */ 93519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 9366e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter payload = (unsigned long)a->data - client->vm_start; 937ef370ee74b7a9cb769d50bfb73b4023ee3e37719Kristian Høgsberg buffer_end = client->buffer.page_count << PAGE_SHIFT; 9386e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (a->data == 0 || client->buffer.pages == NULL || 939ef370ee74b7a9cb769d50bfb73b4023ee3e37719Kristian Høgsberg payload >= buffer_end) { 9409aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg payload = 0; 941ef370ee74b7a9cb769d50bfb73b4023ee3e37719Kristian Høgsberg buffer_end = 0; 94219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg } 94319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 9446e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(a->packets); 9451ccc9147f6a063c42fef67acff34de18435a4a6bAl Viro 9466e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (!access_ok(VERIFY_READ, p, a->size)) 94719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return -EFAULT; 94819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 9496e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter end = (void __user *)p + a->size; 95019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg count = 0; 95119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg while (p < end) { 9521ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg if (get_user(control, &p->control)) 95319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return -EFAULT; 9541ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg u.packet.payload_length = GET_PAYLOAD_LENGTH(control); 9551ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg u.packet.interrupt = GET_INTERRUPT(control); 9561ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg u.packet.skip = GET_SKIP(control); 9571ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg u.packet.tag = GET_TAG(control); 9581ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg u.packet.sy = GET_SY(control); 9591ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158Kristian Høgsberg u.packet.header_length = GET_HEADER_LENGTH(control); 960295e3feb92e5073ec32a3c626302d4b92c4c8a95Kristian Høgsberg 9619b32d5f3074e9b1afaa39a360a59fd77a2214783Kristian Høgsberg if (ctx->type == FW_ISO_CONTEXT_TRANSMIT) { 962385ab5bcd4be586dffdba550b310308d89eade71Clemens Ladisch if (u.packet.header_length % 4 != 0) 963385ab5bcd4be586dffdba550b310308d89eade71Clemens Ladisch return -EINVAL; 964295e3feb92e5073ec32a3c626302d4b92c4c8a95Kristian Høgsberg header_length = u.packet.header_length; 965295e3feb92e5073ec32a3c626302d4b92c4c8a95Kristian Høgsberg } else { 966c781c06d119d04601727f2fbc30151e6760d536dKristian Høgsberg /* 967c781c06d119d04601727f2fbc30151e6760d536dKristian Høgsberg * We require that header_length is a multiple of 968c781c06d119d04601727f2fbc30151e6760d536dKristian Høgsberg * the fixed header size, ctx->header_size. 969c781c06d119d04601727f2fbc30151e6760d536dKristian Høgsberg */ 9709b32d5f3074e9b1afaa39a360a59fd77a2214783Kristian Høgsberg if (ctx->header_size == 0) { 9719b32d5f3074e9b1afaa39a360a59fd77a2214783Kristian Høgsberg if (u.packet.header_length > 0) 9729b32d5f3074e9b1afaa39a360a59fd77a2214783Kristian Høgsberg return -EINVAL; 9734ba1d9c0c22947a9207029e7184733252e6135f1Clemens Ladisch } else if (u.packet.header_length == 0 || 9744ba1d9c0c22947a9207029e7184733252e6135f1Clemens Ladisch u.packet.header_length % ctx->header_size != 0) { 975295e3feb92e5073ec32a3c626302d4b92c4c8a95Kristian Høgsberg return -EINVAL; 9769b32d5f3074e9b1afaa39a360a59fd77a2214783Kristian Høgsberg } 977295e3feb92e5073ec32a3c626302d4b92c4c8a95Kristian Høgsberg header_length = 0; 978295e3feb92e5073ec32a3c626302d4b92c4c8a95Kristian Høgsberg } 979295e3feb92e5073ec32a3c626302d4b92c4c8a95Kristian Høgsberg 98019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg next = (struct fw_cdev_iso_packet __user *) 981295e3feb92e5073ec32a3c626302d4b92c4c8a95Kristian Høgsberg &p->header[header_length / 4]; 98219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg if (next > end) 98319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return -EINVAL; 98419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg if (__copy_from_user 985295e3feb92e5073ec32a3c626302d4b92c4c8a95Kristian Høgsberg (u.packet.header, p->header, header_length)) 98619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return -EFAULT; 98798b6cbe83b6e8db54638746c9040c7962d96b322Kristian Høgsberg if (u.packet.skip && ctx->type == FW_ISO_CONTEXT_TRANSMIT && 98819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg u.packet.header_length + u.packet.payload_length > 0) 98919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return -EINVAL; 990ef370ee74b7a9cb769d50bfb73b4023ee3e37719Kristian Høgsberg if (payload + u.packet.payload_length > buffer_end) 99119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return -EINVAL; 99219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 9939b32d5f3074e9b1afaa39a360a59fd77a2214783Kristian Høgsberg if (fw_iso_context_queue(ctx, &u.packet, 9949b32d5f3074e9b1afaa39a360a59fd77a2214783Kristian Høgsberg &client->buffer, payload)) 99519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg break; 99619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 99719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg p = next; 99819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg payload += u.packet.payload_length; 99919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg count++; 100019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg } 100119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 10026e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->size -= uptr_to_u64(p) - a->packets; 10036e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->packets = uptr_to_u64(p); 10046e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->data = client->vm_start + payload; 100519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 100619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return count; 100719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 100819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 10096e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_start_iso(struct client *client, union ioctl_arg *arg) 101019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 10116e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_start_iso *a = &arg->start_iso; 101219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 10136e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (client->iso_context == NULL || a->handle != 0) 1014abaa5743e340c23922d92c9a5a6753ea3ae71e58Kristian Høgsberg return -EINVAL; 1015fae603121428ba83b7343c88e68a7144525ab3ebStefan Richter 10166e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE && 10176e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter (a->tags == 0 || a->tags > 15 || a->sync > 15)) 10186e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter return -EINVAL; 1019eb0306eac0aad0b7da18d8fbfb777f155b2c010dKristian Høgsberg 10206e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter return fw_iso_context_start(client->iso_context, 10216e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->cycle, a->sync, a->tags); 102219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 102319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 10246e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_stop_iso(struct client *client, union ioctl_arg *arg) 1025b82956685aab4a9d333714300eb8a86fed6c9ab3Kristian Høgsberg{ 10266e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_stop_iso *a = &arg->stop_iso; 1027abaa5743e340c23922d92c9a5a6753ea3ae71e58Kristian Høgsberg 10286e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (client->iso_context == NULL || a->handle != 0) 1029abaa5743e340c23922d92c9a5a6753ea3ae71e58Kristian Høgsberg return -EINVAL; 1030abaa5743e340c23922d92c9a5a6753ea3ae71e58Kristian Høgsberg 1031b82956685aab4a9d333714300eb8a86fed6c9ab3Kristian Høgsberg return fw_iso_context_stop(client->iso_context); 1032b82956685aab4a9d333714300eb8a86fed6c9ab3Kristian Høgsberg} 1033b82956685aab4a9d333714300eb8a86fed6c9ab3Kristian Høgsberg 10346e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_get_cycle_timer2(struct client *client, union ioctl_arg *arg) 1035a64408b96b5f67c2778958a230b5cfa3408a4a81Stefan Richter{ 10366e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_get_cycle_timer2 *a = &arg->get_cycle_timer2; 1037a64408b96b5f67c2778958a230b5cfa3408a4a81Stefan Richter struct fw_card *card = client->device->card; 1038abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter struct timespec ts = {0, 0}; 10394a9bde9b8ab55a2bb51b57cad215a97bcf80bae2Stefan Richter u32 cycle_time; 1040abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter int ret = 0; 1041a64408b96b5f67c2778958a230b5cfa3408a4a81Stefan Richter 10424a9bde9b8ab55a2bb51b57cad215a97bcf80bae2Stefan Richter local_irq_disable(); 1043a64408b96b5f67c2778958a230b5cfa3408a4a81Stefan Richter 1044168cf9af699e87d5a6f44b684583714ecabb8e71Stefan Richter cycle_time = card->driver->get_cycle_time(card); 1045abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter 10466e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter switch (a->clk_id) { 1047abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter case CLOCK_REALTIME: getnstimeofday(&ts); break; 1048abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter case CLOCK_MONOTONIC: do_posix_clock_monotonic_gettime(&ts); break; 1049abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts); break; 1050abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter default: 1051abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter ret = -EINVAL; 1052abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter } 1053a64408b96b5f67c2778958a230b5cfa3408a4a81Stefan Richter 10544a9bde9b8ab55a2bb51b57cad215a97bcf80bae2Stefan Richter local_irq_enable(); 1055a64408b96b5f67c2778958a230b5cfa3408a4a81Stefan Richter 10566e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->tv_sec = ts.tv_sec; 10576e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->tv_nsec = ts.tv_nsec; 10586e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->cycle_timer = cycle_time; 1059abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter 1060abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter return ret; 1061abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter} 1062abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter 10636e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_get_cycle_timer(struct client *client, union ioctl_arg *arg) 1064abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter{ 10656e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_get_cycle_timer *a = &arg->get_cycle_timer; 1066abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter struct fw_cdev_get_cycle_timer2 ct2; 1067abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter 1068abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter ct2.clk_id = CLOCK_REALTIME; 10696e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter ioctl_get_cycle_timer2(client, (union ioctl_arg *)&ct2); 1070abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter 10716e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->local_time = ct2.tv_sec * USEC_PER_SEC + ct2.tv_nsec / NSEC_PER_USEC; 10726e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->cycle_timer = ct2.cycle_timer; 10734a9bde9b8ab55a2bb51b57cad215a97bcf80bae2Stefan Richter 1074a64408b96b5f67c2778958a230b5cfa3408a4a81Stefan Richter return 0; 1075a64408b96b5f67c2778958a230b5cfa3408a4a81Stefan Richter} 1076a64408b96b5f67c2778958a230b5cfa3408a4a81Stefan Richter 1077b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richterstatic void iso_resource_work(struct work_struct *work) 1078b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter{ 1079b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter struct iso_resource_event *e; 1080b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter struct iso_resource *r = 1081b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter container_of(work, struct iso_resource, work.work); 1082b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter struct client *client = r->client; 1083b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter int generation, channel, bandwidth, todo; 1084b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter bool skip, free, success; 1085b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1086b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter spin_lock_irq(&client->lock); 1087b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter generation = client->device->generation; 1088b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter todo = r->todo; 1089b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter /* Allow 1000ms grace period for other reallocations. */ 1090b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (todo == ISO_RES_ALLOC && 1091b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) { 10929fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3)); 1093b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter skip = true; 1094b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } else { 1095b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter /* We could be called twice within the same generation. */ 1096b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter skip = todo == ISO_RES_REALLOC && 1097b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r->generation == generation; 1098b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } 10991ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter free = todo == ISO_RES_DEALLOC || 11001ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter todo == ISO_RES_ALLOC_ONCE || 11011ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter todo == ISO_RES_DEALLOC_ONCE; 1102b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r->generation = generation; 1103b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter spin_unlock_irq(&client->lock); 1104b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1105b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (skip) 1106b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter goto out; 1107b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1108b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter bandwidth = r->bandwidth; 1109b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1110b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter fw_iso_resource_manage(client->device->card, generation, 1111b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r->channels, &channel, &bandwidth, 11121ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter todo == ISO_RES_ALLOC || 11131ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter todo == ISO_RES_REALLOC || 11146fdc03709433ccc2005f0f593ae9d9dd04f7b485Stefan Richter todo == ISO_RES_ALLOC_ONCE, 11156fdc03709433ccc2005f0f593ae9d9dd04f7b485Stefan Richter r->transaction_data); 1116b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter /* 1117b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * Is this generation outdated already? As long as this resource sticks 1118b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * in the idr, it will be scheduled again for a newer generation or at 1119b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * shutdown. 1120b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter */ 1121b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (channel == -EAGAIN && 1122b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter (todo == ISO_RES_ALLOC || todo == ISO_RES_REALLOC)) 1123b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter goto out; 1124b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1125b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter success = channel >= 0 || bandwidth > 0; 1126b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1127b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter spin_lock_irq(&client->lock); 1128b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter /* 1129b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * Transit from allocation to reallocation, except if the client 1130b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * requested deallocation in the meantime. 1131b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter */ 1132b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (r->todo == ISO_RES_ALLOC) 1133b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r->todo = ISO_RES_REALLOC; 1134b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter /* 1135b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * Allocation or reallocation failure? Pull this resource out of the 1136b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * idr and prepare for deletion, unless the client is shutting down. 1137b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter */ 1138b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (r->todo == ISO_RES_REALLOC && !success && 1139b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter !client->in_shutdown && 1140b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter idr_find(&client->resource_idr, r->resource.handle)) { 1141b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter idr_remove(&client->resource_idr, r->resource.handle); 1142b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter client_put(client); 1143b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter free = true; 1144b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } 1145b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter spin_unlock_irq(&client->lock); 1146b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1147b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (todo == ISO_RES_ALLOC && channel >= 0) 11485d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter r->channels = 1ULL << channel; 1149b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1150b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (todo == ISO_RES_REALLOC && success) 1151b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter goto out; 1152b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 11531ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter if (todo == ISO_RES_ALLOC || todo == ISO_RES_ALLOC_ONCE) { 1154b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter e = r->e_alloc; 1155b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r->e_alloc = NULL; 1156b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } else { 1157b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter e = r->e_dealloc; 1158b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r->e_dealloc = NULL; 1159b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } 1160e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter e->iso_resource.handle = r->resource.handle; 1161e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter e->iso_resource.channel = channel; 1162e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter e->iso_resource.bandwidth = bandwidth; 1163b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1164b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter queue_event(client, &e->event, 1165e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter &e->iso_resource, sizeof(e->iso_resource), NULL, 0); 1166b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1167b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (free) { 1168b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter cancel_delayed_work(&r->work); 1169b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter kfree(r->e_alloc); 1170b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter kfree(r->e_dealloc); 1171b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter kfree(r); 1172b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } 1173b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter out: 1174b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter client_put(client); 1175b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter} 1176b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1177b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richterstatic void release_iso_resource(struct client *client, 1178b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter struct client_resource *resource) 1179b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter{ 1180b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter struct iso_resource *r = 1181b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter container_of(resource, struct iso_resource, resource); 1182b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1183b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter spin_lock_irq(&client->lock); 1184b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r->todo = ISO_RES_DEALLOC; 11859fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter schedule_iso_resource(r, 0); 1186b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter spin_unlock_irq(&client->lock); 1187b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter} 1188b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 11891ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richterstatic int init_iso_resource(struct client *client, 11901ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter struct fw_cdev_allocate_iso_resource *request, int todo) 1191b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter{ 1192b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter struct iso_resource_event *e1, *e2; 1193b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter struct iso_resource *r; 1194b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter int ret; 1195b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1196b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if ((request->channels == 0 && request->bandwidth == 0) || 1197b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter request->bandwidth > BANDWIDTH_AVAILABLE_INITIAL || 1198b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter request->bandwidth < 0) 1199b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter return -EINVAL; 1200b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1201b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r = kmalloc(sizeof(*r), GFP_KERNEL); 1202b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter e1 = kmalloc(sizeof(*e1), GFP_KERNEL); 1203b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter e2 = kmalloc(sizeof(*e2), GFP_KERNEL); 1204b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (r == NULL || e1 == NULL || e2 == NULL) { 1205b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter ret = -ENOMEM; 1206b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter goto fail; 1207b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } 1208b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1209b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter INIT_DELAYED_WORK(&r->work, iso_resource_work); 1210b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r->client = client; 12111ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter r->todo = todo; 1212b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r->generation = -1; 1213b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r->channels = request->channels; 1214b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r->bandwidth = request->bandwidth; 1215b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r->e_alloc = e1; 1216b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter r->e_dealloc = e2; 1217b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1218e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter e1->iso_resource.closure = request->closure; 1219e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter e1->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED; 1220e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter e2->iso_resource.closure = request->closure; 1221e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter e2->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED; 1222b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 12231ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter if (todo == ISO_RES_ALLOC) { 12241ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter r->resource.release = release_iso_resource; 12251ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter ret = add_client_resource(client, &r->resource, GFP_KERNEL); 122681610b8fbfc027a67707ff567d490819a3d55844Stefan Richter if (ret < 0) 122781610b8fbfc027a67707ff567d490819a3d55844Stefan Richter goto fail; 12281ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter } else { 12291ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter r->resource.release = NULL; 12301ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter r->resource.handle = -1; 12319fb551bf72929b316abb6d96cfb2ec05e896042aStefan Richter schedule_iso_resource(r, 0); 12321ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter } 1233b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter request->handle = r->resource.handle; 1234b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1235b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter return 0; 1236b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter fail: 1237b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter kfree(r); 1238b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter kfree(e1); 1239b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter kfree(e2); 1240b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 1241b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter return ret; 1242b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter} 1243b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 12446e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_allocate_iso_resource(struct client *client, 12456e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter union ioctl_arg *arg) 12461ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter{ 12476e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter return init_iso_resource(client, 12486e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter &arg->allocate_iso_resource, ISO_RES_ALLOC); 12491ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter} 12501ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter 12516e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_deallocate_iso_resource(struct client *client, 12526e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter union ioctl_arg *arg) 1253b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter{ 12546e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter return release_client_resource(client, 12556e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter arg->deallocate.handle, release_iso_resource, NULL); 1256b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter} 1257b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 12586e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_allocate_iso_resource_once(struct client *client, 12596e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter union ioctl_arg *arg) 12601ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter{ 12616e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter return init_iso_resource(client, 12626e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter &arg->allocate_iso_resource, ISO_RES_ALLOC_ONCE); 12631ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter} 12641ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter 12656e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_deallocate_iso_resource_once(struct client *client, 12666e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter union ioctl_arg *arg) 12671ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter{ 12686e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter return init_iso_resource(client, 12696e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter &arg->allocate_iso_resource, ISO_RES_DEALLOC_ONCE); 12701ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter} 12711ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter 1272c8a25900f35e575938c791507894c036c0f2ca7dStefan Richter/* 1273c8a25900f35e575938c791507894c036c0f2ca7dStefan Richter * Returns a speed code: Maximum speed to or from this device, 1274c8a25900f35e575938c791507894c036c0f2ca7dStefan Richter * limited by the device's link speed, the local node's link speed, 1275c8a25900f35e575938c791507894c036c0f2ca7dStefan Richter * and all PHY port speeds between the two links. 1276c8a25900f35e575938c791507894c036c0f2ca7dStefan Richter */ 12776e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_get_speed(struct client *client, union ioctl_arg *arg) 127833580a3ef5ba3bc0ee1b520df82a24bb37ce28f0Stefan Richter{ 1279c8a25900f35e575938c791507894c036c0f2ca7dStefan Richter return client->device->max_speed; 128033580a3ef5ba3bc0ee1b520df82a24bb37ce28f0Stefan Richter} 128133580a3ef5ba3bc0ee1b520df82a24bb37ce28f0Stefan Richter 12826e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_send_broadcast_request(struct client *client, 12836e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter union ioctl_arg *arg) 1284acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter{ 12856e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_send_request *a = &arg->send_request; 1286acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter 12876e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter switch (a->tcode) { 1288acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter case TCODE_WRITE_QUADLET_REQUEST: 1289acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter case TCODE_WRITE_BLOCK_REQUEST: 1290acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter break; 1291acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter default: 1292acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter return -EINVAL; 1293acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter } 1294acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter 12951566f3dc3e5986a16c7bbb3bb95bb691251a8d25Stefan Richter /* Security policy: Only allow accesses to Units Space. */ 12966e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (a->offset < CSR_REGISTER_BASE + CSR_CONFIG_ROM_END) 12971566f3dc3e5986a16c7bbb3bb95bb691251a8d25Stefan Richter return -EACCES; 12981566f3dc3e5986a16c7bbb3bb95bb691251a8d25Stefan Richter 12996e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter return init_request(client, a, LOCAL_BUS | 0x3f, SCODE_100); 1300acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter} 1301acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter 13026e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int ioctl_send_stream_packet(struct client *client, union ioctl_arg *arg) 1303f8c2287c65f8f72000102fc058232669e4540bc4Jay Fenlason{ 13046e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter struct fw_cdev_send_stream_packet *a = &arg->send_stream_packet; 130518e9b10fcdc090d3a38606958167d5923c7099b7Stefan Richter struct fw_cdev_send_request request; 130618e9b10fcdc090d3a38606958167d5923c7099b7Stefan Richter int dest; 1307f8c2287c65f8f72000102fc058232669e4540bc4Jay Fenlason 13086e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (a->speed > client->device->card->link_speed || 13096e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter a->length > 1024 << a->speed) 131018e9b10fcdc090d3a38606958167d5923c7099b7Stefan Richter return -EIO; 1311f8c2287c65f8f72000102fc058232669e4540bc4Jay Fenlason 13126e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter if (a->tag > 3 || a->channel > 63 || a->sy > 15) 131318e9b10fcdc090d3a38606958167d5923c7099b7Stefan Richter return -EINVAL; 131418e9b10fcdc090d3a38606958167d5923c7099b7Stefan Richter 13156e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter dest = fw_stream_packet_destination_id(a->tag, a->channel, a->sy); 131618e9b10fcdc090d3a38606958167d5923c7099b7Stefan Richter request.tcode = TCODE_STREAM_DATA; 13176e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter request.length = a->length; 13186e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter request.closure = a->closure; 13196e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter request.data = a->data; 13206e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter request.generation = a->generation; 132118e9b10fcdc090d3a38606958167d5923c7099b7Stefan Richter 13226e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter return init_request(client, &request, dest, a->speed); 1323f8c2287c65f8f72000102fc058232669e4540bc4Jay Fenlason} 1324f8c2287c65f8f72000102fc058232669e4540bc4Jay Fenlason 13256e95dea728f4af36c033fcf2318529bd46dae540Stefan Richterstatic int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = { 13264f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg ioctl_get_info, 13274f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg ioctl_send_request, 13284f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg ioctl_allocate, 13294f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg ioctl_deallocate, 13304f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg ioctl_send_response, 13314f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg ioctl_initiate_bus_reset, 13324f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg ioctl_add_descriptor, 13334f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg ioctl_remove_descriptor, 13344f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg ioctl_create_iso_context, 13354f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg ioctl_queue_iso, 13364f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg ioctl_start_iso, 13374f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg ioctl_stop_iso, 1338a64408b96b5f67c2778958a230b5cfa3408a4a81Stefan Richter ioctl_get_cycle_timer, 1339b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter ioctl_allocate_iso_resource, 1340b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter ioctl_deallocate_iso_resource, 13411ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter ioctl_allocate_iso_resource_once, 13421ec3c0269d7196118cc7c403654ca5f19ef4d584Stefan Richter ioctl_deallocate_iso_resource_once, 134333580a3ef5ba3bc0ee1b520df82a24bb37ce28f0Stefan Richter ioctl_get_speed, 1344acfe8333572cad5dc70fce18ac966be0446548d7Jay Fenlason, Stefan Richter ioctl_send_broadcast_request, 1345f8c2287c65f8f72000102fc058232669e4540bc4Jay Fenlason ioctl_send_stream_packet, 1346abfe5a01ef1e463cbafdae461b693db34e308c02Stefan Richter ioctl_get_cycle_timer2, 13474f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg}; 13484f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg 134953dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic int dispatch_ioctl(struct client *client, 135053dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter unsigned int cmd, void __user *arg) 135119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 13526e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter union ioctl_arg buffer; 13532dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter int ret; 13544f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg 135564582298b9c29535188380f488873e7d2196a2ebStefan Richter if (fw_device_is_shutdown(client->device)) 135664582298b9c29535188380f488873e7d2196a2ebStefan Richter return -ENODEV; 135764582298b9c29535188380f488873e7d2196a2ebStefan Richter 13584f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg if (_IOC_TYPE(cmd) != '#' || 13594f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers)) 136019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return -EINVAL; 13614f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg 13624f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg if (_IOC_DIR(cmd) & _IOC_WRITE) { 13632d826cc5c791bdc5f5651324c485746be9492be0Kristian Høgsberg if (_IOC_SIZE(cmd) > sizeof(buffer) || 13646e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter copy_from_user(&buffer, arg, _IOC_SIZE(cmd))) 13654f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg return -EFAULT; 13664f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg } 13674f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg 13686e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter ret = ioctl_handlers[_IOC_NR(cmd)](client, &buffer); 13692dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter if (ret < 0) 13702dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter return ret; 13714f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg 13724f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg if (_IOC_DIR(cmd) & _IOC_READ) { 13732d826cc5c791bdc5f5651324c485746be9492be0Kristian Høgsberg if (_IOC_SIZE(cmd) > sizeof(buffer) || 13746e95dea728f4af36c033fcf2318529bd46dae540Stefan Richter copy_to_user(arg, &buffer, _IOC_SIZE(cmd))) 13754f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg return -EFAULT; 137619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg } 13774f2592232ea951e52b2faf1abf519e13856ac6f4Kristian Høgsberg 13782dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter return ret; 137919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 138019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 138153dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic long fw_device_op_ioctl(struct file *file, 138253dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter unsigned int cmd, unsigned long arg) 138319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 138464582298b9c29535188380f488873e7d2196a2ebStefan Richter return dispatch_ioctl(file->private_data, cmd, (void __user *)arg); 138519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 138619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 138719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg#ifdef CONFIG_COMPAT 138853dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstatic long fw_device_op_compat_ioctl(struct file *file, 138953dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter unsigned int cmd, unsigned long arg) 139019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 139164582298b9c29535188380f488873e7d2196a2ebStefan Richter return dispatch_ioctl(file->private_data, cmd, compat_ptr(arg)); 139219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 139319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg#endif 139419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 139519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsbergstatic int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma) 139619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 139719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct client *client = file->private_data; 13989aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg enum dma_data_direction direction; 13999aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg unsigned long size; 14002dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter int page_count, ret; 14019aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg 1402551f4cb9de716ffcdaf968c99a450c22ff12e8c3Jay Fenlason if (fw_device_is_shutdown(client->device)) 1403551f4cb9de716ffcdaf968c99a450c22ff12e8c3Jay Fenlason return -ENODEV; 1404551f4cb9de716ffcdaf968c99a450c22ff12e8c3Jay Fenlason 14059aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg /* FIXME: We could support multiple buffers, but we don't. */ 14069aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg if (client->buffer.pages != NULL) 14079aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg return -EBUSY; 14089aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg 14099aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg if (!(vma->vm_flags & VM_SHARED)) 14109aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg return -EINVAL; 141119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 14129aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg if (vma->vm_start & ~PAGE_MASK) 141319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return -EINVAL; 141419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 141519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg client->vm_start = vma->vm_start; 14169aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg size = vma->vm_end - vma->vm_start; 14179aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg page_count = size >> PAGE_SHIFT; 14189aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg if (size & ~PAGE_MASK) 14199aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg return -EINVAL; 14209aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg 14219aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg if (vma->vm_flags & VM_WRITE) 14229aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg direction = DMA_TO_DEVICE; 14239aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg else 14249aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg direction = DMA_FROM_DEVICE; 14259aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg 14262dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter ret = fw_iso_buffer_init(&client->buffer, client->device->card, 14272dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter page_count, direction); 14282dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter if (ret < 0) 14292dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter return ret; 143019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 14312dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter ret = fw_iso_buffer_map(&client->buffer, vma); 14322dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter if (ret < 0) 14339aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg fw_iso_buffer_destroy(&client->buffer, client->device->card); 14349aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg 14352dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter return ret; 143619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 143719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 143845ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlasonstatic int shutdown_resource(int id, void *p, void *data) 143945ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason{ 1440e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter struct client_resource *resource = p; 144145ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason struct client *client = data; 144245ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason 1443e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter resource->release(client, resource); 1444fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter client_put(client); 144545ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason 144645ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason return 0; 144745ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason} 144845ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason 144919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsbergstatic int fw_device_op_release(struct inode *inode, struct file *file) 145019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 145119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct client *client = file->private_data; 1452e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter struct event *event, *next_event; 145319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 145497811e347310766030a648fdf0e407b2c91a39c1Stefan Richter mutex_lock(&client->device->client_list_mutex); 145597811e347310766030a648fdf0e407b2c91a39c1Stefan Richter list_del(&client->link); 145697811e347310766030a648fdf0e407b2c91a39c1Stefan Richter mutex_unlock(&client->device->client_list_mutex); 145797811e347310766030a648fdf0e407b2c91a39c1Stefan Richter 145819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg if (client->iso_context) 145919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg fw_iso_context_destroy(client->iso_context); 146019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 146136a755cfc398fc50abc74055d4478c1b067dac55Stefan Richter if (client->buffer.pages) 146236a755cfc398fc50abc74055d4478c1b067dac55Stefan Richter fw_iso_buffer_destroy(&client->buffer, client->device->card); 146336a755cfc398fc50abc74055d4478c1b067dac55Stefan Richter 146445ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason /* Freeze client->resource_idr and client->event_list */ 14653ba949868a6dc082b24cba5c3bf3f50de7391433Stefan Richter spin_lock_irq(&client->lock); 146645ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason client->in_shutdown = true; 14673ba949868a6dc082b24cba5c3bf3f50de7391433Stefan Richter spin_unlock_irq(&client->lock); 146866dea3e5f69abfdfa46b091ea117e497758351e7Kristian Høgsberg 146945ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason idr_for_each(&client->resource_idr, shutdown_resource, client); 147045ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason idr_remove_all(&client->resource_idr); 147145ee3199eb3e4233b755a9bb353a0527a4c58b5fJay Fenlason idr_destroy(&client->resource_idr); 147228cf6a04c82857d562968dc3a8a89726e6ac3dcbKristian Høgsberg 1473e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter list_for_each_entry_safe(event, next_event, &client->event_list, link) 1474e21fcf798e246202d7b60e864f1d7302ebaaf41cStefan Richter kfree(event); 147519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 1476fb4430367b0bbee2420132faf16c7c762a39c0bbStefan Richter client_put(client); 147719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 147819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg return 0; 147919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 148019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 148119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsbergstatic unsigned int fw_device_op_poll(struct file *file, poll_table * pt) 148219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg{ 148319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg struct client *client = file->private_data; 14842603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg unsigned int mask = 0; 148519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 148619a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg poll_wait(file, &client->wait, pt); 148719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 14882603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg if (fw_device_is_shutdown(client->device)) 14892603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg mask |= POLLHUP | POLLERR; 149019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg if (!list_empty(&client->event_list)) 14912603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg mask |= POLLIN | POLLRDNORM; 14922603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg 14932603bf219e9bef3396b96b65326de7db27958c95Kristian Høgsberg return mask; 149419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg} 149519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 149621ebcd1224d05c8673053e1e93ab9ec7ef3e0b84Stefan Richterconst struct file_operations fw_device_ops = { 149719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg .owner = THIS_MODULE, 149819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg .open = fw_device_op_open, 149919a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg .read = fw_device_op_read, 150019a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg .unlocked_ioctl = fw_device_op_ioctl, 150119a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg .poll = fw_device_op_poll, 150219a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg .release = fw_device_op_release, 150319a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg .mmap = fw_device_op_mmap, 150419a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg 150519a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg#ifdef CONFIG_COMPAT 15065af4e5eab30d481f76b89a2167c873dfad960acbStefan Richter .compat_ioctl = fw_device_op_compat_ioctl, 150719a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg#endif 150819a15b937b26638933307bb02f7b1801310d6eb2Kristian Høgsberg}; 1509