Lines Matching +full:comp +full:- +full:int

1 // SPDX-License-Identifier: GPL-2.0
3 * cdev.c - Character device component for Mostcore
5 * Copyright (C) 2013-2015 Microchip Technology Germany II GmbH & Co. KG
25 unsigned int major;
28 } comp; variable
38 unsigned int channel_id;
42 int access_ref;
52 return channel_has_mbo(c->iface, c->channel_id, &comp.cc) > 0; in ch_has_mbo()
57 if (!kfifo_peek(&c->fifo, mbo)) { in ch_get_mbo()
58 *mbo = most_get_mbo(c->iface, c->channel_id, &comp.cc); in ch_get_mbo()
60 kfifo_in(&c->fifo, mbo, 1); in ch_get_mbo()
65 static struct comp_channel *get_channel(struct most_interface *iface, int id) in get_channel()
72 if ((c->iface == iface) && (c->channel_id == id)) { in get_channel()
85 while (kfifo_out((struct kfifo *)&c->fifo, &mbo, 1)) in stop_channel()
87 most_stop_channel(c->iface, c->channel_id, &comp.cc); in stop_channel()
94 device_destroy(comp.class, c->devno); in destroy_cdev()
95 cdev_del(&c->cdev); in destroy_cdev()
97 list_del(&c->list); in destroy_cdev()
103 ida_free(&comp.minor_id, MINOR(c->devno)); in destroy_channel()
104 kfifo_free(&c->fifo); in destroy_channel()
109 * comp_open - implements the syscall to open the device
116 static int comp_open(struct inode *inode, struct file *filp) in comp_open()
119 int ret; in comp_open()
121 c = to_channel(inode->i_cdev); in comp_open()
122 filp->private_data = c; in comp_open()
124 if (((c->cfg->direction == MOST_CH_RX) && in comp_open()
125 ((filp->f_flags & O_ACCMODE) != O_RDONLY)) || in comp_open()
126 ((c->cfg->direction == MOST_CH_TX) && in comp_open()
127 ((filp->f_flags & O_ACCMODE) != O_WRONLY))) { in comp_open()
128 return -EACCES; in comp_open()
131 mutex_lock(&c->io_mutex); in comp_open()
132 if (!c->dev) { in comp_open()
133 mutex_unlock(&c->io_mutex); in comp_open()
134 return -ENODEV; in comp_open()
137 if (c->access_ref) { in comp_open()
138 mutex_unlock(&c->io_mutex); in comp_open()
139 return -EBUSY; in comp_open()
142 c->mbo_offs = 0; in comp_open()
143 ret = most_start_channel(c->iface, c->channel_id, &comp.cc); in comp_open()
145 c->access_ref = 1; in comp_open()
146 mutex_unlock(&c->io_mutex); in comp_open()
151 * comp_close - implements the syscall to close the device
157 static int comp_close(struct inode *inode, struct file *filp) in comp_close()
159 struct comp_channel *c = to_channel(inode->i_cdev); in comp_close()
161 mutex_lock(&c->io_mutex); in comp_close()
162 spin_lock(&c->unlink); in comp_close()
163 c->access_ref = 0; in comp_close()
164 spin_unlock(&c->unlink); in comp_close()
165 if (c->dev) { in comp_close()
167 mutex_unlock(&c->io_mutex); in comp_close()
169 mutex_unlock(&c->io_mutex); in comp_close()
176 * comp_write - implements the syscall to write to the device
185 int ret; in comp_write()
188 struct comp_channel *c = filp->private_data; in comp_write()
190 mutex_lock(&c->io_mutex); in comp_write()
191 while (c->dev && !ch_get_mbo(c, &mbo)) { in comp_write()
192 mutex_unlock(&c->io_mutex); in comp_write()
194 if ((filp->f_flags & O_NONBLOCK)) in comp_write()
195 return -EAGAIN; in comp_write()
196 if (wait_event_interruptible(c->wq, ch_has_mbo(c) || !c->dev)) in comp_write()
197 return -ERESTARTSYS; in comp_write()
198 mutex_lock(&c->io_mutex); in comp_write()
201 if (unlikely(!c->dev)) { in comp_write()
202 ret = -ENODEV; in comp_write()
206 to_copy = min(count, c->cfg->buffer_size - c->mbo_offs); in comp_write()
207 left = copy_from_user(mbo->virt_address + c->mbo_offs, buf, to_copy); in comp_write()
209 ret = -EFAULT; in comp_write()
213 c->mbo_offs += to_copy - left; in comp_write()
214 if (c->mbo_offs >= c->cfg->buffer_size || in comp_write()
215 c->cfg->data_type == MOST_CH_CONTROL || in comp_write()
216 c->cfg->data_type == MOST_CH_ASYNC) { in comp_write()
217 kfifo_skip(&c->fifo); in comp_write()
218 mbo->buffer_length = c->mbo_offs; in comp_write()
219 c->mbo_offs = 0; in comp_write()
223 ret = to_copy - left; in comp_write()
225 mutex_unlock(&c->io_mutex); in comp_write()
230 * comp_read - implements the syscall to read from the device
241 struct comp_channel *c = filp->private_data; in comp_read()
243 mutex_lock(&c->io_mutex); in comp_read()
244 while (c->dev && !kfifo_peek(&c->fifo, &mbo)) { in comp_read()
245 mutex_unlock(&c->io_mutex); in comp_read()
246 if (filp->f_flags & O_NONBLOCK) in comp_read()
247 return -EAGAIN; in comp_read()
248 if (wait_event_interruptible(c->wq, in comp_read()
249 (!kfifo_is_empty(&c->fifo) || in comp_read()
250 (!c->dev)))) in comp_read()
251 return -ERESTARTSYS; in comp_read()
252 mutex_lock(&c->io_mutex); in comp_read()
256 if (unlikely(!c->dev)) { in comp_read()
257 mutex_unlock(&c->io_mutex); in comp_read()
258 return -ENODEV; in comp_read()
263 mbo->processed_length - c->mbo_offs); in comp_read()
266 mbo->virt_address + c->mbo_offs, in comp_read()
269 copied = to_copy - not_copied; in comp_read()
271 c->mbo_offs += copied; in comp_read()
272 if (c->mbo_offs >= mbo->processed_length) { in comp_read()
273 kfifo_skip(&c->fifo); in comp_read()
275 c->mbo_offs = 0; in comp_read()
277 mutex_unlock(&c->io_mutex); in comp_read()
283 struct comp_channel *c = filp->private_data; in comp_poll()
286 poll_wait(filp, &c->wq, wait); in comp_poll()
288 mutex_lock(&c->io_mutex); in comp_poll()
289 if (c->cfg->direction == MOST_CH_RX) { in comp_poll()
290 if (!c->dev || !kfifo_is_empty(&c->fifo)) in comp_poll()
293 if (!c->dev || !kfifo_is_empty(&c->fifo) || ch_has_mbo(c)) in comp_poll()
296 mutex_unlock(&c->io_mutex); in comp_poll()
313 * comp_disconnect_channel - disconnect a channel
320 static int comp_disconnect_channel(struct most_interface *iface, int channel_id) in comp_disconnect_channel()
326 return -EINVAL; in comp_disconnect_channel()
328 mutex_lock(&c->io_mutex); in comp_disconnect_channel()
329 spin_lock(&c->unlink); in comp_disconnect_channel()
330 c->dev = NULL; in comp_disconnect_channel()
331 spin_unlock(&c->unlink); in comp_disconnect_channel()
333 if (c->access_ref) { in comp_disconnect_channel()
335 wake_up_interruptible(&c->wq); in comp_disconnect_channel()
336 mutex_unlock(&c->io_mutex); in comp_disconnect_channel()
338 mutex_unlock(&c->io_mutex); in comp_disconnect_channel()
345 * comp_rx_completion - completion handler for rx channels
351 static int comp_rx_completion(struct mbo *mbo) in comp_rx_completion()
356 return -EINVAL; in comp_rx_completion()
358 c = get_channel(mbo->ifp, mbo->hdm_channel_id); in comp_rx_completion()
360 return -EINVAL; in comp_rx_completion()
362 spin_lock(&c->unlink); in comp_rx_completion()
363 if (!c->access_ref || !c->dev) { in comp_rx_completion()
364 spin_unlock(&c->unlink); in comp_rx_completion()
365 return -ENODEV; in comp_rx_completion()
367 kfifo_in(&c->fifo, &mbo, 1); in comp_rx_completion()
368 spin_unlock(&c->unlink); in comp_rx_completion()
370 if (kfifo_is_full(&c->fifo)) in comp_rx_completion()
371 dev_warn(c->dev, "Fifo is full\n"); in comp_rx_completion()
373 wake_up_interruptible(&c->wq); in comp_rx_completion()
378 * comp_tx_completion - completion handler for tx channels
382 * This wakes sleeping processes in the wait-queue.
384 static int comp_tx_completion(struct most_interface *iface, int channel_id) in comp_tx_completion()
390 return -EINVAL; in comp_tx_completion()
392 if ((channel_id < 0) || (channel_id >= iface->num_channels)) { in comp_tx_completion()
393 dev_warn(c->dev, "Channel ID out of range\n"); in comp_tx_completion()
394 return -EINVAL; in comp_tx_completion()
397 wake_up_interruptible(&c->wq); in comp_tx_completion()
402 * comp_probe - probe function of the driver module
413 static int comp_probe(struct most_interface *iface, int channel_id, in comp_probe()
418 int retval; in comp_probe()
419 int current_minor; in comp_probe()
422 return -EINVAL; in comp_probe()
426 return -EEXIST; in comp_probe()
428 current_minor = ida_alloc(&comp.minor_id, GFP_KERNEL); in comp_probe()
434 retval = -ENOMEM; in comp_probe()
438 c->devno = MKDEV(comp.major, current_minor); in comp_probe()
439 cdev_init(&c->cdev, &channel_fops); in comp_probe()
440 c->cdev.owner = THIS_MODULE; in comp_probe()
441 retval = cdev_add(&c->cdev, c->devno, 1); in comp_probe()
444 c->iface = iface; in comp_probe()
445 c->cfg = cfg; in comp_probe()
446 c->channel_id = channel_id; in comp_probe()
447 c->access_ref = 0; in comp_probe()
448 spin_lock_init(&c->unlink); in comp_probe()
449 INIT_KFIFO(c->fifo); in comp_probe()
450 retval = kfifo_alloc(&c->fifo, cfg->num_buffers, GFP_KERNEL); in comp_probe()
453 init_waitqueue_head(&c->wq); in comp_probe()
454 mutex_init(&c->io_mutex); in comp_probe()
456 list_add_tail(&c->list, &channel_list); in comp_probe()
458 c->dev = device_create(comp.class, NULL, c->devno, NULL, "%s", name); in comp_probe()
460 if (IS_ERR(c->dev)) { in comp_probe()
461 retval = PTR_ERR(c->dev); in comp_probe()
464 kobject_uevent(&c->dev->kobj, KOBJ_ADD); in comp_probe()
468 kfifo_free(&c->fifo); in comp_probe()
469 list_del(&c->list); in comp_probe()
471 cdev_del(&c->cdev); in comp_probe()
475 ida_free(&comp.minor_id, current_minor); in comp_probe()
479 static struct cdev_component comp = { variable
490 static int __init most_cdev_init(void) in most_cdev_init()
492 int err; in most_cdev_init()
494 comp.class = class_create("most_cdev"); in most_cdev_init()
495 if (IS_ERR(comp.class)) in most_cdev_init()
496 return PTR_ERR(comp.class); in most_cdev_init()
498 ida_init(&comp.minor_id); in most_cdev_init()
500 err = alloc_chrdev_region(&comp.devno, 0, CHRDEV_REGION_SIZE, "cdev"); in most_cdev_init()
503 comp.major = MAJOR(comp.devno); in most_cdev_init()
504 err = most_register_component(&comp.cc); in most_cdev_init()
507 err = most_register_configfs_subsys(&comp.cc); in most_cdev_init()
513 most_deregister_component(&comp.cc); in most_cdev_init()
515 unregister_chrdev_region(comp.devno, CHRDEV_REGION_SIZE); in most_cdev_init()
517 ida_destroy(&comp.minor_id); in most_cdev_init()
518 class_destroy(comp.class); in most_cdev_init()
526 most_deregister_configfs_subsys(&comp.cc); in most_cdev_exit()
527 most_deregister_component(&comp.cc); in most_cdev_exit()
533 unregister_chrdev_region(comp.devno, CHRDEV_REGION_SIZE); in most_cdev_exit()
534 ida_destroy(&comp.minor_id); in most_cdev_exit()
535 class_destroy(comp.class); in most_cdev_exit()