📄 seq_clientmgr.c
字号:
/* * query next client */static int snd_seq_ioctl_query_next_client(client_t *client, void __user *arg){ client_t *cptr = NULL; snd_seq_client_info_t info; if (copy_from_user(&info, arg, sizeof(info))) return -EFAULT; /* search for next client */ info.client++; if (info.client < 0) info.client = 0; for (; info.client < SNDRV_SEQ_MAX_CLIENTS; info.client++) { cptr = snd_seq_client_use_ptr(info.client); if (cptr) break; /* found */ } if (cptr == NULL) return -ENOENT; get_client_info(cptr, &info); snd_seq_client_unlock(cptr); if (copy_to_user(arg, &info, sizeof(info))) return -EFAULT; return 0;}/* * query next port */static int snd_seq_ioctl_query_next_port(client_t *client, void __user *arg){ client_t *cptr; client_port_t *port = NULL; snd_seq_port_info_t info; if (copy_from_user(&info, arg, sizeof(info))) return -EFAULT; cptr = snd_seq_client_use_ptr(info.addr.client); if (cptr == NULL) return -ENXIO; /* search for next port */ info.addr.port++; port = snd_seq_port_query_nearest(cptr, &info); if (port == NULL) { snd_seq_client_unlock(cptr); return -ENOENT; } /* get port info */ info.addr = port->addr; snd_seq_get_port_info(port, &info); snd_seq_port_unlock(port); snd_seq_client_unlock(cptr); if (copy_to_user(arg, &info, sizeof(info))) return -EFAULT; return 0;}/* -------------------------------------------------------- */static struct seq_ioctl_table { unsigned int cmd; int (*func)(client_t *client, void __user * arg);} ioctl_tables[] = { { SNDRV_SEQ_IOCTL_SYSTEM_INFO, snd_seq_ioctl_system_info }, { SNDRV_SEQ_IOCTL_RUNNING_MODE, snd_seq_ioctl_running_mode }, { SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, snd_seq_ioctl_get_client_info }, { SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, snd_seq_ioctl_set_client_info }, { SNDRV_SEQ_IOCTL_CREATE_PORT, snd_seq_ioctl_create_port }, { SNDRV_SEQ_IOCTL_DELETE_PORT, snd_seq_ioctl_delete_port }, { SNDRV_SEQ_IOCTL_GET_PORT_INFO, snd_seq_ioctl_get_port_info }, { SNDRV_SEQ_IOCTL_SET_PORT_INFO, snd_seq_ioctl_set_port_info }, { SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, snd_seq_ioctl_subscribe_port }, { SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, snd_seq_ioctl_unsubscribe_port }, { SNDRV_SEQ_IOCTL_CREATE_QUEUE, snd_seq_ioctl_create_queue }, { SNDRV_SEQ_IOCTL_DELETE_QUEUE, snd_seq_ioctl_delete_queue }, { SNDRV_SEQ_IOCTL_GET_QUEUE_INFO, snd_seq_ioctl_get_queue_info }, { SNDRV_SEQ_IOCTL_SET_QUEUE_INFO, snd_seq_ioctl_set_queue_info }, { SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE, snd_seq_ioctl_get_named_queue }, { SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS, snd_seq_ioctl_get_queue_status }, { SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO, snd_seq_ioctl_get_queue_tempo }, { SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, snd_seq_ioctl_set_queue_tempo }, { SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER, snd_seq_ioctl_get_queue_timer }, { SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER, snd_seq_ioctl_set_queue_timer }, { SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT, snd_seq_ioctl_get_queue_client }, { SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT, snd_seq_ioctl_set_queue_client }, { SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, snd_seq_ioctl_get_client_pool }, { SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, snd_seq_ioctl_set_client_pool }, { SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION, snd_seq_ioctl_get_subscription }, { SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, snd_seq_ioctl_query_next_client }, { SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, snd_seq_ioctl_query_next_port }, { SNDRV_SEQ_IOCTL_REMOVE_EVENTS, snd_seq_ioctl_remove_events }, { SNDRV_SEQ_IOCTL_QUERY_SUBS, snd_seq_ioctl_query_subs }, { 0, NULL },};static int snd_seq_do_ioctl(client_t *client, unsigned int cmd, void __user *arg){ struct seq_ioctl_table *p; switch (cmd) { case SNDRV_SEQ_IOCTL_PVERSION: /* return sequencer version number */ return put_user(SNDRV_SEQ_VERSION, (int __user *)arg) ? -EFAULT : 0; case SNDRV_SEQ_IOCTL_CLIENT_ID: /* return the id of this client */ return put_user(client->number, (int __user *)arg) ? -EFAULT : 0; } if (! arg) return -EFAULT; for (p = ioctl_tables; p->cmd; p++) { if (p->cmd == cmd) return p->func(client, arg); } snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%2x)\n", cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); return -ENOTTY;}static int snd_seq_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ client_t *client = (client_t *) file->private_data; int err; snd_assert(client != NULL, return -ENXIO); /* FIXME: need to unlock BKL to allow preemption */ unlock_kernel(); err = snd_seq_do_ioctl(client, cmd, (void __user *) arg); lock_kernel(); return err;}/* -------------------------------------------------------- *//* exported to kernel modules */int snd_seq_create_kernel_client(snd_card_t *card, int client_index, snd_seq_client_callback_t * callback){ client_t *client; snd_assert(! in_interrupt(), return -EBUSY); if (callback == NULL) return -EINVAL; if (card && client_index > 7) return -EINVAL; if (card == NULL && client_index > 63) return -EINVAL; if (card) client_index += 64 + (card->number << 3); if (down_interruptible(®ister_mutex)) return -ERESTARTSYS; /* empty write queue as default */ client = seq_create_client1(client_index, 0); if (client == NULL) { up(®ister_mutex); return -EBUSY; /* failure code */ } usage_alloc(&client_usage, 1); client->accept_input = callback->allow_output; client->accept_output = callback->allow_input; /* fill client data */ client->data.kernel.card = card; client->data.kernel.private_data = callback->private_data; sprintf(client->name, "Client-%d", client->number); client->type = KERNEL_CLIENT; up(®ister_mutex); /* make others aware this new client */ snd_seq_system_client_ev_client_start(client->number); /* return client number to caller */ return client->number;}/* exported to kernel modules */int snd_seq_delete_kernel_client(int client){ client_t *ptr; snd_assert(! in_interrupt(), return -EBUSY); ptr = clientptr(client); if (ptr == NULL) return -EINVAL; seq_free_client(ptr); kfree(ptr); return 0;}/* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue * and snd_seq_kernel_client_enqueue_blocking */static int kernel_client_enqueue(int client, snd_seq_event_t *ev, struct file *file, int blocking, int atomic, int hop){ client_t *cptr; int result; snd_assert(ev != NULL, return -EINVAL); if (ev->type == SNDRV_SEQ_EVENT_NONE) return 0; /* ignore this */ if (ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR) return -EINVAL; /* quoted events can't be enqueued */ /* fill in client number */ ev->source.client = client; if (check_event_type_and_length(ev)) return -EINVAL; cptr = snd_seq_client_use_ptr(client); if (cptr == NULL) return -EINVAL; if (! cptr->accept_output) result = -EPERM; else /* send it */ result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, atomic, hop); snd_seq_client_unlock(cptr); return result;}/* * exported, called by kernel clients to enqueue events (w/o blocking) * * RETURN VALUE: zero if succeed, negative if error */int snd_seq_kernel_client_enqueue(int client, snd_seq_event_t * ev, int atomic, int hop){ return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop);}/* * exported, called by kernel clients to enqueue events (with blocking) * * RETURN VALUE: zero if succeed, negative if error */int snd_seq_kernel_client_enqueue_blocking(int client, snd_seq_event_t * ev, struct file *file, int atomic, int hop){ return kernel_client_enqueue(client, ev, file, 1, atomic, hop);}/* * exported, called by kernel clients to dispatch events directly to other * clients, bypassing the queues. Event time-stamp will be updated. * * RETURN VALUE: negative = delivery failed, * zero, or positive: the number of delivered events */int snd_seq_kernel_client_dispatch(int client, snd_seq_event_t * ev, int atomic, int hop){ client_t *cptr; int result; snd_assert(ev != NULL, return -EINVAL); /* fill in client number */ ev->queue = SNDRV_SEQ_QUEUE_DIRECT; ev->source.client = client; if (check_event_type_and_length(ev)) return -EINVAL; cptr = snd_seq_client_use_ptr(client); if (cptr == NULL) return -EINVAL; if (!cptr->accept_output) result = -EPERM; else result = snd_seq_deliver_event(cptr, ev, atomic, hop); snd_seq_client_unlock(cptr); return result;}/* * exported, called by kernel clients to perform same functions as with * userland ioctl() */int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg){ client_t *client; mm_segment_t fs; int result; client = clientptr(clientid); if (client == NULL) return -ENXIO; fs = snd_enter_user(); result = snd_seq_do_ioctl(client, cmd, arg); snd_leave_user(fs); return result;}/* exported (for OSS emulator) */int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait){ client_t *client; client = clientptr(clientid); if (client == NULL) return -ENXIO; if (! snd_seq_write_pool_allocated(client)) return 1; if (snd_seq_pool_poll_wait(client->pool, file, wait)) return 1; return 0;}/*---------------------------------------------------------------------------*//* * /proc interface */static void snd_seq_info_dump_subscribers(snd_info_buffer_t *buffer, port_subs_info_t *group, int is_src, char *msg){ struct list_head *p; subscribers_t *s; int count = 0; down_read(&group->list_mutex); if (list_empty(&group->list_head)) { up_read(&group->list_mutex); return; } snd_iprintf(buffer, msg); list_for_each(p, &group->list_head) { if (is_src) s = list_entry(p, subscribers_t, src_list); else s = list_entry(p, subscribers_t, dest_list); if (count++) snd_iprintf(buffer, ", "); snd_iprintf(buffer, "%d:%d", is_src ? s->info.dest.client : s->info.sender.client, is_src ? s->info.dest.port : s->info.sender.port); if (s->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) snd_iprintf(buffer, "[%c:%d]", ((s->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL) ? 'r' : 't'), s->info.queue); if (group->exclusive) snd_iprintf(buffer, "[ex]"); } up_read(&group->list_mutex); snd_iprintf(buffer, "\n");}#define FLAG_PERM_RD(perm) ((perm) & SNDRV_SEQ_PORT_CAP_READ ? ((perm) & SNDRV_SEQ_PORT_CAP_SUBS_READ ? 'R' : 'r') : '-')#define FLAG_PERM_WR(perm) ((perm) & SNDRV_SEQ_PORT_CAP_WRITE ? ((perm) & SNDRV_SEQ_PORT_CAP_SUBS_WRITE ? 'W' : 'w') : '-')#define FLAG_PERM_EX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_NO_EXPORT ? '-' : 'e')#define FLAG_PERM_DUPLEX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_DUPLEX ? 'X' : '-')static void snd_seq_info_dump_ports(snd_info_buffer_t *buffer, client_t *client){ struct list_head *l; down(&client->ports_mutex); list_for_each(l, &client->ports_list_head) { client_port_t *p = list_entry(l, client_port_t, list); snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n", p->addr.port, p->name, FLAG_PERM_RD(p->capability), FLAG_PERM_WR(p->capability), FLAG_PERM_EX(p->capability), FLAG_PERM_DUPLEX(p->capability)); snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, " Connecting To: "); snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, " Connected From: "); } up(&client->ports_mutex);}/* exported to seq_info.c */void snd_seq_info_clients_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer){ extern void snd_seq_info_pool(snd_info_buffer_t * buffer, pool_t * pool, char *space); int c; client_t *client; snd_iprintf(buffer, "Client info\n"); snd_iprintf(buffer, " cur clients : %d\n", client_usage.cur); snd_iprintf(buffer, " peak clients : %d\n", client_usage.peak); snd_iprintf(buffer, " max clients : %d\n", SNDRV_SEQ_MAX_CLIENTS); snd_iprintf(buffer, "\n"); /* list the client table */ for (c = 0; c < SNDRV_SEQ_MAX_CLIENTS; c++) { client = snd_seq_client_use_ptr(c); if (client == NULL) continue; if (client->type == NO_CLIENT) { snd_seq_client_unlock(client); continue; } snd_iprintf(buffer, "Client %3d : \"%s\" [%s]\n", c, client->name, client->type == USER_CLIENT ? "User" : "Kernel"); snd_seq_info_dump_ports(buffer, client); if (snd_seq_write_pool_allocated(client)) { snd_iprintf(buffer, " Output pool :\n"); snd_seq_info_pool(buffer, client->pool, " "); } if (client->type == USER_CLIENT && client->data.user.fifo && client->data.user.fifo->pool) { snd_iprintf(buffer, " Input pool :\n"); snd_seq_info_pool(buffer, client->data.user.fifo->pool, " "); } snd_seq_client_unlock(client); }}/*---------------------------------------------------------------------------*//* * REGISTRATION PART */static struct file_operations snd_seq_f_ops ={ .owner = THIS_MODULE, .read = snd_seq_read, .write = snd_seq_write, .open = snd_seq_open, .release = snd_seq_release, .poll = snd_seq_poll, .ioctl = snd_seq_ioctl,};static snd_minor_t snd_seq_reg ={ .comment = "sequencer", .f_ops = &snd_seq_f_ops,};/* * register sequencer device */int __init snd_sequencer_device_init(void){ int err; if (down_interruptible(®ister_mutex)) return -ERESTARTSYS; if ((err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0, &snd_seq_reg, "seq")) < 0) { up(®ister_mutex); return err; } up(®ister_mutex); return 0;}/* * unregister sequencer device */void __exit snd_sequencer_device_done(void){ snd_unregister_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -