/*------------------------------------------------------------------------------------------*\ * * Copyright (C) 2006 AVM GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \*------------------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include /*--- #include ---*/ #include #include #include #include #include #include #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) #include #endif/*--- #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) ---*/ #include "debug.h" #include #include #include "appl.h" #include "host.h" #include "capi_oslib.h" #include "local_capi.h" #include "capi_pipe.h" #include #include "zugriff.h" /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ /*--- MODULE_DESCRIPTION("AVM Central Event distribution"); ---*/ /*--- MODULE_LICENSE("\n(C) Copyright 2004, AVM\n"); ---*/ static struct _capi_oslib capi_oslib; /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static int capi_oslib_open(struct inode *, struct file *); static int capi_oslib_close(struct inode *, struct file *); static int capi_oslib_fasync(int, struct file *, int); static ssize_t capi_oslib_write(struct file *, const char *, size_t , loff_t *); static ssize_t capi_oslib_read(struct file *, char *, size_t , loff_t *); void capi_oslib_cleanup(void); int capi_oslib_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long args); static unsigned int capi_oslib_poll(struct file *filp, poll_table *wait); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int capi_oslib_capi_register(struct _capi_oslib_open_data *open_data, unsigned char *Buffer, unsigned int BufferSize, unsigned int MessageBufferSize, unsigned int MaxNCCIs, unsigned int WindowSize, unsigned int B3BlockSize); static int capi_oslib_capi_release(struct _capi_oslib_open_data *open_data); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct semaphore capi_oslib_sema; unsigned long long capi_oslib_source_mask; spinlock_t capi_oslib_lock = SPIN_LOCK_UNLOCKED; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct file_operations capi_oslib_fops = { owner: THIS_MODULE, open: capi_oslib_open, release: capi_oslib_close, read: capi_oslib_read, write: capi_oslib_write, ioctl: capi_oslib_ioctl, fasync: capi_oslib_fasync, poll: capi_oslib_poll, }; #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) #define CAPIOSLIB_UDEV #endif/*--- #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) ---*/ /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int __init capi_oslib_file_init(void) { int reason; DEB_INFO("[capi_oslib_file_init] register_chrdev_region()\n"); capi_oslib.device = MKDEV(68, 0); /* CAPI !!! */ reason = register_chrdev_region(capi_oslib.device, 1, "capi_oslib"); if(reason) { DEB_ERR("[capi_oslib] register_chrdev_region failed: reason %d!\n", reason); return -ERESTARTSYS; } capi_oslib.cdev = cdev_alloc(); if (!capi_oslib.cdev) { unregister_chrdev_region(capi_oslib.device, 1); DEB_ERR("[capi_oslib] cdev_alloc failed!\n"); return -ERESTARTSYS; } capi_oslib.cdev->owner = capi_oslib_fops.owner; capi_oslib.cdev->ops = &capi_oslib_fops; kobject_set_name(&(capi_oslib.cdev->kobj), "capi_oslib"); spin_lock_init(&capi_oslib_lock); /*--------------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------------*/ sema_init(&capi_oslib_sema, 1); /* TODO: weitere initialisierungen */ if(cdev_add(capi_oslib.cdev, capi_oslib.device, 1)) { kobject_put(&capi_oslib.cdev->kobj); unregister_chrdev_region(capi_oslib.device, 1); DEB_ERR("[capi_oslib] cdev_add failed!\n"); return -ERESTARTSYS; } #if defined(CAPIOSLIB_UDEV) /*--- Geraetedatei anlegen: ---*/ capi_oslib.osclass = class_create(THIS_MODULE, "capi_oslib"); device_create(capi_oslib.osclass, NULL, 1, NULL, "%s%d", "capi", 0); #endif/*--- #if defined(CAPIOSLIB_UDEV) ---*/ return 0; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ #if defined(CONFIG_CAPI_OSLIB_MODULE) void capi_oslib_file_cleanup(void) { DEB_INFO("[%s]: unregister_chrdev(%u)\n", "capi_oslib", capi_oslib.major); #if defined(CONFIG_AVM_PUSH_BUTTON) capi_oslib_push_button_deinit(); #endif /*--- #if defined(CONFIG_AVM_PUSH_BUTTON) ---*/ #if defined(CAPIOSLIB_UDEV) device_destroy(capi_oslib.osclass, 1); class_destroy(capi_oslib.osclass); #endif/*--- #if defined(CAPIOSLIB_UDEV) ---*/ /*--------------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------------*/ cdev_del(capi_oslib.cdev); /* Delete char device */ /* TODO: weitere de-initialisierungen */ unregister_chrdev_region(capi_oslib.device, 1); /*--------------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------------*/ return; } #endif /*--- #if defined(CONFIG_CAPI_OSLIB_MODULE) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void capi_oslib_file_activate(void) { HOST_INIT(SOURCE_DEV_CAPI, 25 /* max APPLs */, 100 /* max NCCIs */, 0 /* CAPI_INDEX */); HOST_INIT(SOURCE_PTR_CAPI, 25 /* max APPLs */, 100 /* max NCCIs */, 0 /* CAPI_INDEX */); capi_oslib.activated = 1; DEB_INFO("[capi_oslib_file_activate] activated\n"); } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static int capi_oslib_fasync(int fd, struct file *filp, int mode) { struct _capi_oslib_open_data *open_data = (struct _capi_oslib_open_data *)filp->private_data; DEB_INFO("[capi_oslib_fasync] capi_oslib_fasync:\n"); return fasync_helper(fd, filp, mode, &(open_data->fasync)); } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static unsigned int capi_oslib_poll(struct file *filp, poll_table *wait) { struct _capi_oslib_open_data *open_data = (struct _capi_oslib_open_data *)filp->private_data; unsigned int status = 0; if(open_data->ApplId == 0) /* nicht (mehr) registriet */ return 0; /*--- DEB_INFO("[poll] wait:\n"); ---*/ poll_wait (filp, &(open_data->wait_queue), wait); /* TODO: pruefen ob message anliegt */ if(open_data->ApplId) { status |= POLLOUT | POLLWRNORM; if(LOCAL_CAPI_GET_MESSAGE(open_data->mode, open_data->ApplId, NULL, CAPI_NO_SUSPEND)) status |= POLLIN | POLLRDNORM; } /*--- if(status) ---*/ #if 0 if(status) DEB_INFO("[poll]:%s%s (%s)\n", status & POLLIN ? " POLLIN" : "", status & POLLOUT ? " POLLOUT" : "", current->comm); #endif /*--- { ---*/ /*--- static int xxx = 0; ---*/ /*--- if((xxx++ & 0xFF) == 0) ---*/ /*--- printk("[poll] %s\n", current->comm); ---*/ /*--- } ---*/ return status; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static int capi_oslib_open(struct inode *inode __attribute__((unused)), struct file *filp) { struct _capi_oslib_open_data *open_data; DEB_INFO("capi_oslib_open\n"); /*-------------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------------*/ if(filp->f_flags & O_APPEND) { DEB_ERR("[%s]: capi_oslib_open: open O_APPEND not supported\n", "capi_oslib"); return -EFAULT; } /*-------------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------------*/ if(capi_oslib.activated == 0) { DEB_ERR("not jet activated\n"); return -EFAULT; } /*-------------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------------*/ if(down_interruptible(&capi_oslib_sema)) { DEB_ERR("down_interruptible() failed\n"); return -ERESTARTSYS; } /*-------------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------------*/ open_data = (struct _capi_oslib_open_data *)kmalloc(sizeof(struct _capi_oslib_open_data), GFP_KERNEL); if(!open_data) { DEB_ERR("%s: capi_oslib_open: open malloc failed\n", "capi_oslib"); up(&capi_oslib_sema); return -EFAULT; } memset(open_data, 0, sizeof(*open_data)); init_waitqueue_head (&(open_data->wait_queue)); open_data->pf_owner = &(filp->f_owner); filp->private_data = (void *)open_data; up(&capi_oslib_sema); DEB_INFO("[%s]: capi_oslib_open: open success flags=0x%x\n", "capi_oslib", filp->f_flags); return 0; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static int capi_oslib_close(struct inode *inode __attribute__((unused)), struct file *filp) { DEB_INFO("[%s]: capi_oslib_close:\n", "capi_oslib"); if(down_interruptible(&capi_oslib_sema)) { DEB_ERR("%s down_interruptible() failed\n", "capi_oslib"); return -ERESTARTSYS; } /*--- achtung auf ind wartende "gefreien" und warten bis alle fertig ---*/ if(filp->private_data) { struct _capi_oslib_open_data *open_data = (struct _capi_oslib_open_data *)filp->private_data; /* TODO: auswerten des close falls */ if(open_data->ApplId) capi_oslib_capi_release(open_data); capi_oslib_fasync(-1, filp, 0); /*--- remove this file from asynchonously notified filp ---*/ kfree(filp->private_data); filp->private_data = NULL; } up(&capi_oslib_sema); return 0; } /*------------------------------------------------------------------------------------------*\ * CapiTrace \*------------------------------------------------------------------------------------------*/ static ssize_t capi_oslib_write(struct file *filp, const char *write_buffer, size_t write_length, loff_t *write_pos __attribute__((unused))) { unsigned int status; unsigned char *data; /*--- unsigned int data_length; ---*/ struct _capi_oslib_open_data *open_data = (struct _capi_oslib_open_data *)filp->private_data; struct __attribute__ ((packed)) _capi_message_header *header = (struct __attribute__ ((packed)) _capi_message_header *)write_buffer; /*--- DEB_INFO("[write]: write_length = %u *write_pos = 0x%LX, (%s)\n", write_length, *write_pos, current->comm); ---*/ if(open_data->ApplId == 0) { DEB_ERR("[write] not registered\n"); open_data->last_error = ERR_IllegalApplId; return -EIO; } if(write_length < sizeof(struct __attribute__ ((packed)) _capi_message_header)) { DEB_ERR("%s: capi_oslib_write: write_lengh < %u\n", "capi_oslib_write", sizeof(struct __attribute__ ((packed)) _capi_message_header)); open_data->last_error = ERR_IllegalMessage; return -EIO; } if(sizeof(*header) != 8) DEB_ERR("[header] capi header should be %d is %d\n", 8, sizeof(*header)); #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) write_length -= copy_from_user(open_data->put_message_buffer, write_buffer, min(write_length, MAX_CAPI_MESSAGE_SIZE)); data = open_data->put_message_buffer; #else /*--- #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) ---*/ data = (unsigned char *)write_buffer; #endif /*--- #else ---*/ /*--- #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) ---*/ if(data == NULL) { DEB_ERR("[write] wrong message buffer\n"); open_data->last_error = ERR_OS_Resource; return -EIO; } if(down_interruptible(&capi_oslib_sema)) { DEB_ERR("%s down_interruptible() failed\n", "capi_oslib_write"); open_data->last_error = ERR_OS_Resource; return -ERESTARTSYS; } /*--------------------------------------------------------------------------------------*\ * AUSWERTEN der WRITE DATA CAPI Header ist gelesen \*--------------------------------------------------------------------------------------*/ copy_word_to_le_unaligned((unsigned char *)&(header->ApplId), open_data->ApplId); /*--- DEB_INFO("[write] %s\n", CAPI_MESSAGE_NAME(header->Command, header->SubCommand)); ---*/ if(open_data->mode == SOURCE_PTR_CAPI) capi_oslib_map_addr(open_data, (void *)data); if(open_data->mode == SOURCE_DEV_CAPI) { struct __attribute__ ((packed)) _capi_message *C = (struct __attribute__ ((packed)) _capi_message *)data; if(CA_IS_DATA_B3_REQ(data)) { unsigned int b3datalen = copy_word_from_le_aligned((unsigned char *)&C->capi_message_part.data_b3_req.DataLen); unsigned char *b3data = LOCAL_CAPI_NEW_DATA_B3_REQ_BUFFER(open_data->mode, open_data->ApplId, copy_dword_from_le_aligned((unsigned char *)&C->capi_message_part.data_b3_req.NCCI)); if(b3data == NULL) { DEB_ERR("[write] data b3 buffer overflow\n"); open_data->last_error = ERR_MessageLost; up(&capi_oslib_sema); return -EIO; } #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) if(b3datalen > sizeof(open_data->put_message_buffer) - copy_word_from_le_aligned((unsigned char *)&C->capi_message_header.Length) ) #else /*--- #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) ---*/ if(b3datalen > open_data->AllocB3BlockSize) #endif /*--- #else ---*/ /*--- #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) ---*/ { DEB_ERR("[write] data b3 buffer too small\n"); open_data->last_error = ERR_MessageLost; up(&capi_oslib_sema); return -EIO; } if (copy_from_user(b3data, data + copy_word_from_le_aligned((unsigned char *)&header->Length), b3datalen)) { DEB_ERR("[write] copy_from_user failed\n"); open_data->last_error = ERR_MessageLost; up(&capi_oslib_sema); return -EIO; } copy_dword_to_le_aligned((unsigned char *)&C->capi_message_part.data_b3_req.Data, (unsigned int)b3data); /*--- DEB_INFO("[b3_req] len=%u h=0x%x\n", b3datalen, C->capi_message_part.data_b3_req.Handle); ---*/ /*--- } else if(CA_IS_DATA_B3_RESP(data)) { ---*/ /*--- DEB_INFO("[b3_resp] h=0x%x\n", copy_word_from_le_aligned((unsigned char *)&C->capi_message_part.data_b3_resp.Handle)); ---*/ } } status = LOCAL_CAPI_PUT_MESSAGE(open_data->mode, open_data->ApplId, (unsigned char *)data); up(&capi_oslib_sema); if(status) { DEB_ERR("CAPI_PUT_MESSAGE failed error 0x%x\n", status); open_data->last_error = status; return -EIO; } return write_length; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static ssize_t capi_oslib_read(struct file *filp, char *read_buffer, size_t max_read_length, loff_t *read_pos) { int status; unsigned int copy_length = 0; unsigned int rx_buffer_length = 0; struct _capi_oslib_open_data *open_data = (struct _capi_oslib_open_data *)filp->private_data; struct __attribute__ ((packed)) _capi_message *M; #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) unsigned char *rx_buffer = open_data->get_message_buffer; #else /*--- #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) ---*/ unsigned char *rx_buffer = read_buffer; #endif /*--- #else ---*/ /*--- #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) ---*/ /*--- DEB_INFO("capi_oslib_read: (%s)\n", current->comm); ---*/ if(open_data->ApplId == 0) { DEB_ERR("[read] not registered\n"); return capi_oslib_dump_open_data(filp, read_buffer, max_read_length, read_pos); /*--- return -EFAULT; ---*/ } capi_oslib_read_retry: if(down_interruptible(&capi_oslib_sema)) { DEB_ERR("[read] down_interruptible() failed\n"); return -ERESTARTSYS; } /*--------------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------------*/ status = LOCAL_CAPI_GET_MESSAGE(open_data->mode, open_data->ApplId, (unsigned char **)&rx_buffer, CAPI_NO_SUSPEND); switch(status) { case ERR_QueueEmpty: rx_buffer_length = 0; break; case 0: M = (struct __attribute__ ((packed)) _capi_message *)(rx_buffer); rx_buffer_length = copy_word_from_le_unaligned((unsigned char *)&(M->capi_message_header.Length)); /*--- printk(KERN_ERR "[read] rx_buffer 0x%x 0x%x rx_buffer_length = 0x%x\n", rx_buffer[0], rx_buffer[1], rx_buffer_length); ---*/ if(open_data->mode == SOURCE_PTR_CAPI) capi_oslib_map_addr(open_data, rx_buffer); if(open_data->mode == SOURCE_DEV_CAPI) { struct __attribute__ ((packed)) _capi_message *C = (struct __attribute__ ((packed)) _capi_message *)rx_buffer; if(CA_IS_DATA_B3_IND(rx_buffer)) { unsigned char *data = (unsigned char *)copy_dword_from_le_aligned((unsigned char *)&C->capi_message_part.data_b3_ind.Data); /*--- unsigned char *data = C->capi_message_part.data_b3_ind.Data; ---*/ unsigned int datalen = copy_word_from_le_aligned((unsigned char *)&C->capi_message_part.data_b3_ind.DataLen); /*--- DEB_INFO("[b3_ind] data=0x%x len=%u h=0x%x\n", data, datalen, copy_word_from_le_aligned((unsigned char *)&C->capi_message_part.data_b3_ind.Handle)); ---*/ #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) if(rx_buffer_length + datalen <= sizeof(open_data->get_message_buffer)) #else /*--- #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) ---*/ if(rx_buffer_length + datalen <= max_read_length) #endif /*--- #else ---*/ /*--- #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) ---*/ { memcpy(rx_buffer + rx_buffer_length, data, datalen); rx_buffer_length += datalen; } else { DEB_ERR("[read] buffer too short\n"); open_data->last_error = ERR_MessageToSmall; up(&capi_oslib_sema); return -EIO; } } else if(CA_IS_DATA_B3_CONF(rx_buffer)) { /*--- DEB_INFO("[b3_conf] h=0x%x\n", copy_word_from_le_aligned((unsigned char *)&C->capi_message_part.data_b3_conf.Handle)); ---*/ } } /*--- DEB_INFO("[read] %s\n", CAPI_MESSAGE_NAME(M->capi_message_header.Command, M->capi_message_header.SubCommand)); ---*/ break; default: open_data->last_error = status; up(&capi_oslib_sema); return -EIO; } /*--------------------------------------------------------------------------------------*\ * sind überhaupt Daten vorhanden \*--------------------------------------------------------------------------------------*/ if(rx_buffer_length) { /*--- DEB_INFO("[read] rx_buffer_length = %u *read_pos = %Lu\n", rx_buffer_length, *read_pos); ---*/ copy_length = rx_buffer_length; if(copy_length > max_read_length) { DEB_ERR("read_buffer to small\n"); copy_length = max_read_length; } /*--------------------------------------------------------------------------------------*\ * sind wir bloekierend, nein \*--------------------------------------------------------------------------------------*/ } else if(filp->f_flags & O_NONBLOCK) { up(&capi_oslib_sema); /*--- DEB_INFO("[read] non block, empty\n"); ---*/ /*--- { ---*/ /*--- static int xxx = 0; ---*/ /*--- if((xxx++ & 0xFF) == 0) ---*/ /*--- printk("[read] empty %s\n", current->comm); ---*/ /*--- } ---*/ return -EAGAIN; /*--------------------------------------------------------------------------------------*\ * sind wir bloekierend, ja \*--------------------------------------------------------------------------------------*/ } else { up(&capi_oslib_sema); DEB_INFO("[read] sleep on\n"); if(wait_event_interruptible(open_data->wait_queue, open_data->read_pipe->WritePos == open_data->read_pipe->ReadPos)) { DEB_INFO("[%s] handle released\n", "capi_oslib_read"); return -ERESTARTSYS; } DEB_INFO("[read] wake up\n"); goto capi_oslib_read_retry; } #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) if(copy_to_user(read_buffer, rx_buffer, copy_length)) { up(&capi_oslib_sema); DEB_ERR("%s: capi_read: copy_to_user failed\n", "capi_oslib_read"); return -EFAULT; } #endif /*--- #if defined(CAPI_OSLIB_USE_LOCAL_BUFFERS) ---*/ *read_pos = (loff_t)0; up(&capi_oslib_sema); return copy_length; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int capi_oslib_capi_register(struct _capi_oslib_open_data *open_data, unsigned char *Buffer, unsigned int BufferSize, unsigned int MessageBufferSize, unsigned int MaxNCCIs, unsigned int WindowSize, unsigned int B3BlockSize) { unsigned int status; if(open_data->ApplId) { DEB_ERR("already registered (ApplId=%u) !\n", open_data->ApplId); return ERR_ResourceError; } reregister: status = LOCAL_CAPI_REGISTER(open_data->mode, MessageBufferSize, MaxNCCIs, WindowSize, B3BlockSize, &(open_data->ApplId)); if((status == ERR_NoError) && (open_data->mode == SOURCE_PTR_CAPI)) { if(capi_oslib_register_user_space_blocks(open_data, Buffer, BufferSize, MaxNCCIs, WindowSize, B3BlockSize)) { DEB_WARN("[register] change from SOURCE_PTR_CAPI to SOURCE_DEV_CAPI mode\n"); LOCAL_CAPI_RELEASE(open_data->mode, open_data->ApplId); open_data->mode = SOURCE_DEV_CAPI; goto reregister; } } open_data->read_pipe = LOCAL_CAPI_GET_MESSAGE_WAIT_QUEUE(open_data->mode, open_data->ApplId, &(open_data->wait_queue), NULL); open_data->B3BlockSize = B3BlockSize; open_data->B3WindowSize = WindowSize; open_data->MaxNCCIs = MaxNCCIs; open_data->MessageBufferSize = MessageBufferSize; open_data->AllocB3BlockSize = max((unsigned int)B3BlockSize, (unsigned int)B3_DATA_ALLOC_SIZE); capi_oslib_register_open_data(open_data); DEB_INFO("[register] ApplId=%u status=0x%x (%s)\n", open_data->ApplId, status, current->comm); return status; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int capi_oslib_capi_release(struct _capi_oslib_open_data *open_data) { unsigned int status; capi_oslib_release_open_data(open_data); DEB_INFO("[close] ApplId=%d\n", open_data->ApplId); status = LOCAL_CAPI_RELEASE(open_data->mode, open_data->ApplId); open_data->mode = SOURCE_UNKNOWN; return status; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int capi_oslib_ioctl(struct inode *inode __attribute__((unused)), struct file *filp, unsigned int cmd, unsigned long args) { struct _capi_oslib_open_data *open_data = (struct _capi_oslib_open_data *)filp->private_data; int status = 0, ret = 0; capi_ioctl_struct capi_ioctl_struct; /*--- unsigned int dir = _IOC_DIR(cmd); ---*/ unsigned int type = _IOC_TYPE(cmd); unsigned int nr = _IOC_NR(cmd); unsigned int size = _IOC_SIZE(cmd); /*--- DEB_ERR("[ioctl] cmd: 0x%04x\n", cmd); ---*/ /*--- DEB_ERR("[ioctl] args: %d\n", args); ---*/ /*--- DEB_ERR("[ioctl] type: 0x%x\n", type); ---*/ /*--- DEB_ERR("[ioctl] nr: 0x%x\n", nr); ---*/ /*--- DEB_ERR("[ioctl] size: %d\n", size); ---*/ if(type != 'C') { DEB_ERR("[ioctl] type not 'C', was type %d, nr %d, size %d from %s\n", type, nr, size, current->comm); return -EFAULT; } if(size > sizeof(capi_ioctl_struct)) { DEB_ERR("[ioctl] size invalid, was %d from %s\n", size, current->comm); return -EFAULT; } switch(nr) { /*----------------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------------*/ case 0x01: /*--- #define CAPI_REGISTER _IOW('C',0x01,struct capi_register_params) ---*/ { capi_register_params *p_capi_register_params = &capi_ioctl_struct.rparams; struct _extended_register { unsigned char *b3_buffer; unsigned int b3_buffer_len; } *extended_register = (struct _extended_register *)(&p_capi_register_params[1]); unsigned int b3_buffer_len; unsigned char *b3_buffer; short *p_Error = &capi_ioctl_struct.errcode; if (args) { if(copy_from_user(&capi_ioctl_struct, (void *)args, size)) { DEB_ERR("[ioctl] %s:%d failed from %s\n", __func__, __LINE__, current->comm); return -EFAULT; } } else { DEB_ERR("[ioctl] args null for ioctl nr %d, size %d from %s\n", nr, size, current->comm); return -EFAULT; } DEB_INFO("[register] size=%u sizeof(capi_register_params)=%u sizeof(struct _extended_register)=%u\n", size, sizeof(capi_register_params), sizeof(struct _extended_register)); if(size < sizeof(capi_register_params) + sizeof(struct _extended_register)) { b3_buffer = NULL; b3_buffer_len = 0; open_data->mode = SOURCE_DEV_CAPI; DEB_WARN("no user space b3_buffer\n"); } else { b3_buffer = extended_register->b3_buffer; b3_buffer_len = extended_register->b3_buffer_len; open_data->mode = SOURCE_PTR_CAPI; DEB_INFO("user space b3_buffer = 0x%p len=%u\n", b3_buffer, b3_buffer_len); if(b3_buffer_len == 0) { open_data->last_error = ERR_OS_Resource; DEB_ERR("[capi_register] failed status=%d no user space buffer length\n", status); return -EIO; } else { int Len; Len = capi_oslib_get_data_b3_ind_buffer_size(p_capi_register_params->level3cnt, p_capi_register_params->datablklen, p_capi_register_params->datablkcnt); if(Len > (int)b3_buffer_len) { DEB_ERR("[capi_register] failed user space buffer too small (should be %u is %u)\n", Len, b3_buffer_len); open_data->last_error = ERR_OS_Resource; return -EIO; } } } status = capi_oslib_capi_register(open_data, b3_buffer, b3_buffer_len, 1024 + (1024 * p_capi_register_params->level3cnt) /* MessageBufferSize */, p_capi_register_params->level3cnt /* MaxNCCIs */, p_capi_register_params->datablkcnt /* WindowSize */, p_capi_register_params->datablklen /* B3BlockSize */); size = 0; if(status) { open_data->last_error = status; DEB_ERR("capi_register failed status=%d\n", status); return -EIO; } *p_Error = status; size = sizeof(*p_Error); ret = open_data->ApplId; } break; case 0x06: /*--- #define CAPI_GET_MANUFACTURER _IOWR('C',0x06,int) ---*/ /* broken: wanted size 64 (CAPI_MANUFACTURER_LEN) */ { char *p_Manufacturer = (char *)&capi_ioctl_struct.manufacturer; if (args) { if(copy_from_user(&capi_ioctl_struct, (void *)args, size)) { DEB_ERR("[ioctl] %s:%d failed from %s\n", __func__, __LINE__, current->comm); return -EFAULT; } } else { DEB_ERR("[ioctl] args null for ioctl nr %d, size %d from %s\n", nr, size, current->comm); return -EFAULT; } CAPI_GET_MANUFACTURER(p_Manufacturer); size = strlen(p_Manufacturer); } break; case 0x07: /*--- #define CAPI_GET_VERSION _IOWR('C',0x07,struct capi_version) ---*/ { capi_version *p_capi_version = &capi_ioctl_struct.version; if (args) { if(copy_from_user(&capi_ioctl_struct, (void *)args, size)) { DEB_ERR("[ioctl] %s:%d failed from %s\n", __func__, __LINE__, current->comm); return -EFAULT; } } else { DEB_ERR("[ioctl] args null for ioctl nr %d, size %d from %s\n", nr, size, current->comm); return -EFAULT; } status = CAPI_GET_VERSION( &p_capi_version->majorversion, &p_capi_version->minorversion, &p_capi_version->majormanuversion, &p_capi_version->minormanuversion); if(status) { open_data->last_error = status; DEB_ERR("capi_get_version failed status=%d\n", status); return -EIO; } size = sizeof(capi_version); } break; case 0x08: /*--- #define CAPI_GET_SERIAL _IOWR('C',0x08,int) ---*/ /* broken: wanted size 8 (CAPI_SERIAL_LEN) */ { char *p_Serial = (char *)&capi_ioctl_struct.serial; if (args) { if(copy_from_user(&capi_ioctl_struct, (void *)args, size)) { DEB_ERR("[ioctl] %s:%d failed from %s\n", __func__, __LINE__, current->comm); return -EFAULT; } } else { DEB_ERR("[ioctl] args null for ioctl nr %d, size %d from %s\n", nr, size, current->comm); return -EFAULT; } /*--- DEB_ERR("[getserial] %4B\n", p_Serial); ---*/ CAPI_GET_SERIAL_NUMBER(capi_ioctl_struct.contr, p_Serial); size = strlen(p_Serial); /*--- DEB_ERR("[getserial] %*B\n", size, p_Serial); ---*/ } break; case 0x09: /*--- #define CAPI_GET_PROFILE _IOWR('C',0x09,struct capi_profile) ---*/ { capi_profile *p_capi_profile = &capi_ioctl_struct.profile; unsigned char Buffer[64]; if (args) { if(copy_from_user(&capi_ioctl_struct, (void *)args, size)) { DEB_ERR("[ioctl] %s:%d failed from %s\n", __func__, __LINE__, current->comm); return -EFAULT; } } else { DEB_ERR("[ioctl] args null for ioctl nr %d, size %d from %s\n", nr, size, current->comm); return -EFAULT; } /*--- DEB_ERR("[getprofile]Cntrl=%d '%*B' %p %p\n", capi_ioctl_struct.contr, size, &capi_ioctl_struct, &capi_ioctl_struct, &capi_ioctl_struct.contr); ---*/ size = 0; status = CAPI_GET_PROFILE(Buffer, capi_ioctl_struct.contr); if(status == 0) { if(capi_ioctl_struct.contr == 0) size = sizeof(unsigned int); else size = sizeof(capi_profile); memcpy(p_capi_profile, Buffer, size); } else { open_data->last_error = status; DEB_ERR("capi_get_profile failed status=%d\n", status); return -EIO; } /*--- DEB_ERR("[getprofile] '%*B'\n", size, p_capi_profile); ---*/ } break; case 0x20: /*--- #define CAPI_MANUFACTURER_CMD _IOWR('C',0x20, struct capi_manufacturer_cmd) ---*/ { /*--- capi_manufacturer_cmd *p_capi_manufacturer_cmd = &capi_ioctl_struct.cmd; ---*/ size = 0; open_data->last_error = 0; DEB_ERR("capi_get_manufacturer_cmd failed status=%d\n", status); return -EIO; } break; /*----------------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------------*/ case 0x21: /*--- #define CAPI_GET_ERRCODE _IOR('C',0x21, __u16) ---*/ { short *p_Error = &capi_ioctl_struct.errcode; if (args) { if(copy_from_user(&capi_ioctl_struct, (void *)args, size)) { DEB_ERR("[ioctl] %s:%d failed from %s\n", __func__, __LINE__, current->comm); return -EFAULT; } } else { DEB_ERR("[ioctl] args null for ioctl nr %d, size %d from %s\n", nr, size, current->comm); return -EFAULT; } copy_word_to_le_unaligned ((unsigned char *)p_Error, open_data->last_error); open_data->last_error = 0; DEB_INFO("collect last error=%d\n", open_data->last_error); size = sizeof(*p_Error); } break; /*----------------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------------*/ case 0x22: /*--- #define CAPI_INSTALLED _IOR('C',0x22, __u16) ---*/ { size = 0; DEB_ERR("capi_installed\n"); #if 0 if(capi_ioctl_struct.contr == 0) { unsigned int controller; status = ERR_IllegalController; for(controller = 1 ; controller <= capi_oslib_stack->controllers ; controller++) { if(CAPI_INSTALLED(capi_ioctl_struct.contr) == ERR_NoError) { status = 0; break; } } } else { status = CAPI_INSTALLED(capi_ioctl_struct.contr); } #else status = CAPI_INSTALLED(0); #endif if (status != ERR_NoError) { open_data->last_error = status; DEB_ERR("capi_installed failed status=%d\n", status); return -EIO; } } break; case 0x23: /*--- #define CAPI_GET_FLAGS _IOR('C',0x23, unsigned) ---*/ case 0x24: /*--- #define CAPI_SET_FLAGS _IOR('C',0x24, unsigned) ---*/ case 0x25: /*--- #define CAPI_CLR_FLAGS _IOR('C',0x25, unsigned) ---*/ case 0x26: /*--- #define CAPI_NCCI_OPENCOUNT _IOR('C',0x26, unsigned) ---*/ case 0x27: /*--- #define CAPI_NCCI_GETUNIT _IOR('C',0x27, unsigned) ---*/ default: size = 0; DEB_ERR("[ioctl] nr 0x%x not supported\n", nr); return -EFAULT; } if(size) { if(copy_to_user((void *)args, &capi_ioctl_struct, size)) { DEB_ERR("[ioctl] %s:%d failed from %s\n", __func__, __LINE__, current->comm); ret = -EFAULT; } } return ret; }