1 #include <linux/cdev.h>
2 #include <linux/device.h>
4 #include <linux/list.h>
5 #include <linux/kernel.h>
6 #include <linux/module.h>
7 #include <linux/slab.h>
9 #include <linux/tapi/tapi.h>
10 #include <linux/tapi/tapi-ioctl.h>
12 /* FIXME Does it acutally make sense to allow more then one application at a
13 * time to open the control device? For example calling sync from one app will
14 * also sync all others. */
16 struct tapi_control_file
{
17 struct tapi_device
*tdev
;
18 struct list_head links
;
21 static struct tapi_endpoint
*tapi_lookup_endpoint(struct tapi_device
*tdev
,
24 struct tapi_stream
*stream
;
26 if (ep_id
< tdev
->num_ports
)
27 return &tdev
->ports
[ep_id
].ep
;
29 list_for_each_entry(stream
, &tdev
->streams
, head
) {
30 if (stream
->ep
.id
== ep_id
)
34 return ERR_PTR(-ENOENT
);
37 static inline struct tapi_device
*inode_to_tdev(struct inode
*inode
)
39 return container_of(inode
->i_cdev
, struct tapi_char_device
, cdev
)->tdev
;
42 static int tapi_control_open(struct inode
*inode
, struct file
*file
)
45 struct tapi_device
*tdev
= inode_to_tdev(inode
);
46 struct tapi_control_file
*tctrl
;
48 get_device(&tdev
->dev
);
50 tctrl
= kzalloc(sizeof(*tctrl
), GFP_KERNEL
);
56 INIT_LIST_HEAD(&tctrl
->links
);
59 file
->private_data
= tctrl
;
64 put_device(&tdev
->dev
);
69 static int tapi_control_release(struct inode
*inode
, struct file
*file
)
71 struct tapi_control_file
*tctrl
= file
->private_data
;
72 struct tapi_link
*link
;
75 list_for_each_entry(link
, &tctrl
->links
, head
)
76 tapi_link_free(tctrl
->tdev
, link
);
78 put_device(&tctrl
->tdev
->dev
);
84 static long tapi_control_ioctl_link_alloc(struct tapi_control_file
*tctrl
,
87 struct tapi_link
*link
;
88 struct tapi_endpoint
*ep1
, *ep2
;
90 ep1
= tapi_lookup_endpoint(tctrl
->tdev
, arg
>> 16);
91 ep2
= tapi_lookup_endpoint(tctrl
->tdev
, arg
& 0xffff);
93 link
= tapi_link_alloc(tctrl
->tdev
, ep1
, ep2
);
97 list_add_tail(&link
->head
, &tctrl
->links
);
102 struct tapi_link
*tapi_control_lookup_link(struct tapi_control_file
*tctrl
,
105 struct tapi_link
*link
;
107 list_for_each_entry(link
, &tctrl
->links
, head
) {
115 static long tapi_control_ioctl_link_free(struct tapi_control_file
*tctrl
,
118 struct tapi_link
*link
= tapi_control_lookup_link(tctrl
, arg
);
122 tapi_link_free(tctrl
->tdev
, link
);
123 list_del(&link
->head
);
128 static long tapi_control_ioctl_link_enable(struct tapi_control_file
*tctrl
,
131 struct tapi_link
*link
= tapi_control_lookup_link(tctrl
, arg
);
135 return tapi_link_enable(tctrl
->tdev
, link
);
138 static long tapi_control_ioctl_link_disable(struct tapi_control_file
*tctrl
,
141 struct tapi_link
*link
= tapi_control_lookup_link(tctrl
, arg
);
145 return tapi_link_disable(tctrl
->tdev
, link
);
148 static long tapi_control_ioctl_sync(struct tapi_control_file
*tctrl
)
150 return tapi_sync(tctrl
->tdev
);
153 static long tapi_control_ioctl(struct file
*file
, unsigned int cmd
,
157 struct tapi_control_file
*tctrl
= file
->private_data
;
160 case TAPI_CONTROL_IOCTL_LINK_ALLOC
:
161 ret
= tapi_control_ioctl_link_alloc(tctrl
, arg
);
163 case TAPI_CONTROL_IOCTL_LINK_FREE
:
164 ret
= tapi_control_ioctl_link_free(tctrl
, arg
);
166 case TAPI_CONTROL_IOCTL_LINK_ENABLE
:
167 ret
= tapi_control_ioctl_link_enable(tctrl
, arg
);
169 case TAPI_CONTROL_IOCTL_LINK_DISABLE
:
170 ret
= tapi_control_ioctl_link_disable(tctrl
, arg
);
172 case TAPI_CONTROL_IOCTL_SYNC
:
173 ret
= tapi_control_ioctl_sync(tctrl
);
182 static const struct file_operations tapi_control_file_ops
= {
183 .owner
= THIS_MODULE
,
184 .open
= tapi_control_open
,
185 .release
= tapi_control_release
,
186 .unlocked_ioctl
= tapi_control_ioctl
,
189 int tapi_register_control_device(struct tapi_device
* tdev
)
191 dev_set_name(&tdev
->control_dev
.dev
, "tapi%uC", tdev
->id
);
192 return tapi_char_device_register(tdev
, &tdev
->control_dev
, &tapi_control_file_ops
);