Ticket #4053: usb_midi_fix.diff

File usb_midi_fix.diff, 16.1 KB (added by Pete, 15 years ago)

(Working!) Patches to usb_midi and midi_server to cure page faults

  • haiku/src/add-ons/kernel/drivers/midi/

    diff -u haiku/src/add-ons/kernel/drivers/midi/usb_midi_ALPHA1/usb_midi.c haiku/src/add-ons/kernel/drivers/midi/usb_midi/usb_midi.c
    old new  
    33 * usb_midi.c
    44 *
    55 * Copyright 2006-2009 Haiku Inc.  All rights reserved.
    6  * Distributed under the terms of the MIT Licence.
     6 * Distributed under tthe terms of the MIT Licence.
    77 *
    88 * Authors:
    99 *      Jérôme Duval
     
    1717 */
    1818
    1919
    20 /*#define DEBUG 1*/ /* Define this to enable DPRINTF_INFO statements */
     20/* #define DEBUG 1 */   /* Define this to enable DPRINTF_INFO statements */
    2121#include "usb_midi.h"
    2222
    23 #include <support/Debug.h>
     23#include <stdio.h>
    2424#include <stdlib.h>
    2525#include <string.h>
    2626#include <unistd.h>
     
    3232static int midi_device_number = 0;
    3333const char* midi_base_name = "midi/usb/";
    3434
    35 
    3635usbmidi_device_info*
    3736create_device(const usb_device* dev, const usb_interface_info* ii, uint16 ifno)
    3837{
     
    5251    if (my_dev == NULL)
    5352        return NULL;
    5453
    55     my_dev->sem_cb = sem = create_sem(0, DRIVER_NAME "_cb");
    56     if (sem < 0) {
    57         DPRINTF_ERR((MY_ID "create_sem() failed %d\n", (int)sem));
    58         free(my_dev);
    59         return NULL;
    60     }
    61 
    6254    my_dev->sem_lock = sem = create_sem(1, DRIVER_NAME "_lock");
    6355    if (sem < 0) {
    6456        DPRINTF_ERR((MY_ID "create_sem() failed %d\n", (int)sem));
    65         delete_sem(my_dev->sem_cb);
    6657        free(my_dev);
    6758        return NULL;
    6859    }
     
    7364        B_PAGE_SIZE, B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA);
    7465    if (area < 0) {
    7566        DPRINTF_ERR((MY_ID "create_area() failed %d\n", (int)area));
    76         delete_sem(my_dev->sem_cb);
    7767        delete_sem(my_dev->sem_lock);
    7868        free(my_dev);
    7969        return NULL;
     
    8373    my_dev->sem_send =  sem = create_sem(1, DRIVER_NAME "_send");
    8474    if (sem < 0) {
    8575        DPRINTF_ERR((MY_ID "create_sem() failed %d\n", (int)sem));
    86         delete_sem(my_dev->sem_cb);
    8776        delete_sem(my_dev->sem_lock);
    8877        delete_area(area);
    8978        free(my_dev);
     
    9281    {
    9382        int32 bc;
    9483        get_sem_count(sem, &bc);
    95         DPRINTF_INFO((MY_ID "Allocated %d write buffers\n", bc));
     84        DPRINTF_INFO((MY_ID "Allocated %ld write buffers\n", bc));
    9685    }
    9786
    9887
     
    10089    my_dev->dev = dev;
    10190    my_dev->ifno = ifno;
    10291    my_dev->open = 0;
    103     my_dev->open_fds = NULL;
     92    my_dev->open_fd = NULL;
    10493    my_dev->active = true;
    10594    my_dev->flags = 0;
    10695    my_dev->rbuf = create_ring_buffer(1024);
    10796    my_dev->buffer_size = B_PAGE_SIZE/2;
     97    DPRINTF_INFO((MY_ID "Created device %p\n", my_dev);)
    10898       
    10999    return my_dev;
    110100}
     
    118108        delete_ring_buffer(my_dev->rbuf);
    119109        my_dev->rbuf = NULL;
    120110    }
     111    DPRINTF_INFO((MY_ID "remove_device %p\n", my_dev);)
    121112 
    122113    delete_area(my_dev->buffer_area);
    123     delete_sem(my_dev->sem_cb);
    124114    delete_sem(my_dev->sem_lock);
    125115    delete_sem(my_dev->sem_send);
    126116    free(my_dev);
    127117}
    128118
    129119
    130 /* driver cookie (per open) */
     120/* driver cookie (per open -- but only one open allowed!) */
    131121
    132122typedef struct driver_cookie
    133123{
    134124    struct driver_cookie    *next;
    135125    usbmidi_device_info         *my_dev;
     126    sem_id sem_cb;
    136127} driver_cookie;
    137128
    138129   
     
    174165        DPRINTF_INFO((MY_ID "received packet %x:%d %x %x %x\n", packet->cin, packet->cn,
    175166            packet->midi[0], packet->midi[1], packet->midi[2]));
    176167        ring_buffer_write(my_dev->rbuf, packet->midi, pktlen);
    177         release_sem_etc(my_dev->sem_cb, pktlen, B_DO_NOT_RESCHEDULE);
     168        release_sem_etc(my_dev->open_fd->sem_cb, pktlen, B_DO_NOT_RESCHEDULE);
    178169        packet++;
    179170        bytes_left -= sizeof(usb_midi_event_packet);
    180171    }
     
    193184    usbmidi_device_info* my_dev = cookie;
    194185
    195186    assert(cookie != NULL);
    196     DPRINTF_INFO((MY_ID "midi_usb_read_callback() -- packet length %d\n", actual_len));
     187    DPRINTF_INFO((MY_ID "midi_usb_read_callback() -- packet length %ld\n", actual_len));
    197188
    198189    acquire_sem(my_dev->sem_lock);
    199190    my_dev->actual_length = actual_len;
    200191    my_dev->bus_status = status;    /* B_USB_STATUS_* */
    201192    if (status != B_OK) {
    202193        /* request failed */
    203         release_sem(my_dev->sem_lock);
    204         DPRINTF_ERR((MY_ID "bus status %d\n", (int)status));
    205         if (status == B_CANCELED) {
     194        DPRINTF_INFO((MY_ID "bus status %d\n", (int)status)); /* previously DPRINTF_ERR */
     195        if (status == B_CANCELED || !my_dev->active) {
    206196            /* cancelled: device is unplugged */
     197            DPRINTF_INFO((MY_ID "midi_usb_read_callback: cancelled (status=%lx active=%d -- deleting sem_cb\n",
     198                status, my_dev->active));
     199            delete_sem(my_dev->open_fd->sem_cb);    /* done here to ensure read is freed */
     200            release_sem(my_dev->sem_lock);
    207201            return;
    208202        }
     203        release_sem(my_dev->sem_lock);
    209204    } else {
    210205        /* got a report */
    211206#if 0
     
    244239#endif
    245240
    246241    assert(cookie != NULL);
    247     DPRINTF_INFO((MY_ID "midi_usb_write_callback() status %ld length %d  pkt %p cin %x\n",
     242    DPRINTF_INFO((MY_ID "midi_usb_write_callback() status %ld length %ld  pkt %p cin %x\n",
    248243        status, actual_len, pkt, pkt->cin));
    249244    release_sem(my_dev->sem_send); /* done with buffer */
    250245}
     
    266261    int alt;
    267262   
    268263    assert(dev != NULL && cookie != NULL);
    269     DPRINTF_INFO((MY_ID "device_added()\n"));
     264    DPRINTF_INFO((MY_ID "usb_midi_added(%p, %p)\n", dev, cookie));
    270265
    271266    dev_desc = usb->get_device_descriptor(dev);
    272267
     
    348343    add_device_info(my_dev);
    349344
    350345    *cookie = my_dev;
    351     DPRINTF_INFO((MY_ID "added %s\n", my_dev->name));
     346    DPRINTF_INFO((MY_ID "usb_midi_added: added %s\n", my_dev->name));
    352347
    353348    return B_OK;
    354349}
     
    361356
    362357    assert(cookie != NULL);
    363358
    364     DPRINTF_INFO((MY_ID "device_removed(%s)\n", my_dev->name));
     359    DPRINTF_INFO((MY_ID "usb_midi_removed(%s)\n", my_dev->name));
     360    acquire_sem(usbmidi_device_list_lock);  /* convenient mutex for safety */
     361    my_dev->active = false;
     362    if (my_dev->open_fd) {
     363        my_dev->open_fd->my_dev = NULL;
     364        delete_sem(my_dev->open_fd->sem_cb);    /* done here to ensure read is freed */
     365    }
     366    release_sem(usbmidi_device_list_lock);
    365367    usb->cancel_queued_transfers(my_dev->ept_in->handle);
    366368    usb->cancel_queued_transfers(my_dev->ept_out->handle);
     369    DPRINTF_INFO((MY_ID "usb_midi_removed: removing info & device: %s\n", my_dev->name));
    367370    remove_device_info(my_dev);
    368     if (my_dev->open == 0) {
    369         remove_device(my_dev);
    370     } else {
    371         DPRINTF_INFO((MY_ID "%s still open\n", my_dev->name));
    372         my_dev->active = false;
    373     }
     371    remove_device(my_dev);
    374372    return B_OK;
    375373}
    376374
     
    400398
    401399    assert(name != NULL);
    402400    assert(out_cookie != NULL);
    403     DPRINTF_INFO((MY_ID "open(%s)\n", name));
     401    DPRINTF_INFO((MY_ID "usb_midi_open(%s)\n", name));
    404402
    405403    if ((my_dev = search_device_info(name)) == NULL)
    406404        return B_ENTRY_NOT_FOUND;
     405    if (my_dev->open_fd != NULL)
     406        return B_BUSY;  /* there can only be one open channel to the device */
    407407    if ((cookie = malloc(sizeof(driver_cookie))) == NULL)
    408408        return B_NO_MEMORY;
    409409
    410     acquire_sem(my_dev->sem_lock);
     410    cookie->sem_cb = create_sem(0, DRIVER_NAME "_cb");
     411    if (cookie->sem_cb < 0) {
     412        DPRINTF_ERR((MY_ID "create_sem() failed %d\n", (int)cookie->sem_cb));
     413        free(cookie);
     414        return B_ERROR;
     415    }
     416
     417    acquire_sem(usbmidi_device_list_lock);  /* use global mutex now */
    411418    cookie->my_dev = my_dev;
    412     cookie->next = my_dev->open_fds;
    413     my_dev->open_fds = cookie;
     419    my_dev->open_fd = cookie;
    414420    my_dev->open++;
    415     release_sem(my_dev->sem_lock);
     421    release_sem(usbmidi_device_list_lock);
    416422
    417423    *out_cookie = cookie;
    418     DPRINTF_INFO((MY_ID "device %s open (%d)\n", name, my_dev->open));
     424    DPRINTF_INFO((MY_ID "usb_midi_open: device %s open (%d)\n", name, my_dev->open));
    419425    return B_OK;
    420426}
    421427
     
    433439
    434440    assert(cookie != NULL);
    435441    my_dev = cookie->my_dev;
    436     assert(my_dev != NULL);
    437442   
    438     if (!my_dev->active)
    439         return B_ERROR;     /* already unplugged */
     443    if (!my_dev || !my_dev->active)
     444        return B_ERROR; /* already unplugged */
    440445       
    441     DPRINTF_INFO((MY_ID "MIDI read (%d byte buffer at %ld cookie %p)\n",
     446    DPRINTF_INFO((MY_ID "usb_midi_read: (%ld byte buffer at %ld cookie %p)\n",
    442447        *num_bytes, (int32)position, cookie));
    443     err = acquire_sem_etc(my_dev->sem_cb, 1, B_CAN_INTERRUPT, 0LL);
    444     if (err != B_OK)
    445         return err;
    446     acquire_sem(my_dev->sem_lock);
    447     ring_buffer_user_read(my_dev->rbuf, buf, 1);
    448     release_sem(my_dev->sem_lock);
    449     *num_bytes = 1;
    450     DPRINTF_INFO((MY_ID "read byte %x -- cookie %p)\n", *(uint8*)buf, cookie));
    451     return err;
     448    while (my_dev && my_dev->active) {
     449        DPRINTF_INFOZ((MY_ID "waiting on acquire_sem_etc\n");)
     450        err = acquire_sem_etc(cookie->sem_cb, 1,
     451             B_RELATIVE_TIMEOUT, 1000000);
     452        if (err == B_TIMED_OUT) {
     453            DPRINTF_INFOZ((MY_ID "acquire_sem_etc timed out\n");)
     454            continue;   /* see if we're still active */
     455        }
     456        if (err != B_OK) {
     457            *num_bytes = 0;
     458            DPRINTF_INFO((MY_ID "acquire_sem_etc aborted\n");)
     459            break;
     460        }
     461        DPRINTF_INFO((MY_ID "reading from ringbuffer\n");)
     462        acquire_sem(my_dev->sem_lock);
     463        ring_buffer_user_read(my_dev->rbuf, buf, 1);
     464        release_sem(my_dev->sem_lock);
     465        *num_bytes = 1;
     466        DPRINTF_INFO((MY_ID "read byte %x -- cookie %p)\n", *(uint8*)buf, cookie));
     467        return B_OK;
     468    }
     469    DPRINTF_INFO((MY_ID "usb_midi_read: loop terminated -- Device no longer active\n");)
     470    return B_CANCELED;
    452471}
    453472
    454473
     
    491510
    492511    assert(cookie != NULL);
    493512    my_dev = cookie->my_dev;
    494     assert(my_dev != NULL);
    495513
    496     if (!my_dev->active)
     514    if (!my_dev || !my_dev->active)
    497515        return B_ERROR;     /* already unplugged */
    498516       
    499517    buff_lim = my_dev->buffer_size * 3 / 4; /* max MIDI bytes buffer space */
    500518   
    501     DPRINTF_INFO((MY_ID "MIDI write (%d bytes at %ld)\n", *num_bytes, position));
     519    DPRINTF_INFO((MY_ID "MIDI write (%ld bytes at %Ld)\n", *num_bytes, position));
    502520    if (*num_bytes > 3 && midicode != 0xF0) {
    503521        DPRINTF_ERR((MY_ID "Non-SysEx packet of %ld bytes -- too big to handle\n",
    504522            *num_bytes));
     
    563581{
    564582    usbmidi_device_info* my_dev;
    565583
    566     assert(cookie != NULL && cookie->my_dev != NULL);
     584    assert(cookie != NULL);
     585    delete_sem(cookie->sem_cb);
    567586    my_dev = cookie->my_dev;
    568     DPRINTF_INFO((MY_ID "close(%s)\n", my_dev->name));
     587    DPRINTF_INFO((MY_ID "usb_midi_close(%p device=%p)\n", cookie, my_dev));
    569588
    570     /* detach the cookie from list */
    571589
    572     acquire_sem(my_dev->sem_lock);
    573     if (my_dev->open_fds == cookie)
    574         my_dev->open_fds = cookie->next;
    575     else {
    576         driver_cookie* p;
    577         for (p = my_dev->open_fds; p != NULL; p = p->next) {
    578             if (p->next == cookie) {
    579                 p->next = cookie->next;
    580                 break;
    581             }
    582         }
     590    acquire_sem(usbmidi_device_list_lock);
     591    if (my_dev) {
     592        /* detach the cookie from device */
     593        my_dev->open_fd = NULL;
     594        --my_dev->open;
    583595    }
    584     --my_dev->open;
    585     release_sem(my_dev->sem_lock);
     596    release_sem(usbmidi_device_list_lock);
     597    DPRINTF_INFO((MY_ID "usb_midi_close: complete\n");)
    586598
    587599    return B_OK;
    588600}
     
    598610{
    599611    usbmidi_device_info* my_dev;
    600612
    601     assert(cookie != NULL && cookie->my_dev != NULL);
     613    assert(cookie != NULL);
    602614    my_dev = cookie->my_dev;
    603     DPRINTF_INFO((MY_ID "free(%s)\n", my_dev->name));
     615    DPRINTF_INFO((MY_ID "usb_midi_free(%p device=%p)\n", cookie, my_dev));
    604616
    605617    free(cookie);
    606     if (my_dev->open > 0)
    607         DPRINTF_INFO((MY_ID "%d opens left\n", my_dev->open));
    608     else if (!my_dev->active) {
    609         DPRINTF_INFO((MY_ID "removed %s\n", my_dev->name));
    610         remove_device(my_dev);
    611     }
    612618
    613619    return B_OK;
    614620}
     
    683689    delete_sem(usbmidi_device_list_lock);
    684690    put_module(B_USB_MODULE_NAME);
    685691    free_device_names();
     692    DPRINTF_INFO((MY_ID "uninit complete\n"));
    686693}
    687694
    688695
  • haiku/src/add-ons/kernel/drivers/midi/

    diff -u haiku/src/add-ons/kernel/drivers/midi/usb_midi_ALPHA1/usb_midi.h haiku/src/add-ons/kernel/drivers/midi/usb_midi/usb_midi.h
    old new  
    6262    struct usbmidi_device_info* next;
    6363
    6464    /* maintain device */
    65     sem_id sem_cb;
    6665    sem_id sem_lock;
    6766    sem_id sem_send;
    6867    area_id buffer_area;
     
    7776
    7877    bool active;
    7978    int open;
    80     struct driver_cookie* open_fds;
     79    struct driver_cookie* open_fd;
    8180
    8281    /* work area for transfer */
    8382    int usbd_status, bus_status, cmd_status;
  • DeviceWatcher.cpp

    diff -u haiku/src/servers/midi_ALPHA1/DeviceWatcher.cpp haiku/src/servers/midi/DeviceWatcher.cpp
    old new  
    88 *      Philippe Houdoin
    99 */
    1010
    11 
    1211#include "debug.h"
    1312#include "DeviceWatcher.h"
    1413#include "PortDrivers.h"
     
    3231using BPrivate::HashMap;
    3332using BPrivate::HashString;
    3433
     34
     35
    3536const char *kDevicesRoot = "/dev/midi";
    36 // const char *kDevicesRoot = "/Data/tmp";
    3737
    3838
    3939class DeviceEndpoints {
     
    132132    if (message->FindString("path", &path) != B_OK)
    133133        return;
    134134
     135    const char* filename;
     136    if (message->FindString("name", &filename) != B_OK)
     137        return;
     138
    135139    switch (opcode) {
    136140        case B_ENTRY_CREATED: {
    137             _AddDevice(path);
     141            BPath bpath(path);
     142            TRACE(("got path %s leaf %s name %s\n", path, bpath.Leaf(), filename));
     143            if (strcmp(bpath.Leaf(), filename) == 0) _AddDevice(path);
    138144            break;
    139145        }
    140146        case B_ENTRY_REMOVED: {
     
    152158int32
    153159DeviceWatcher::_InitialDevicesScanThread(void* data)
    154160{
    155     ((DeviceWatcher*)data)->_ScanDevices(kDevicesRoot);
     161    ((DeviceWatcher*) data)->_ScanDevices(kDevicesRoot);
    156162    return 0;
    157163}
    158164
     
    183189{
    184190    TRACE(("DeviceWatcher::_AddDevice(\"%s\");\n", path));
    185191
    186     if (fDeviceEndpointsMap.ContainsKey(path)) {
     192    if ( fDeviceEndpointsMap.ContainsKey(path) ) {
    187193        // Already known
     194        TRACE(("already known...!\n"));
    188195        return;
    189196    }
    190197       
    191     BEntry entry(path);
    192     if (entry.IsDirectory())
    193         // Invalid path !
    194         return;
    195        
    196     if (entry.IsSymLink()) {
    197         BEntry symlink(path, true);
    198         if (symlink.IsDirectory()) {
    199             // Invalid path!
    200             return;
    201         }
    202     }
    203 
    204198    int fd = open(path, O_RDWR | O_EXCL);
    205199    if (fd < 0)
    206         return;
     200        return;
     201       
    207202   
     203    TRACE(("Doing _AddDevice(\"%s\"); fd=%d\n", path, fd));
     204
    208205    MidiPortConsumer* consumer = new MidiPortConsumer(fd, path);
    209206    _SetIcons(consumer);
    210207    TRACE(("Register %s MidiPortConsumer\n", consumer->Name()));
     
    215212    TRACE(("Register %s MidiPortProducer\n", producer->Name()));
    216213    producer->Register();
    217214
    218     DeviceEndpoints* deviceEndpoints = new DeviceEndpoints(fd, consumer, producer);
     215    DeviceEndpoints * deviceEndpoints = new DeviceEndpoints(fd, consumer, producer);
    219216    fDeviceEndpointsMap.Put(path, deviceEndpoints);
     217    TRACE(("Done _AddDevice(\"%s\")\n", path));
    220218}
    221219
    222220
     
    225223{
    226224    TRACE(("DeviceWatcher::_RemoveDevice(\"%s\");\n", path));
    227225       
    228     DeviceEndpoints* deviceEndpoints = fDeviceEndpointsMap.Get(path);
    229     if (!deviceEndpoints)
     226    DeviceEndpoints * deviceEndpoints = fDeviceEndpointsMap.Get(path);
     227    if (!deviceEndpoints) {
     228        TRACE(("_RemoveDevice(\"%s\") didn't find endpoint in map!!\n", path));
    230229        return;
     230    }
    231231       
    232     close(deviceEndpoints->fFD);
    233232
     233    TRACE((" _RemoveDevice(\"%s\") unregistering\n", path));
    234234    deviceEndpoints->fConsumer->Unregister();
    235235    deviceEndpoints->fProducer->Unregister();
    236236
     237    TRACE((" _RemoveDevice(\"%s\") releasing\n", path));
    237238    deviceEndpoints->fConsumer->Release();
    238239    deviceEndpoints->fProducer->Release();
    239240
     241    TRACE((" _RemoveDevice(\"%s\") removing from map\n", path));
    240242    fDeviceEndpointsMap.Remove(path);
     243    TRACE(("Done _RemoveDevice(\"%s\")\n", path));
    241244}
    242245
    243246
  • haiku/src/servers/

    diff -u haiku/src/servers/midi_ALPHA1/PortDrivers.cpp haiku/src/servers/midi/PortDrivers.cpp
    old new  
    1515#include <stdio.h>
    1616#include <stdlib.h>
    1717#include <unistd.h>
     18#include <errno.h>
    1819
    1920#include <String.h>
    2021
     
    9091
    9192    while (fKeepRunning) {
    9293        if (read(fFileDescriptor, &next, 1) != 1) {
    93             perror("Error reading data from driver");
     94            if (errno == B_CANCELED) fKeepRunning = false;
     95            else perror("Error reading data from driver");
    9496            break;
    9597        }
    9698
     
    234236    if (haveSysEx)
    235237        free(sysexBuf);
    236238
    237     return fKeepRunning ? B_ERROR : B_OK;
     239    return fKeepRunning ? errno : B_OK;
    238240}
  • haiku/src/servers/

    diff -u haiku/src/servers/midi_ALPHA1/midi_server.rdef haiku/src/servers/midi/midi_server.rdef
    old new  
    1010    variety    = B_APPV_ALPHA,
    1111    internal   = 0,
    1212    short_info = "midi_server",
    13     long_info  = "midi_server ©2002-2006 Haiku"
     13    long_info  = "midi_server ©2002-2009 Haiku"
    1414};
    1515
    1616resource vector_icon array {