// SPDX-License-Identifier: GPL-2.0-or-later /* * usbusx2y.c - ALSA USB US-428 Driver * 2005-04-14 Karsten Wiese Version 0.8.7.2: Call snd_card_free() instead of snd_card_free_in_thread() to prevent oops with dead keyboard symptom. Tested ok with kernel 2.6.12-rc2.
2004-12-14 Karsten Wiese Version 0.8.7.1: snd_pcm_open for rawusb pcm-devices now returns -EBUSY if called without rawusb's hwdep device being open.
2004-12-02 Karsten Wiese Version 0.8.7: Use macro usb_maxpacket() for portability.
2004-10-26 Karsten Wiese Version 0.8.6: wake_up() process waiting in usx2y_urbs_start() on error.
2004-10-21 Karsten Wiese Version 0.8.5: nrpacks is runtime or compiletime configurable now with tested values from 1 to 4.
2004-10-03 Karsten Wiese Version 0.8.2: Avoid any possible racing while in prepare callback.
2004-09-30 Karsten Wiese Version 0.8.0: Simplified things and made ohci work again.
2004-09-20 Karsten Wiese Version 0.7.3: Use usb_kill_urb() instead of deprecated (kernel 2.6.9) usb_unlink_urb().
2004-07-13 Karsten Wiese Version 0.7.1: Don't sleep in START/STOP callbacks anymore. us428 channels C/D not handled just for this version, sorry.
2004-06-21 Karsten Wiese Version 0.6.4: Temporarely suspend midi input to sanely call usb_set_interface() when setting format.
2004-06-12 Karsten Wiese Version 0.6.3: Made it thus the following rule is enforced: "All pcm substreams of one usx2y have to operate at the same rate & format."
2004-04-06 Karsten Wiese Version 0.6.0: Runs on 2.6.5 kernel without any "--with-debug=" things. us224 reported running.
2004-01-14 Karsten Wiese Version 0.5.1: Runs with 2.6.1 kernel.
2003-12-30 Karsten Wiese Version 0.4.1: Fix 24Bit 4Channel capturing for the us428.
2003-11-27 Karsten Wiese, Martin Langer Version 0.4: us122 support. us224 could be tested by uncommenting the sections containing USB_ID_US224
2003-06-18 Karsten Wiese Version 0.0.5: changed to compile with kernel 2.4.21 and alsa 0.9.4
2002-10-16 Karsten Wiese Version 0.0.4: compiles again with alsa-current. USB_ISO_ASAP not used anymore (most of the time), instead urb->start_frame is calculated here now, some calls inside usb-driver don't need to happen anymore.
To get the best out of this: Disable APM-support in the kernel as APM-BIOS calls (once each second) hard disable interrupt for many precious milliseconds. This helped me much on my slowish PII 400 & PIII 500. ACPI yet untested but might cause the same bad behaviour. Use a kernel with lowlatency and preemptiv patches applied. To autoload snd-usb-midi append a line post-install snd-usb-us428 modprobe snd-usb-midi to /etc/modules.conf.
known problems: sliders, knobs, lights not yet handled except MASTER Volume slider. "pcm -c 2" doesn't work. "pcm -c 2 -m direct_interleaved" does. KDE3: "Enable full duplex operation" deadlocks.
2002-08-31 Karsten Wiese Version 0.0.3: audio also simplex; simplifying: iso urbs only 1 packet, melted structs. ASYNC_UNLINK not used anymore: no more crashes so far..... for alsa 0.9 rc3.
2002-08-09 Karsten Wiese Version 0.0.2: midi works with snd-usb-midi, audio (only fullduplex now) with i.e. bristol. The firmware has been sniffed from win2k us-428 driver 3.09.
#ifdef USX2Y_NRPACKS_VARIABLE int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */
module_param(nrpacks, int, 0444);
MODULE_PARM_DESC(nrpacks, "Number of packets per URB."); #endif
/* * pipe 4 is used for switching the lamps, setting samplerate, volumes ....
*/ staticvoid i_usx2y_out04_int(struct urb *urb)
{ #ifdef CONFIG_SND_DEBUG if (urb->status) { int i; struct usx2ydev *usx2y = urb->context;
for (i = 0; i < 10 && usx2y->as04.urb[i] != urb; i++)
;
dev_dbg(&urb->dev->dev, "%s urb %i status=%i\n", __func__, i, urb->status);
} #endif
}
staticvoid i_usx2y_in04_int(struct urb *urb)
{ int err = 0; struct usx2ydev *usx2y = urb->context; struct us428ctls_sharedmem *us428ctls = usx2y->us428ctls_sharedmem; struct us428_p4out *p4out; int i, j, n, diff, send;
usx2y->in04_int_calls++;
if (urb->status) {
dev_dbg(&urb->dev->dev, "Interrupt Pipe 4 came back with status=%i\n", urb->status); return;
}
if (us428ctls) {
diff = -1; if (us428ctls->ctl_snapshot_last == -2) {
diff = 0;
memcpy(usx2y->in04_last, usx2y->in04_buf, sizeof(usx2y->in04_last));
us428ctls->ctl_snapshot_last = -1;
} else { for (i = 0; i < 21; i++) { if (usx2y->in04_last[i] != ((char *)usx2y->in04_buf)[i]) { if (diff < 0)
diff = i;
usx2y->in04_last[i] = ((char *)usx2y->in04_buf)[i];
}
}
} if (diff >= 0) {
n = us428ctls->ctl_snapshot_last + 1; if (n >= N_US428_CTL_BUFS || n < 0)
n = 0;
memcpy(us428ctls->ctl_snapshot + n, usx2y->in04_buf, sizeof(us428ctls->ctl_snapshot[0]));
us428ctls->ctl_snapshot_differs_at[n] = diff;
us428ctls->ctl_snapshot_last = n;
wake_up(&usx2y->us428ctls_wait_queue_head);
}
}
if (usx2y->us04) { if (!usx2y->us04->submitted) { do {
err = usb_submit_urb(usx2y->us04->urb[usx2y->us04->submitted++], GFP_ATOMIC);
} while (!err && usx2y->us04->submitted < usx2y->us04->len);
}
} else { if (us428ctls && us428ctls->p4out_last >= 0 && us428ctls->p4out_last < N_US428_P4OUT_BUFS) { if (us428ctls->p4out_last != us428ctls->p4out_sent) {
send = us428ctls->p4out_sent + 1; if (send >= N_US428_P4OUT_BUFS)
send = 0; for (j = 0; j < URBS_ASYNC_SEQ && !err; ++j) { if (!usx2y->as04.urb[j]->status) {
p4out = us428ctls->p4out + send; // FIXME if more than 1 p4out is new, 1 gets lost.
usb_fill_bulk_urb(usx2y->as04.urb[j], usx2y->dev,
usb_sndbulkpipe(usx2y->dev, 0x04), &p4out->val.vol,
p4out->type == ELT_LIGHT ? sizeof(struct us428_lights) : 5,
i_usx2y_out04_int, usx2y);
err = usb_submit_urb(usx2y->as04.urb[j], GFP_ATOMIC);
us428ctls->p4out_sent = send; break;
}
}
}
}
}
if (err)
dev_err(&urb->dev->dev, "in04_int() usb_submit_urb err=%i\n", err);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.