Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  HID driver for the Prodikeys PC-MIDI Keyboard
0004  *  providing midi & extra multimedia keys functionality
0005  *
0006  *  Copyright (c) 2009 Don Prince <dhprince.devel@yahoo.co.uk>
0007  *
0008  *  Controls for Octave Shift Up/Down, Channel, and
0009  *  Sustain Duration available via sysfs.
0010  */
0011 
0012 /*
0013  */
0014 
0015 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0016 
0017 #include <linux/device.h>
0018 #include <linux/module.h>
0019 #include <linux/usb.h>
0020 #include <linux/mutex.h>
0021 #include <linux/hid.h>
0022 #include <sound/core.h>
0023 #include <sound/initval.h>
0024 #include <sound/rawmidi.h>
0025 #include "hid-ids.h"
0026 
0027 
0028 #define pk_debug(format, arg...) \
0029     pr_debug("hid-prodikeys: " format "\n" , ## arg)
0030 #define pk_error(format, arg...) \
0031     pr_err("hid-prodikeys: " format "\n" , ## arg)
0032 
0033 struct pcmidi_snd;
0034 
0035 struct pk_device {
0036     unsigned long       quirks;
0037 
0038     struct hid_device   *hdev;
0039     struct pcmidi_snd   *pm; /* pcmidi device context */
0040 };
0041 
0042 struct pcmidi_sustain {
0043     unsigned long       in_use;
0044     struct pcmidi_snd   *pm;
0045     struct timer_list   timer;
0046     unsigned char       status;
0047     unsigned char       note;
0048     unsigned char       velocity;
0049 };
0050 
0051 #define PCMIDI_SUSTAINED_MAX    32
0052 struct pcmidi_snd {
0053     struct pk_device        *pk;
0054     unsigned short          ifnum;
0055     struct hid_report       *pcmidi_report6;
0056     struct input_dev        *input_ep82;
0057     unsigned short          midi_mode;
0058     unsigned short          midi_sustain_mode;
0059     unsigned short          midi_sustain;
0060     unsigned short          midi_channel;
0061     short               midi_octave;
0062     struct pcmidi_sustain       sustained_notes[PCMIDI_SUSTAINED_MAX];
0063     unsigned short          fn_state;
0064     unsigned short          last_key[24];
0065     spinlock_t          rawmidi_in_lock;
0066     struct snd_card         *card;
0067     struct snd_rawmidi      *rwmidi;
0068     struct snd_rawmidi_substream    *in_substream;
0069     struct snd_rawmidi_substream    *out_substream;
0070     unsigned long           in_triggered;
0071     unsigned long           out_active;
0072 };
0073 
0074 #define PK_QUIRK_NOGET  0x00010000
0075 #define PCMIDI_MIDDLE_C 60
0076 #define PCMIDI_CHANNEL_MIN 0
0077 #define PCMIDI_CHANNEL_MAX 15
0078 #define PCMIDI_OCTAVE_MIN (-2)
0079 #define PCMIDI_OCTAVE_MAX 2
0080 #define PCMIDI_SUSTAIN_MIN 0
0081 #define PCMIDI_SUSTAIN_MAX 5000
0082 
0083 static const char shortname[] = "PC-MIDI";
0084 static const char longname[] = "Prodikeys PC-MIDI Keyboard";
0085 
0086 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
0087 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
0088 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
0089 
0090 module_param_array(index, int, NULL, 0444);
0091 module_param_array(id, charp, NULL, 0444);
0092 module_param_array(enable, bool, NULL, 0444);
0093 MODULE_PARM_DESC(index, "Index value for the PC-MIDI virtual audio driver");
0094 MODULE_PARM_DESC(id, "ID string for the PC-MIDI virtual audio driver");
0095 MODULE_PARM_DESC(enable, "Enable for the PC-MIDI virtual audio driver");
0096 
0097 
0098 /* Output routine for the sysfs channel file */
0099 static ssize_t show_channel(struct device *dev,
0100     struct device_attribute *attr, char *buf)
0101 {
0102     struct hid_device *hdev = to_hid_device(dev);
0103     struct pk_device *pk = hid_get_drvdata(hdev);
0104 
0105     dbg_hid("pcmidi sysfs read channel=%u\n", pk->pm->midi_channel);
0106 
0107     return sprintf(buf, "%u (min:%u, max:%u)\n", pk->pm->midi_channel,
0108         PCMIDI_CHANNEL_MIN, PCMIDI_CHANNEL_MAX);
0109 }
0110 
0111 /* Input routine for the sysfs channel file */
0112 static ssize_t store_channel(struct device *dev,
0113     struct device_attribute *attr, const char *buf, size_t count)
0114 {
0115     struct hid_device *hdev = to_hid_device(dev);
0116     struct pk_device *pk = hid_get_drvdata(hdev);
0117 
0118     unsigned channel = 0;
0119 
0120     if (sscanf(buf, "%u", &channel) > 0 && channel <= PCMIDI_CHANNEL_MAX) {
0121         dbg_hid("pcmidi sysfs write channel=%u\n", channel);
0122         pk->pm->midi_channel = channel;
0123         return strlen(buf);
0124     }
0125     return -EINVAL;
0126 }
0127 
0128 static DEVICE_ATTR(channel, S_IRUGO | S_IWUSR | S_IWGRP , show_channel,
0129         store_channel);
0130 
0131 static struct device_attribute *sysfs_device_attr_channel = {
0132         &dev_attr_channel,
0133         };
0134 
0135 /* Output routine for the sysfs sustain file */
0136 static ssize_t show_sustain(struct device *dev,
0137  struct device_attribute *attr, char *buf)
0138 {
0139     struct hid_device *hdev = to_hid_device(dev);
0140     struct pk_device *pk = hid_get_drvdata(hdev);
0141 
0142     dbg_hid("pcmidi sysfs read sustain=%u\n", pk->pm->midi_sustain);
0143 
0144     return sprintf(buf, "%u (off:%u, max:%u (ms))\n", pk->pm->midi_sustain,
0145         PCMIDI_SUSTAIN_MIN, PCMIDI_SUSTAIN_MAX);
0146 }
0147 
0148 /* Input routine for the sysfs sustain file */
0149 static ssize_t store_sustain(struct device *dev,
0150     struct device_attribute *attr, const char *buf, size_t count)
0151 {
0152     struct hid_device *hdev = to_hid_device(dev);
0153     struct pk_device *pk = hid_get_drvdata(hdev);
0154 
0155     unsigned sustain = 0;
0156 
0157     if (sscanf(buf, "%u", &sustain) > 0 && sustain <= PCMIDI_SUSTAIN_MAX) {
0158         dbg_hid("pcmidi sysfs write sustain=%u\n", sustain);
0159         pk->pm->midi_sustain = sustain;
0160         pk->pm->midi_sustain_mode =
0161             (0 == sustain || !pk->pm->midi_mode) ? 0 : 1;
0162         return strlen(buf);
0163     }
0164     return -EINVAL;
0165 }
0166 
0167 static DEVICE_ATTR(sustain, S_IRUGO | S_IWUSR | S_IWGRP, show_sustain,
0168         store_sustain);
0169 
0170 static struct device_attribute *sysfs_device_attr_sustain = {
0171         &dev_attr_sustain,
0172         };
0173 
0174 /* Output routine for the sysfs octave file */
0175 static ssize_t show_octave(struct device *dev,
0176     struct device_attribute *attr, char *buf)
0177 {
0178     struct hid_device *hdev = to_hid_device(dev);
0179     struct pk_device *pk = hid_get_drvdata(hdev);
0180 
0181     dbg_hid("pcmidi sysfs read octave=%d\n", pk->pm->midi_octave);
0182 
0183     return sprintf(buf, "%d (min:%d, max:%d)\n", pk->pm->midi_octave,
0184         PCMIDI_OCTAVE_MIN, PCMIDI_OCTAVE_MAX);
0185 }
0186 
0187 /* Input routine for the sysfs octave file */
0188 static ssize_t store_octave(struct device *dev,
0189     struct device_attribute *attr, const char *buf, size_t count)
0190 {
0191     struct hid_device *hdev = to_hid_device(dev);
0192     struct pk_device *pk = hid_get_drvdata(hdev);
0193 
0194     int octave = 0;
0195 
0196     if (sscanf(buf, "%d", &octave) > 0 &&
0197         octave >= PCMIDI_OCTAVE_MIN && octave <= PCMIDI_OCTAVE_MAX) {
0198         dbg_hid("pcmidi sysfs write octave=%d\n", octave);
0199         pk->pm->midi_octave = octave;
0200         return strlen(buf);
0201     }
0202     return -EINVAL;
0203 }
0204 
0205 static DEVICE_ATTR(octave, S_IRUGO | S_IWUSR | S_IWGRP, show_octave,
0206         store_octave);
0207 
0208 static struct device_attribute *sysfs_device_attr_octave = {
0209         &dev_attr_octave,
0210         };
0211 
0212 
0213 static void pcmidi_send_note(struct pcmidi_snd *pm,
0214     unsigned char status, unsigned char note, unsigned char velocity)
0215 {
0216     unsigned long flags;
0217     unsigned char buffer[3];
0218 
0219     buffer[0] = status;
0220     buffer[1] = note;
0221     buffer[2] = velocity;
0222 
0223     spin_lock_irqsave(&pm->rawmidi_in_lock, flags);
0224 
0225     if (!pm->in_substream)
0226         goto drop_note;
0227     if (!test_bit(pm->in_substream->number, &pm->in_triggered))
0228         goto drop_note;
0229 
0230     snd_rawmidi_receive(pm->in_substream, buffer, 3);
0231 
0232 drop_note:
0233     spin_unlock_irqrestore(&pm->rawmidi_in_lock, flags);
0234 
0235     return;
0236 }
0237 
0238 static void pcmidi_sustained_note_release(struct timer_list *t)
0239 {
0240     struct pcmidi_sustain *pms = from_timer(pms, t, timer);
0241 
0242     pcmidi_send_note(pms->pm, pms->status, pms->note, pms->velocity);
0243     pms->in_use = 0;
0244 }
0245 
0246 static void init_sustain_timers(struct pcmidi_snd *pm)
0247 {
0248     struct pcmidi_sustain *pms;
0249     unsigned i;
0250 
0251     for (i = 0; i < PCMIDI_SUSTAINED_MAX; i++) {
0252         pms = &pm->sustained_notes[i];
0253         pms->in_use = 0;
0254         pms->pm = pm;
0255         timer_setup(&pms->timer, pcmidi_sustained_note_release, 0);
0256     }
0257 }
0258 
0259 static void stop_sustain_timers(struct pcmidi_snd *pm)
0260 {
0261     struct pcmidi_sustain *pms;
0262     unsigned i;
0263 
0264     for (i = 0; i < PCMIDI_SUSTAINED_MAX; i++) {
0265         pms = &pm->sustained_notes[i];
0266         pms->in_use = 1;
0267         del_timer_sync(&pms->timer);
0268     }
0269 }
0270 
0271 static int pcmidi_get_output_report(struct pcmidi_snd *pm)
0272 {
0273     struct hid_device *hdev = pm->pk->hdev;
0274     struct hid_report *report;
0275 
0276     list_for_each_entry(report,
0277         &hdev->report_enum[HID_OUTPUT_REPORT].report_list, list) {
0278         if (!(6 == report->id))
0279             continue;
0280 
0281         if (report->maxfield < 1) {
0282             hid_err(hdev, "output report is empty\n");
0283             break;
0284         }
0285         if (report->field[0]->report_count != 2) {
0286             hid_err(hdev, "field count too low\n");
0287             break;
0288         }
0289         pm->pcmidi_report6 = report;
0290         return 0;
0291     }
0292     /* should never get here */
0293     return -ENODEV;
0294 }
0295 
0296 static void pcmidi_submit_output_report(struct pcmidi_snd *pm, int state)
0297 {
0298     struct hid_device *hdev = pm->pk->hdev;
0299     struct hid_report *report = pm->pcmidi_report6;
0300     report->field[0]->value[0] = 0x01;
0301     report->field[0]->value[1] = state;
0302 
0303     hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
0304 }
0305 
0306 static int pcmidi_handle_report1(struct pcmidi_snd *pm, u8 *data)
0307 {
0308     u32 bit_mask;
0309 
0310     bit_mask = data[1];
0311     bit_mask = (bit_mask << 8) | data[2];
0312     bit_mask = (bit_mask << 8) | data[3];
0313 
0314     dbg_hid("pcmidi mode: %d\n", pm->midi_mode);
0315 
0316     /*KEY_MAIL or octave down*/
0317     if (pm->midi_mode && bit_mask == 0x004000) {
0318         /* octave down */
0319         pm->midi_octave--;
0320         if (pm->midi_octave < -2)
0321             pm->midi_octave = -2;
0322         dbg_hid("pcmidi mode: %d octave: %d\n",
0323             pm->midi_mode, pm->midi_octave);
0324         return 1;
0325     }
0326     /*KEY_WWW or sustain*/
0327     else if (pm->midi_mode && bit_mask == 0x000004) {
0328         /* sustain on/off*/
0329         pm->midi_sustain_mode ^= 0x1;
0330         return 1;
0331     }
0332 
0333     return 0; /* continue key processing */
0334 }
0335 
0336 static int pcmidi_handle_report3(struct pcmidi_snd *pm, u8 *data, int size)
0337 {
0338     struct pcmidi_sustain *pms;
0339     unsigned i, j;
0340     unsigned char status, note, velocity;
0341 
0342     unsigned num_notes = (size-1)/2;
0343     for (j = 0; j < num_notes; j++) {
0344         note = data[j*2+1];
0345         velocity = data[j*2+2];
0346 
0347         if (note < 0x81) { /* note on */
0348             status = 128 + 16 + pm->midi_channel; /* 1001nnnn */
0349             note = note - 0x54 + PCMIDI_MIDDLE_C +
0350                 (pm->midi_octave * 12);
0351             if (0 == velocity)
0352                 velocity = 1; /* force note on */
0353         } else { /* note off */
0354             status = 128 + pm->midi_channel; /* 1000nnnn */
0355             note = note - 0x94 + PCMIDI_MIDDLE_C +
0356                 (pm->midi_octave*12);
0357 
0358             if (pm->midi_sustain_mode) {
0359                 for (i = 0; i < PCMIDI_SUSTAINED_MAX; i++) {
0360                     pms = &pm->sustained_notes[i];
0361                     if (!pms->in_use) {
0362                         pms->status = status;
0363                         pms->note = note;
0364                         pms->velocity = velocity;
0365                         pms->in_use = 1;
0366 
0367                         mod_timer(&pms->timer,
0368                             jiffies +
0369                     msecs_to_jiffies(pm->midi_sustain));
0370                         return 1;
0371                     }
0372                 }
0373             }
0374         }
0375         pcmidi_send_note(pm, status, note, velocity);
0376     }
0377 
0378     return 1;
0379 }
0380 
0381 static int pcmidi_handle_report4(struct pcmidi_snd *pm, u8 *data)
0382 {
0383     unsigned    key;
0384     u32     bit_mask;
0385     u32     bit_index;
0386 
0387     bit_mask = data[1];
0388     bit_mask = (bit_mask << 8) | data[2];
0389     bit_mask = (bit_mask << 8) | data[3];
0390 
0391     /* break keys */
0392     for (bit_index = 0; bit_index < 24; bit_index++) {
0393         if (!((0x01 << bit_index) & bit_mask)) {
0394             input_event(pm->input_ep82, EV_KEY,
0395                 pm->last_key[bit_index], 0);
0396             pm->last_key[bit_index] = 0;
0397         }
0398     }
0399 
0400     /* make keys */
0401     for (bit_index = 0; bit_index < 24; bit_index++) {
0402         key = 0;
0403         switch ((0x01 << bit_index) & bit_mask) {
0404         case 0x000010: /* Fn lock*/
0405             pm->fn_state ^= 0x000010;
0406             if (pm->fn_state)
0407                 pcmidi_submit_output_report(pm, 0xc5);
0408             else
0409                 pcmidi_submit_output_report(pm, 0xc6);
0410             continue;
0411         case 0x020000: /* midi launcher..send a key (qwerty) or not? */
0412             pcmidi_submit_output_report(pm, 0xc1);
0413             pm->midi_mode ^= 0x01;
0414 
0415             dbg_hid("pcmidi mode: %d\n", pm->midi_mode);
0416             continue;
0417         case 0x100000: /* KEY_MESSENGER or octave up */
0418             dbg_hid("pcmidi mode: %d\n", pm->midi_mode);
0419             if (pm->midi_mode) {
0420                 pm->midi_octave++;
0421                 if (pm->midi_octave > 2)
0422                     pm->midi_octave = 2;
0423                 dbg_hid("pcmidi mode: %d octave: %d\n",
0424                     pm->midi_mode, pm->midi_octave);
0425                 continue;
0426             } else
0427                 key = KEY_MESSENGER;
0428             break;
0429         case 0x400000:
0430             key = KEY_CALENDAR;
0431             break;
0432         case 0x080000:
0433             key = KEY_ADDRESSBOOK;
0434             break;
0435         case 0x040000:
0436             key = KEY_DOCUMENTS;
0437             break;
0438         case 0x800000:
0439             key = KEY_WORDPROCESSOR;
0440             break;
0441         case 0x200000:
0442             key = KEY_SPREADSHEET;
0443             break;
0444         case 0x010000:
0445             key = KEY_COFFEE;
0446             break;
0447         case 0x000100:
0448             key = KEY_HELP;
0449             break;
0450         case 0x000200:
0451             key = KEY_SEND;
0452             break;
0453         case 0x000400:
0454             key = KEY_REPLY;
0455             break;
0456         case 0x000800:
0457             key = KEY_FORWARDMAIL;
0458             break;
0459         case 0x001000:
0460             key = KEY_NEW;
0461             break;
0462         case 0x002000:
0463             key = KEY_OPEN;
0464             break;
0465         case 0x004000:
0466             key = KEY_CLOSE;
0467             break;
0468         case 0x008000:
0469             key = KEY_SAVE;
0470             break;
0471         case 0x000001:
0472             key = KEY_UNDO;
0473             break;
0474         case 0x000002:
0475             key = KEY_REDO;
0476             break;
0477         case 0x000004:
0478             key = KEY_SPELLCHECK;
0479             break;
0480         case 0x000008:
0481             key = KEY_PRINT;
0482             break;
0483         }
0484         if (key) {
0485             input_event(pm->input_ep82, EV_KEY, key, 1);
0486             pm->last_key[bit_index] = key;
0487         }
0488     }
0489 
0490     return 1;
0491 }
0492 
0493 static int pcmidi_handle_report(
0494     struct pcmidi_snd *pm, unsigned report_id, u8 *data, int size)
0495 {
0496     int ret = 0;
0497 
0498     switch (report_id) {
0499     case 0x01: /* midi keys (qwerty)*/
0500         ret = pcmidi_handle_report1(pm, data);
0501         break;
0502     case 0x03: /* midi keyboard (musical)*/
0503         ret = pcmidi_handle_report3(pm, data, size);
0504         break;
0505     case 0x04: /* multimedia/midi keys (qwerty)*/
0506         ret = pcmidi_handle_report4(pm, data);
0507         break;
0508     }
0509     return ret;
0510 }
0511 
0512 static void pcmidi_setup_extra_keys(
0513     struct pcmidi_snd *pm, struct input_dev *input)
0514 {
0515     /* reassigned functionality for N/A keys
0516         MY PICTURES =>  KEY_WORDPROCESSOR
0517         MY MUSIC=>  KEY_SPREADSHEET
0518     */
0519     static const unsigned int keys[] = {
0520         KEY_FN,
0521         KEY_MESSENGER, KEY_CALENDAR,
0522         KEY_ADDRESSBOOK, KEY_DOCUMENTS,
0523         KEY_WORDPROCESSOR,
0524         KEY_SPREADSHEET,
0525         KEY_COFFEE,
0526         KEY_HELP, KEY_SEND,
0527         KEY_REPLY, KEY_FORWARDMAIL,
0528         KEY_NEW, KEY_OPEN,
0529         KEY_CLOSE, KEY_SAVE,
0530         KEY_UNDO, KEY_REDO,
0531         KEY_SPELLCHECK, KEY_PRINT,
0532         0
0533     };
0534 
0535     const unsigned int *pkeys = &keys[0];
0536     unsigned short i;
0537 
0538     if (pm->ifnum != 1)  /* only set up ONCE for interace 1 */
0539         return;
0540 
0541     pm->input_ep82 = input;
0542 
0543     for (i = 0; i < 24; i++)
0544         pm->last_key[i] = 0;
0545 
0546     while (*pkeys != 0) {
0547         set_bit(*pkeys, pm->input_ep82->keybit);
0548         ++pkeys;
0549     }
0550 }
0551 
0552 static int pcmidi_set_operational(struct pcmidi_snd *pm)
0553 {
0554     int rc;
0555 
0556     if (pm->ifnum != 1)
0557         return 0; /* only set up ONCE for interace 1 */
0558 
0559     rc = pcmidi_get_output_report(pm);
0560     if (rc < 0)
0561         return rc;
0562     pcmidi_submit_output_report(pm, 0xc1);
0563     return 0;
0564 }
0565 
0566 static int pcmidi_snd_free(struct snd_device *dev)
0567 {
0568     return 0;
0569 }
0570 
0571 static int pcmidi_in_open(struct snd_rawmidi_substream *substream)
0572 {
0573     struct pcmidi_snd *pm = substream->rmidi->private_data;
0574 
0575     dbg_hid("pcmidi in open\n");
0576     pm->in_substream = substream;
0577     return 0;
0578 }
0579 
0580 static int pcmidi_in_close(struct snd_rawmidi_substream *substream)
0581 {
0582     dbg_hid("pcmidi in close\n");
0583     return 0;
0584 }
0585 
0586 static void pcmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
0587 {
0588     struct pcmidi_snd *pm = substream->rmidi->private_data;
0589 
0590     dbg_hid("pcmidi in trigger %d\n", up);
0591 
0592     pm->in_triggered = up;
0593 }
0594 
0595 static const struct snd_rawmidi_ops pcmidi_in_ops = {
0596     .open = pcmidi_in_open,
0597     .close = pcmidi_in_close,
0598     .trigger = pcmidi_in_trigger
0599 };
0600 
0601 static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
0602 {
0603     static int dev;
0604     struct snd_card *card;
0605     struct snd_rawmidi *rwmidi;
0606     int err;
0607 
0608     static struct snd_device_ops ops = {
0609         .dev_free = pcmidi_snd_free,
0610     };
0611 
0612     if (pm->ifnum != 1)
0613         return 0; /* only set up midi device ONCE for interace 1 */
0614 
0615     if (dev >= SNDRV_CARDS)
0616         return -ENODEV;
0617 
0618     if (!enable[dev]) {
0619         dev++;
0620         return -ENOENT;
0621     }
0622 
0623     /* Setup sound card */
0624 
0625     err = snd_card_new(&pm->pk->hdev->dev, index[dev], id[dev],
0626                THIS_MODULE, 0, &card);
0627     if (err < 0) {
0628         pk_error("failed to create pc-midi sound card\n");
0629         err = -ENOMEM;
0630         goto fail;
0631     }
0632     pm->card = card;
0633 
0634     /* Setup sound device */
0635     err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, pm, &ops);
0636     if (err < 0) {
0637         pk_error("failed to create pc-midi sound device: error %d\n",
0638             err);
0639         goto fail;
0640     }
0641 
0642     strncpy(card->driver, shortname, sizeof(card->driver));
0643     strncpy(card->shortname, shortname, sizeof(card->shortname));
0644     strncpy(card->longname, longname, sizeof(card->longname));
0645 
0646     /* Set up rawmidi */
0647     err = snd_rawmidi_new(card, card->shortname, 0,
0648                   0, 1, &rwmidi);
0649     if (err < 0) {
0650         pk_error("failed to create pc-midi rawmidi device: error %d\n",
0651             err);
0652         goto fail;
0653     }
0654     pm->rwmidi = rwmidi;
0655     strncpy(rwmidi->name, card->shortname, sizeof(rwmidi->name));
0656     rwmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT;
0657     rwmidi->private_data = pm;
0658 
0659     snd_rawmidi_set_ops(rwmidi, SNDRV_RAWMIDI_STREAM_INPUT,
0660         &pcmidi_in_ops);
0661 
0662     /* create sysfs variables */
0663     err = device_create_file(&pm->pk->hdev->dev,
0664                  sysfs_device_attr_channel);
0665     if (err < 0) {
0666         pk_error("failed to create sysfs attribute channel: error %d\n",
0667             err);
0668         goto fail;
0669     }
0670 
0671     err = device_create_file(&pm->pk->hdev->dev,
0672                 sysfs_device_attr_sustain);
0673     if (err < 0) {
0674         pk_error("failed to create sysfs attribute sustain: error %d\n",
0675             err);
0676         goto fail_attr_sustain;
0677     }
0678 
0679     err = device_create_file(&pm->pk->hdev->dev,
0680              sysfs_device_attr_octave);
0681     if (err < 0) {
0682         pk_error("failed to create sysfs attribute octave: error %d\n",
0683             err);
0684         goto fail_attr_octave;
0685     }
0686 
0687     spin_lock_init(&pm->rawmidi_in_lock);
0688 
0689     init_sustain_timers(pm);
0690     err = pcmidi_set_operational(pm);
0691     if (err < 0) {
0692         pk_error("failed to find output report\n");
0693         goto fail_register;
0694     }
0695 
0696     /* register it */
0697     err = snd_card_register(card);
0698     if (err < 0) {
0699         pk_error("failed to register pc-midi sound card: error %d\n",
0700              err);
0701         goto fail_register;
0702     }
0703 
0704     dbg_hid("pcmidi_snd_initialise finished ok\n");
0705     return 0;
0706 
0707 fail_register:
0708     stop_sustain_timers(pm);
0709     device_remove_file(&pm->pk->hdev->dev, sysfs_device_attr_octave);
0710 fail_attr_octave:
0711     device_remove_file(&pm->pk->hdev->dev, sysfs_device_attr_sustain);
0712 fail_attr_sustain:
0713     device_remove_file(&pm->pk->hdev->dev, sysfs_device_attr_channel);
0714 fail:
0715     if (pm->card) {
0716         snd_card_free(pm->card);
0717         pm->card = NULL;
0718     }
0719     return err;
0720 }
0721 
0722 static int pcmidi_snd_terminate(struct pcmidi_snd *pm)
0723 {
0724     if (pm->card) {
0725         stop_sustain_timers(pm);
0726 
0727         device_remove_file(&pm->pk->hdev->dev,
0728             sysfs_device_attr_channel);
0729         device_remove_file(&pm->pk->hdev->dev,
0730             sysfs_device_attr_sustain);
0731         device_remove_file(&pm->pk->hdev->dev,
0732             sysfs_device_attr_octave);
0733 
0734         snd_card_disconnect(pm->card);
0735         snd_card_free_when_closed(pm->card);
0736     }
0737 
0738     return 0;
0739 }
0740 
0741 /*
0742  * PC-MIDI report descriptor for report id is wrong.
0743  */
0744 static __u8 *pk_report_fixup(struct hid_device *hdev, __u8 *rdesc,
0745         unsigned int *rsize)
0746 {
0747     if (*rsize == 178 &&
0748           rdesc[111] == 0x06 && rdesc[112] == 0x00 &&
0749           rdesc[113] == 0xff) {
0750         hid_info(hdev,
0751              "fixing up pc-midi keyboard report descriptor\n");
0752 
0753         rdesc[144] = 0x18; /* report 4: was 0x10 report count */
0754     }
0755     return rdesc;
0756 }
0757 
0758 static int pk_input_mapping(struct hid_device *hdev, struct hid_input *hi,
0759         struct hid_field *field, struct hid_usage *usage,
0760         unsigned long **bit, int *max)
0761 {
0762     struct pk_device *pk = hid_get_drvdata(hdev);
0763     struct pcmidi_snd *pm;
0764 
0765     pm = pk->pm;
0766 
0767     if (HID_UP_MSVENDOR == (usage->hid & HID_USAGE_PAGE) &&
0768         1 == pm->ifnum) {
0769         pcmidi_setup_extra_keys(pm, hi->input);
0770         return 0;
0771     }
0772 
0773     return 0;
0774 }
0775 
0776 
0777 static int pk_raw_event(struct hid_device *hdev, struct hid_report *report,
0778     u8 *data, int size)
0779 {
0780     struct pk_device *pk = hid_get_drvdata(hdev);
0781     int ret = 0;
0782 
0783     if (1 == pk->pm->ifnum) {
0784         if (report->id == data[0])
0785             switch (report->id) {
0786             case 0x01: /* midi keys (qwerty)*/
0787             case 0x03: /* midi keyboard (musical)*/
0788             case 0x04: /* extra/midi keys (qwerty)*/
0789                 ret = pcmidi_handle_report(pk->pm,
0790                         report->id, data, size);
0791                 break;
0792             }
0793     }
0794 
0795     return ret;
0796 }
0797 
0798 static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
0799 {
0800     int ret;
0801     struct usb_interface *intf;
0802     unsigned short ifnum;
0803     unsigned long quirks = id->driver_data;
0804     struct pk_device *pk;
0805     struct pcmidi_snd *pm = NULL;
0806 
0807     if (!hid_is_usb(hdev))
0808         return -EINVAL;
0809 
0810     intf = to_usb_interface(hdev->dev.parent);
0811     ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
0812 
0813     pk = kzalloc(sizeof(*pk), GFP_KERNEL);
0814     if (pk == NULL) {
0815         hid_err(hdev, "can't alloc descriptor\n");
0816         return -ENOMEM;
0817     }
0818 
0819     pk->hdev = hdev;
0820 
0821     pm = kzalloc(sizeof(*pm), GFP_KERNEL);
0822     if (pm == NULL) {
0823         hid_err(hdev, "can't alloc descriptor\n");
0824         ret = -ENOMEM;
0825         goto err_free_pk;
0826     }
0827 
0828     pm->pk = pk;
0829     pk->pm = pm;
0830     pm->ifnum = ifnum;
0831 
0832     hid_set_drvdata(hdev, pk);
0833 
0834     ret = hid_parse(hdev);
0835     if (ret) {
0836         hid_err(hdev, "hid parse failed\n");
0837         goto err_free;
0838     }
0839 
0840     if (quirks & PK_QUIRK_NOGET) { /* hid_parse cleared all the quirks */
0841         hdev->quirks |= HID_QUIRK_NOGET;
0842     }
0843 
0844     ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
0845     if (ret) {
0846         hid_err(hdev, "hw start failed\n");
0847         goto err_free;
0848     }
0849 
0850     ret = pcmidi_snd_initialise(pm);
0851     if (ret < 0)
0852         goto err_stop;
0853 
0854     return 0;
0855 err_stop:
0856     hid_hw_stop(hdev);
0857 err_free:
0858     kfree(pm);
0859 err_free_pk:
0860     kfree(pk);
0861 
0862     return ret;
0863 }
0864 
0865 static void pk_remove(struct hid_device *hdev)
0866 {
0867     struct pk_device *pk = hid_get_drvdata(hdev);
0868     struct pcmidi_snd *pm;
0869 
0870     pm = pk->pm;
0871     if (pm) {
0872         pcmidi_snd_terminate(pm);
0873         kfree(pm);
0874     }
0875 
0876     hid_hw_stop(hdev);
0877 
0878     kfree(pk);
0879 }
0880 
0881 static const struct hid_device_id pk_devices[] = {
0882     {HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS,
0883         USB_DEVICE_ID_PRODIKEYS_PCMIDI),
0884         .driver_data = PK_QUIRK_NOGET},
0885     { }
0886 };
0887 MODULE_DEVICE_TABLE(hid, pk_devices);
0888 
0889 static struct hid_driver pk_driver = {
0890     .name = "prodikeys",
0891     .id_table = pk_devices,
0892     .report_fixup = pk_report_fixup,
0893     .input_mapping = pk_input_mapping,
0894     .raw_event = pk_raw_event,
0895     .probe = pk_probe,
0896     .remove = pk_remove,
0897 };
0898 module_hid_driver(pk_driver);
0899 
0900 MODULE_LICENSE("GPL");