linux-old/drivers/usb/auerchar.c
<<
>>
Prefs
   1/*****************************************************************************/
   2/*
   3 *      auerchar.c  --  Auerswald PBX/System Telephone character interface.
   4 *
   5 *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.de)
   6 *
   7 *      Very much code of this driver is borrowed from dabusb.c (Deti Fliegl)
   8 *      and from the USB Skeleton driver (Greg Kroah-Hartman). Thank you.
   9 *
  10 *      This program is free software; you can redistribute it and/or modify
  11 *      it under the terms of the GNU General Public License as published by
  12 *      the Free Software Foundation; either version 2 of the License, or
  13 *      (at your option) any later version.
  14 *
  15 *      This program is distributed in the hope that it will be useful,
  16 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 *      GNU General Public License for more details.
  19 *
  20 *      You should have received a copy of the GNU General Public License
  21 *      along with this program; if not, write to the Free Software
  22 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23 */
  24 /*****************************************************************************/
  25
  26#undef DEBUG                    /* include debug macros until it's done */
  27#include <linux/usb.h>
  28#include "auerchar.h"
  29#include "auermain.h"
  30#include <linux/slab.h>
  31#include <asm/uaccess.h>        /* user area access functions */
  32
  33/*-------------------------------------------------------------------*/
  34
  35/* wake up waiting readers */
  36static void auerchar_disconnect(struct auerscon *scp)
  37{
  38        struct auerchar *ccp =((struct auerchar *) ((char *) (scp) - (unsigned long) (&((struct auerchar *) 0)->scontext)));
  39        dbg("auerchar_disconnect called");
  40        ccp->removed = 1;
  41        wake_up(&ccp->readwait);
  42}
  43
  44
  45/* dispatch a read paket to a waiting character device */
  46static void auerchar_ctrlread_dispatch(struct auerscon *scp,
  47                                       struct auerbuf *bp)
  48{
  49        unsigned long flags;
  50        struct auerchar *ccp;
  51        struct auerbuf *newbp = NULL;
  52        char *charp;
  53        dbg("auerchar_ctrlread_dispatch called");
  54        ccp =((struct auerchar *) ((char *) (scp) - (unsigned long)(&((struct auerchar *) 0)->scontext)));
  55
  56        /* get a read buffer from character device context */
  57        newbp = auerbuf_getbuf(&ccp->bufctl);
  58        if (!newbp) {
  59                dbg("No read buffer available, discard paket!");
  60                return;         /* no buffer, no dispatch */
  61        }
  62
  63        /* copy information to new buffer element
  64           (all buffers have the same length) */
  65        charp = newbp->bufp;
  66        newbp->bufp = bp->bufp;
  67        bp->bufp = charp;
  68        newbp->len = bp->len;
  69
  70        /* insert new buffer in read list */
  71        spin_lock_irqsave(&ccp->bufctl.lock, flags);
  72        list_add_tail(&newbp->buff_list, &ccp->bufctl.rec_buff_list);
  73        spin_unlock_irqrestore(&ccp->bufctl.lock, flags);
  74        dbg("read buffer appended to rec_list");
  75
  76        /* wake up pending synchronous reads */
  77        wake_up(&ccp->readwait);
  78}
  79
  80
  81/* Delete an auerswald character context */
  82void auerchar_delete(struct auerchar *ccp)
  83{
  84        dbg("auerchar_delete");
  85        if (ccp == NULL)
  86                return;
  87
  88        /* wake up pending synchronous reads */
  89        ccp->removed = 1;
  90        wake_up(&ccp->readwait);
  91
  92        /* remove the read buffer */
  93        if (ccp->readbuf) {
  94                auerbuf_releasebuf(ccp->readbuf);
  95                ccp->readbuf = NULL;
  96        }
  97
  98        /* remove the character buffers */
  99        auerbuf_free_buffers(&ccp->bufctl);
 100
 101        /* release the memory */
 102        kfree(ccp);
 103}
 104
 105
 106/* --------------------------------------------------------------------- */
 107/* Char device functions                                                 */
 108
 109/* Open a new character device */
 110int auerchar_open(struct inode *inode, struct file *file)
 111{
 112        int dtindex = MINOR(inode->i_rdev) - AUER_MINOR_BASE;
 113        struct auerswald *cp = NULL;
 114        struct auerchar *ccp = NULL;
 115        int ret;
 116
 117        /* minor number in range? */
 118        if ((dtindex < 0) || (dtindex >= AUER_MAX_DEVICES)) {
 119                return -ENODEV;
 120        }
 121        /* usb device available? */
 122        if (down_interruptible(&auerdev_table_mutex)) {
 123                return -ERESTARTSYS;
 124        }
 125        cp = auerdev_table[dtindex];
 126        if (cp == NULL) {
 127                up(&auerdev_table_mutex);
 128                return -ENODEV;
 129        }
 130        if (down_interruptible(&cp->mutex)) {
 131                up(&auerdev_table_mutex);
 132                return -ERESTARTSYS;
 133        }
 134        up(&auerdev_table_mutex);
 135
 136        /* we have access to the device. Now lets allocate memory */
 137        ccp = (struct auerchar *) kmalloc(sizeof(struct auerchar), GFP_KERNEL);
 138        if (ccp == NULL) {
 139                err("out of memory");
 140                ret = -ENOMEM;
 141                goto ofail;
 142        }
 143
 144        /* Initialize device descriptor */
 145        memset(ccp, 0, sizeof(struct auerchar));
 146        init_MUTEX(&ccp->mutex);
 147        init_MUTEX(&ccp->readmutex);
 148        auerbuf_init(&ccp->bufctl);
 149        ccp->scontext.id = AUH_UNASSIGNED;
 150        ccp->scontext.dispatch = auerchar_ctrlread_dispatch;
 151        ccp->scontext.disconnect = auerchar_disconnect;
 152        init_waitqueue_head(&ccp->readwait);
 153
 154        ret =
 155            auerbuf_setup(&ccp->bufctl, AU_RBUFFERS,
 156                          cp->maxControlLength + AUH_SIZE);
 157        if (ret) {
 158                goto ofail;
 159        }
 160
 161        cp->open_count++;
 162        ccp->auerdev = cp;
 163        dbg("open %s as /dev/usb/%s", cp->dev_desc, cp->name);
 164        up(&cp->mutex);
 165
 166        /* file IO stuff */
 167        file->f_pos = 0;
 168        file->private_data = ccp;
 169        return 0;
 170
 171        /* Error exit */
 172      ofail:up(&cp->mutex);
 173        auerchar_delete(ccp);
 174        return ret;
 175}
 176
 177
 178/* IOCTL functions */
 179int auerchar_ioctl(struct inode *inode, struct file *file,
 180                   unsigned int cmd, unsigned long arg)
 181{
 182        struct auerchar *ccp = (struct auerchar *) file->private_data;
 183        int ret = 0;
 184        struct audevinfo devinfo;
 185        struct auerswald *cp = NULL;
 186        unsigned int u;
 187        dbg("ioctl");
 188
 189        /* get the mutexes */
 190        if (down_interruptible(&ccp->mutex)) {
 191                return -ERESTARTSYS;
 192        }
 193        cp = ccp->auerdev;
 194        if (!cp) {
 195                up(&ccp->mutex);
 196                return -ENODEV;
 197        }
 198        if (down_interruptible(&cp->mutex)) {
 199                up(&ccp->mutex);
 200                return -ERESTARTSYS;
 201        }
 202
 203        /* Check for removal */
 204        if (!cp->usbdev) {
 205                up(&cp->mutex);
 206                up(&ccp->mutex);
 207                return -ENODEV;
 208        }
 209
 210        switch (cmd) {
 211
 212                /* return != 0 if Transmitt channel ready to send */
 213        case IOCTL_AU_TXREADY:
 214                dbg("IOCTL_AU_TXREADY");
 215                u = ccp->auerdev && (ccp->scontext.id != AUH_UNASSIGNED)
 216                    && !list_empty(&cp->bufctl.free_buff_list);
 217                ret = put_user(u, (unsigned int *) arg);
 218                break;
 219
 220                /* return != 0 if connected to a service channel */
 221        case IOCTL_AU_CONNECT:
 222                dbg("IOCTL_AU_CONNECT");
 223                u = (ccp->scontext.id != AUH_UNASSIGNED);
 224                ret = put_user(u, (unsigned int *) arg);
 225                break;
 226
 227                /* return != 0 if Receive Data available */
 228        case IOCTL_AU_RXAVAIL:
 229                dbg("IOCTL_AU_RXAVAIL");
 230                if (ccp->scontext.id == AUH_UNASSIGNED) {
 231                        ret = -EIO;
 232                        break;
 233                }
 234                u = 0;          /* no data */
 235                if (ccp->readbuf) {
 236                        int restlen = ccp->readbuf->len - ccp->readoffset;
 237                        if (restlen > 0)
 238                                u = 1;
 239                }
 240                if (!u) {
 241                        if (!list_empty(&ccp->bufctl.rec_buff_list)) {
 242                                u = 1;
 243                        }
 244                }
 245                ret = put_user(u, (unsigned int *) arg);
 246                break;
 247
 248                /* return the max. buffer length for the device */
 249        case IOCTL_AU_BUFLEN:
 250                dbg("IOCTL_AU_BUFLEN");
 251                u = cp->maxControlLength;
 252                ret = put_user(u, (unsigned int *) arg);
 253                break;
 254
 255                /* requesting a service channel */
 256        case IOCTL_AU_SERVREQ:
 257                dbg("IOCTL_AU_SERVREQ");
 258                /* requesting a service means: release the previous one first */
 259                auerswald_removeservice(cp, &ccp->scontext);
 260                /* get the channel number */
 261                ret = get_user(u, (unsigned int *) arg);
 262                if (ret) {
 263                        break;
 264                }
 265                if ((u < AUH_FIRSTUSERCH) || (u >= AUH_TYPESIZE)) {
 266                        ret = -EIO;
 267                        break;
 268                }
 269                dbg("auerchar service request parameters are ok");
 270                ccp->scontext.id = u;
 271
 272                /* request the service now */
 273                ret = auerswald_addservice(cp, &ccp->scontext);
 274                if (ret) {
 275                        /* no: revert service entry */
 276                        ccp->scontext.id = AUH_UNASSIGNED;
 277                }
 278                break;
 279
 280                /* get a string descriptor for the device */
 281        case IOCTL_AU_DEVINFO:
 282                dbg("IOCTL_AU_DEVINFO");
 283                if (copy_from_user
 284                    (&devinfo, (void *) arg, sizeof(struct audevinfo))) {
 285                        ret = -EFAULT;
 286                        break;
 287                }
 288                u = strlen(cp->dev_desc) + 1;
 289                if (u > devinfo.bsize) {
 290                        u = devinfo.bsize;
 291                }
 292                ret = copy_to_user(devinfo.buf, cp->dev_desc, u);
 293                break;
 294
 295                /* get the max. string descriptor length */
 296        case IOCTL_AU_SLEN:
 297                dbg("IOCTL_AU_SLEN");
 298                u = AUSI_DLEN;
 299                ret = put_user(u, (unsigned int *) arg);
 300                break;
 301
 302        default:
 303                dbg("IOCTL_AU_UNKNOWN");
 304                ret = -ENOIOCTLCMD;
 305                break;
 306        }
 307        /* release the mutexes */
 308        up(&cp->mutex);
 309        up(&ccp->mutex);
 310        return ret;
 311}
 312
 313
 314/* Seek is not supported */
 315loff_t auerchar_llseek(struct file * file, loff_t offset, int origin)
 316{
 317        dbg("auerchar_seek");
 318        return -ESPIPE;
 319}
 320
 321
 322/* Read data from the device */
 323ssize_t auerchar_read(struct file * file, char *buf, size_t count,
 324                      loff_t * ppos)
 325{
 326        unsigned long flags;
 327        struct auerchar *ccp = (struct auerchar *) file->private_data;
 328        struct auerbuf *bp = NULL;
 329        wait_queue_t wait;
 330
 331        dbg("auerchar_read");
 332
 333        /* Error checking */
 334        if (!ccp)
 335                return -EIO;
 336        if (*ppos)
 337                return -ESPIPE;
 338        if (count == 0)
 339                return 0;
 340
 341        /* get the mutex */
 342        if (down_interruptible(&ccp->mutex))
 343                return -ERESTARTSYS;
 344
 345        /* Can we expect to read something? */
 346        if (ccp->scontext.id == AUH_UNASSIGNED) {
 347                up(&ccp->mutex);
 348                return -EIO;
 349        }
 350
 351        /* only one reader per device allowed */
 352        if (down_interruptible(&ccp->readmutex)) {
 353                up(&ccp->mutex);
 354                return -ERESTARTSYS;
 355        }
 356
 357        /* read data from readbuf, if available */
 358      doreadbuf:
 359        bp = ccp->readbuf;
 360        if (bp) {
 361                /* read the maximum bytes */
 362                int restlen = bp->len - ccp->readoffset;
 363                if (restlen < 0)
 364                        restlen = 0;
 365                if (count > restlen)
 366                        count = restlen;
 367                if (count) {
 368                        if (copy_to_user
 369                            (buf, bp->bufp + ccp->readoffset, count)) {
 370                                dbg("auerswald_read: copy_to_user failed");
 371                                up(&ccp->readmutex);
 372                                up(&ccp->mutex);
 373                                return -EFAULT;
 374                        }
 375                }
 376                /* advance the read offset */
 377                ccp->readoffset += count;
 378                restlen -= count;
 379                // reuse the read buffer
 380                if (restlen <= 0) {
 381                        auerbuf_releasebuf(bp);
 382                        ccp->readbuf = NULL;
 383                }
 384                /* return with number of bytes read */
 385                if (count) {
 386                        up(&ccp->readmutex);
 387                        up(&ccp->mutex);
 388                        return count;
 389                }
 390        }
 391
 392        /* a read buffer is not available. Try to get the next data block. */
 393      doreadlist:
 394        /* Preparing for sleep */
 395        init_waitqueue_entry(&wait, current);
 396        set_current_state(TASK_INTERRUPTIBLE);
 397        add_wait_queue(&ccp->readwait, &wait);
 398
 399        bp = NULL;
 400        spin_lock_irqsave(&ccp->bufctl.lock, flags);
 401        if (!list_empty(&ccp->bufctl.rec_buff_list)) {
 402                /* yes: get the entry */
 403                struct list_head *tmp = ccp->bufctl.rec_buff_list.next;
 404                list_del(tmp);
 405                bp = list_entry(tmp, struct auerbuf, buff_list);
 406        }
 407        spin_unlock_irqrestore(&ccp->bufctl.lock, flags);
 408
 409        /* have we got data? */
 410        if (bp) {
 411                ccp->readbuf = bp;
 412                ccp->readoffset = AUH_SIZE;     /* for headerbyte */
 413                set_current_state(TASK_RUNNING);
 414                remove_wait_queue(&ccp->readwait, &wait);
 415                goto doreadbuf; /* now we can read! */
 416        }
 417
 418        /* no data available. Should we wait? */
 419        if (file->f_flags & O_NONBLOCK) {
 420                dbg("No read buffer available, returning -EAGAIN");
 421                set_current_state(TASK_RUNNING);
 422                remove_wait_queue(&ccp->readwait, &wait);
 423                up(&ccp->readmutex);
 424                up(&ccp->mutex);
 425                return -EAGAIN; /* nonblocking, no data available */
 426        }
 427
 428        /* yes, we should wait! */
 429        up(&ccp->mutex);        /* allow other operations while we wait */
 430        schedule();
 431        remove_wait_queue(&ccp->readwait, &wait);
 432        if (signal_pending(current)) {
 433                /* waked up by a signal */
 434                up(&ccp->readmutex);
 435                return -ERESTARTSYS;
 436        }
 437
 438        /* Anything left to read? */
 439        if ((ccp->scontext.id == AUH_UNASSIGNED) || ccp->removed) {
 440                up(&ccp->readmutex);
 441                return -EIO;
 442        }
 443
 444        if (down_interruptible(&ccp->mutex)) {
 445                up(&ccp->readmutex);
 446                return -ERESTARTSYS;
 447        }
 448
 449        /* try to read the incomming data again */
 450        goto doreadlist;
 451}
 452
 453
 454/* Write a data block into the right service channel of the device */
 455ssize_t auerchar_write(struct file *file, const char *buf, size_t len,
 456                       loff_t * ppos)
 457{
 458        struct auerchar *ccp = (struct auerchar *) file->private_data;
 459        struct auerswald *cp = NULL;
 460        struct auerbuf *bp;
 461        int ret;
 462        wait_queue_t wait;
 463
 464        dbg("auerchar_write %d bytes", len);
 465
 466        /* Error checking */
 467        if (!ccp)
 468                return -EIO;
 469        if (*ppos)
 470                return -ESPIPE;
 471        if (len == 0)
 472                return 0;
 473
 474      write_again:
 475        /* get the mutex */
 476        if (down_interruptible(&ccp->mutex))
 477                return -ERESTARTSYS;
 478
 479        /* Can we expect to write something? */
 480        if (ccp->scontext.id == AUH_UNASSIGNED) {
 481                up(&ccp->mutex);
 482                return -EIO;
 483        }
 484
 485        cp = ccp->auerdev;
 486        if (!cp) {
 487                up(&ccp->mutex);
 488                return -ERESTARTSYS;
 489        }
 490        if (down_interruptible(&cp->mutex)) {
 491                up(&ccp->mutex);
 492                return -ERESTARTSYS;
 493        }
 494        if (!cp->usbdev) {
 495                up(&cp->mutex);
 496                up(&ccp->mutex);
 497                return -EIO;
 498        }
 499        /* Prepare for sleep */
 500        init_waitqueue_entry(&wait, current);
 501        set_current_state(TASK_INTERRUPTIBLE);
 502        add_wait_queue(&cp->bufferwait, &wait);
 503
 504        /* Try to get a buffer from the device pool.
 505           We can't use a buffer from ccp->bufctl because the write
 506           command will last beond a release() */
 507        bp = auerbuf_getbuf(&cp->bufctl);
 508        /* are there any buffers left? */
 509        if (!bp) {
 510                up(&cp->mutex);
 511                up(&ccp->mutex);
 512
 513                /* NONBLOCK: don't wait */
 514                if (file->f_flags & O_NONBLOCK) {
 515                        set_current_state(TASK_RUNNING);
 516                        remove_wait_queue(&cp->bufferwait, &wait);
 517                        return -EAGAIN;
 518                }
 519
 520                /* BLOCKING: wait */
 521                schedule();
 522                remove_wait_queue(&cp->bufferwait, &wait);
 523                if (signal_pending(current)) {
 524                        /* waked up by a signal */
 525                        return -ERESTARTSYS;
 526                }
 527                goto write_again;
 528        } else {
 529                set_current_state(TASK_RUNNING);
 530                remove_wait_queue(&cp->bufferwait, &wait);
 531        }
 532
 533        /* protect against too big write requests */
 534        if (len > cp->maxControlLength)
 535                len = cp->maxControlLength;
 536
 537        /* Fill the buffer */
 538        if (copy_from_user(bp->bufp + AUH_SIZE, buf, len)) {
 539                dbg("copy_from_user failed");
 540                auerbuf_releasebuf(bp);
 541                /* Wake up all processes waiting for a buffer */
 542                wake_up(&cp->bufferwait);
 543                up(&cp->mutex);
 544                up(&ccp->mutex);
 545                return -EIO;
 546        }
 547
 548        /* set the header byte */
 549        *(bp->bufp) = ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT;
 550
 551        /* Set the transfer Parameters */
 552        bp->len = len + AUH_SIZE;
 553        bp->dr->bRequestType = AUT_WREQ;
 554        bp->dr->bRequest = AUV_WBLOCK;
 555        bp->dr->wValue = cpu_to_le16(0);
 556        bp->dr->wIndex =
 557            cpu_to_le16(ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT);
 558        bp->dr->wLength = cpu_to_le16(len + AUH_SIZE);
 559        FILL_CONTROL_URB(bp->urbp, cp->usbdev,
 560                         usb_sndctrlpipe(cp->usbdev, 0),
 561                         (unsigned char *) bp->dr, bp->bufp,
 562                         len + AUH_SIZE, auerchar_ctrlwrite_complete, bp);
 563        /* up we go */
 564        ret = auerchain_submit_urb(&cp->controlchain, bp->urbp);
 565        up(&cp->mutex);
 566        if (ret) {
 567                dbg("auerchar_write: nonzero result of auerchain_submit_urb %d", ret);
 568                auerbuf_releasebuf(bp);
 569                /* Wake up all processes waiting for a buffer */
 570                wake_up(&cp->bufferwait);
 571                up(&ccp->mutex);
 572                return -EIO;
 573        } else {
 574                dbg("auerchar_write: Write OK");
 575                up(&ccp->mutex);
 576                return len;
 577        }
 578}
 579
 580
 581/* Close a character device */
 582int auerchar_release(struct inode *inode, struct file *file)
 583{
 584        struct auerchar *ccp = (struct auerchar *) file->private_data;
 585        struct auerswald *cp;
 586        dbg("release");
 587
 588        /* get the mutexes */
 589        if (down_interruptible(&ccp->mutex)) {
 590                return -ERESTARTSYS;
 591        }
 592        cp = ccp->auerdev;
 593        if (cp) {
 594                if (down_interruptible(&cp->mutex)) {
 595                        up(&ccp->mutex);
 596                        return -ERESTARTSYS;
 597                }
 598                /* remove an open service */
 599                auerswald_removeservice(cp, &ccp->scontext);
 600                /* detach from device */
 601                if ((--cp->open_count <= 0) && (cp->usbdev == NULL)) {
 602                        /* usb device waits for removal */
 603                        up(&cp->mutex);
 604                        auerswald_delete(cp);
 605                } else {
 606                        up(&cp->mutex);
 607                }
 608                cp = NULL;
 609                ccp->auerdev = NULL;
 610        }
 611        up(&ccp->mutex);
 612        auerchar_delete(ccp);
 613
 614        return 0;
 615}
 616
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.