diff --git a/data/settings/media/usb_vision/Locales/Australia Air b/data/settings/media/usb_vision/Locales/Australia Air new file mode 100644 index 0000000000..7923fe3029 --- /dev/null +++ b/data/settings/media/usb_vision/Locales/Australia Air @@ -0,0 +1,81 @@ +; +; Tuner locale file for BeOS USBVision driver +; +; "Australia Broadcast channels" +; +;=========================================================== +; This file is a part of BeOS USBVision driver project. +; Copyright (c) 2003 by Siarzuk Zharski +; +; This file may be used under the terms of the BSD License +; Look into the file "License" for details. +; +; $Source: /cvsroot/sis4be/usbvision/Locales/Australia\040Air,v $ +; $Author: zharik $ +; $Revision: 1.2 $ +; $Date: 2003/07/09 04:58:08 $ +;=========================================================== +; +; Format of this file: +; +; The file begins with the name of locale preceded with "@"-sign. This name will be +; visible for user in Tuner Locale settings. +; Channels are presented as frequency <-> name pairs. +; The Frequency is in Hz and name begins just after the first space character +; after frequency number. The name ends at the end of line. +; +; All lines beginning with ";"-sign are comments and will be ignored. +; +@Australia Air + 46250000 0 + 57250000 1 + 64250000 2 + 86250000 3 + 95250000 4 +102250000 5 +138250000 5A +175250000 6 +182250000 7 +189250000 8 +196250000 9 +209250000 10 +216250000 11 +527250000 28 +534250000 29 +541250000 30 +548250000 31 +555250000 32 +562250000 33 +569250000 34 +576250000 35 +604250000 39 +611250000 40 +618250000 41 +625250000 42 +632250000 43 +639250000 44 +646250000 45 +653250000 46 +660250000 47 +667250000 48 +674250000 49 +681250000 50 +688250000 51 +695250000 52 +702250000 53 +709250000 54 +716250000 55 +723250000 56 +730250000 57 +737250000 58 +744250000 59 +751250000 60 +758250000 61 +765250000 62 +772250000 63 +779250000 64 +786250000 65 +793250000 66 +800250000 67 +807250000 68 +814250000 69 diff --git a/data/settings/media/usb_vision/Locales/FM Radio b/data/settings/media/usb_vision/Locales/FM Radio new file mode 100644 index 0000000000..cb880bffc4 --- /dev/null +++ b/data/settings/media/usb_vision/Locales/FM Radio @@ -0,0 +1,228 @@ +; +; Tuner locale file for BeOS USBVision driver +; +; "FM Radio channels" +; +;=========================================================== +; This file is a part of BeOS USBVision driver project. +; Copyright (c) 2003 by Siarzuk Zharski +; +; This file may be used under the terms of the BSD License +; Look into the file "License" for details. +; +; $Source: /cvsroot/sis4be/usbvision/Locales/FM\040Radio,v $ +; $Author: zharik $ +; $Revision: 1.2 $ +; $Date: 2003/07/09 04:58:08 $ +;=========================================================== +; +; Format of this file: +; +; The file begins with the name of locale preceded with "@"-sign. This name will be +; visible for user in Tuner Locale settings. +; Channels are presented as frequency <-> name pairs. +; The Frequency is in Hz and name begins just after the first space character +; after frequency number. The name ends at the end of line. +; +; All lines beginning with ";"-sign are comments and will be ignored. +; +; The word "Radio" in angle brakets means that channels are radio channels. +; +@FM Radio +; + 87500000 87,5 + 87600000 87,6 + 87700000 87,7 + 87800000 87,8 + 87900000 87,9 + 88000000 88,0 + 88100000 88,1 + 88200000 88,2 + 88300000 88,3 + 88400000 88,4 + 88500000 88,5 + 88600000 88,6 + 88700000 88,7 + 88800000 88,8 + 88900000 88,9 + 89000000 89,0 + 89100000 89,1 + 89200000 89,2 + 89300000 89,3 + 89400000 89,4 + 89500000 89,5 + 89600000 89,6 + 89700000 89,7 + 89800000 89,8 + 89900000 89,9 + 90000000 90,0 + 90100000 90,1 + 90200000 90,2 + 90300000 90,3 + 90400000 90,4 + 90500000 90,5 + 90600000 90,6 + 90700000 90,7 + 90800000 90,8 + 90900000 90,9 + 91000000 91,0 + 91100000 91,1 + 91200000 91,2 + 91300000 91,3 + 91400000 91,4 + 91500000 91,5 + 91600000 91,6 + 91700000 91,7 + 91800000 91,8 + 91900000 91,9 + 92000000 92,0 + 92100000 92,1 + 92200000 92,2 + 92300000 92,3 + 92400000 92,4 + 92500000 92,5 + 92600000 92,6 + 92700000 92,7 + 92800000 92,8 + 92900000 92,9 + 93000000 93,0 + 93100000 93,1 + 93200000 93,2 + 93300000 93,3 + 93400000 93,4 + 93500000 93,5 + 93600000 93,6 + 93700000 93,7 + 93800000 93,8 + 93900000 93,9 + 94000000 94,0 + 94100000 94,1 + 94200000 94,2 + 94300000 94,3 + 94400000 94,4 + 94500000 94,5 + 94600000 94,6 + 94700000 94,7 + 94800000 94,8 + 94900000 94,9 + 95000000 95,0 + 95100000 95,1 + 95200000 95,2 + 95300000 95,3 + 95400000 95,4 + 95500000 95,5 + 95600000 95,6 + 95700000 95,7 + 95800000 95,8 + 95900000 95,9 + 96000000 96,0 + 97100000 97,1 + 97200000 97,2 + 97300000 97,3 + 97400000 97,4 + 97500000 97,5 + 97600000 97,6 + 97700000 97,7 + 97800000 97,8 + 97900000 97,9 + 98000000 98,0 + 98100000 98,1 + 98200000 98,2 + 98300000 98,3 + 98400000 98,4 + 98500000 98,5 + 98600000 98,6 + 98700000 98,7 + 98800000 98,8 + 98900000 98,9 + 99000000 99,0 + 99100000 99,1 + 99200000 99,2 + 99300000 99,3 + 99400000 99,4 + 99500000 99,5 + 99600000 99,6 + 99700000 99,7 + 99800000 99,8 + 99900000 99,9 +100000000 100,0 +100100000 100,1 +100200000 100,2 +100300000 100,3 +100400000 100,4 +100500000 100,5 +100600000 100,6 +100700000 100,7 +100800000 100,8 +100900000 100,9 +101000000 101,0 +101100000 101,1 +101200000 101,2 +101300000 101,3 +101400000 101,4 +101500000 101,5 +101600000 101,6 +101700000 101,7 +101800000 101,8 +101900000 101,9 +102000000 102,0 +102100000 102,1 +102200000 102,2 +102300000 102,3 +102400000 102,4 +102500000 102,5 +102600000 102,6 +102700000 102,7 +102800000 102,8 +102900000 102,9 +103000000 103,0 +103100000 103,1 +103200000 103,2 +103300000 103,3 +103400000 103,4 +103500000 103,5 +103600000 103,6 +103700000 103,7 +103800000 103,8 +103900000 103,9 +104000000 104,0 +104100000 104,1 +104200000 104,2 +104300000 104,3 +104400000 104,4 +104500000 104,5 +104600000 104,6 +104700000 104,7 +104800000 104,8 +104900000 104,9 +105000000 105,0 +105100000 105,1 +105200000 105,2 +105300000 105,3 +105400000 105,4 +105500000 105,5 +105600000 105,6 +105700000 105,7 +105800000 105,8 +105900000 105,9 +106000000 106,0 +106100000 106,1 +106200000 106,2 +106300000 106,3 +106400000 106,4 +106500000 106,5 +106600000 106,6 +106700000 106,7 +106800000 106,8 +106900000 106,9 +107000000 107,0 +107100000 107,1 +107200000 107,2 +107300000 107,3 +107400000 107,4 +107500000 107,5 +107600000 107,6 +107700000 107,7 +107800000 107,8 +107900000 107,9 +108000000 108,0 diff --git a/data/settings/media/usb_vision/Locales/Ireland Air b/data/settings/media/usb_vision/Locales/Ireland Air new file mode 100644 index 0000000000..c945379d16 --- /dev/null +++ b/data/settings/media/usb_vision/Locales/Ireland Air @@ -0,0 +1,88 @@ +; +; Tuner locale file for BeOS USBVision driver +; +; "Ireland Broadcast channels" +; +;=========================================================== +; This file is a part of BeOS USBVision driver project. +; Copyright (c) 2003 by Siarzuk Zharski +; +; This file may be used under the terms of the BSD License +; Look into the file "License" for details. +; +; $Source: /cvsroot/sis4be/usbvision/Locales/Ireland\040Air,v $ +; $Author: zharik $ +; $Revision: 1.2 $ +; $Date: 2003/07/09 04:58:08 $ +;=========================================================== +; +; Format of this file: +; +; The file begins with the name of locale preceded with "@"-sign. This name will be +; visible for user in Tuner Locale settings. +; Channels are presented as frequency <-> name pairs. +; The Frequency is in Hz and name begins just after the first space character +; after frequency number. The name ends at the end of line. +; +; All lines beginning with ";"-sign are comments and will be ignored. +; +@Ireland Air + 45750000 A(2) + 53750000 B(3) + 61750000 C(4) +175250000 D(5) +183250000 E(6) +191250000 F(7) +199250000 G(8) +207250000 H(9) +215250000 I(10) +223250000 J(11) +471250000 21 +479250000 22 +487250000 23 +495250000 24 +503250000 25 +511250000 26 +519250000 27 +527250000 28 +535250000 29 +543250000 30 +551250000 31 +559250000 32 +567250000 33 +575250000 34 +583250000 35 +591250000 36 +599250000 37 +607250000 38 +615250000 39 +623250000 40 +631250000 41 +639250000 42 +647250000 43 +655250000 44 +663250000 45 +671250000 46 +679250000 47 +687250000 48 +695250000 49 +703250000 50 +711250000 51 +719250000 52 +727250000 53 +735250000 54 +743250000 55 +751250000 56 +759250000 57 +767250000 58 +775250000 59 +783250000 60 +791250000 61 +799250000 62 +807250000 63 +815250000 64 +823250000 65 +831250000 66 +839250000 67 +847250000 68 +855250000 69 diff --git a/data/settings/media/usb_vision/Locales/Japan Air b/data/settings/media/usb_vision/Locales/Japan Air new file mode 100644 index 0000000000..2e6484d7f7 --- /dev/null +++ b/data/settings/media/usb_vision/Locales/Japan Air @@ -0,0 +1,91 @@ +; +; Tuner locale file for BeOS USBVision driver +; +; "Japan Broadcast channels" +; +;=========================================================== +; This file is a part of BeOS USBVision driver project. +; Copyright (c) 2003 by Siarzuk Zharski +; +; This file may be used under the terms of the BSD License +; Look into the file "License" for details. +; +; $Source: /cvsroot/sis4be/usbvision/Locales/Japan\040Air,v $ +; $Author: zharik $ +; $Revision: 1.2 $ +; $Date: 2003/07/09 04:58:08 $ +;=========================================================== +; +; Format of this file: +; +; The file begins with the name of locale preceded with "@"-sign. This name will be +; visible for user in Tuner Locale settings. +; Channels are presented as frequency <-> name pairs. +; The Frequency is in Hz and name begins just after the first space character +; after frequency number. The name ends at the end of line. +; +; All lines beginning with ";"-sign are comments and will be ignored. +; +@Japan Air + 91250000 1 + 97250000 2 +103250000 3 +171250000 4 +177250000 5 +183250000 6 +189250000 7 +193250000 8 +199250000 9 +205250000 10 +211250000 11 +217250000 12 +471250000 13 +477250000 14 +483250000 15 +489250000 16 +495250000 17 +501250000 18 +507250000 19 +513250000 20 +519250000 21 +525250000 22 +531250000 23 +537250000 24 +543250000 25 +549250000 26 +555250000 27 +561250000 28 +567250000 29 +573250000 30 +579250000 31 +585250000 32 +591250000 33 +597250000 34 +603250000 35 +609250000 36 +615250000 37 +621250000 38 +627250000 39 +633250000 40 +639250000 41 +645250000 42 +651250000 43 +657250000 44 +663250000 45 +669250000 46 +675250000 47 +681250000 48 +687250000 49 +693250000 50 +699250000 51 +705250000 52 +711250000 53 +717250000 54 +723250000 55 +729250000 56 +735250000 57 +741250000 58 +747250000 59 +753250000 60 +759250000 61 +765250000 62 diff --git a/data/settings/media/usb_vision/Locales/Japan Cable b/data/settings/media/usb_vision/Locales/Japan Cable new file mode 100644 index 0000000000..d2140d32a6 --- /dev/null +++ b/data/settings/media/usb_vision/Locales/Japan Cable @@ -0,0 +1,92 @@ +; +; Tuner locale file for BeOS USBVision driver +; +; "Japan Cable channels" +; +;=========================================================== +; This file is a part of BeOS USBVision driver project. +; Copyright (c) 2003 by Siarzuk Zharski +; +; This file may be used under the terms of the BSD License +; Look into the file "License" for details. +; +; $Source: /cvsroot/sis4be/usbvision/Locales/Japan\040Cable,v $ +; $Author: zharik $ +; $Revision: 1.2 $ +; $Date: 2003/07/09 04:58:08 $ +;=========================================================== +; +; Format of this file: +; +; The file begins with the name of locale preceded with "@"-sign. This name will be +; visible for user in Tuner Locale settings. +; Channels are presented as frequency <-> name pairs. +; The Frequency is in Hz and name begins just after the first space character +; after frequency number. The name ends at the end of line. +; +; All lines beginning with ";"-sign are comments and will be ignored. +; +@Japan Cable + 91250000 1 + 97250000 2 +103250000 3 +171250000 4 +177250000 5 +183250000 6 +189250000 7 +193250000 8 +199250000 9 +205250000 10 +211250000 11 +217250000 12 +109250000 C13 +115250000 C14 +121250000 C15 +127250000 C16 +133250000 C17 +139250000 C18 +145250000 C19 +151250000 C20 +157250000 C21 +165250000 C22 +223250000 C23 +229250000 C24 +235250000 C25 +241250000 C26 +247250000 C27 +253250000 C28 +259250000 C29 +265250000 C30 +271250000 C31 +277250000 C32 +293250000 C33 +289250000 C34 +295250000 C35 +301250000 C36 +307250000 C37 +313250000 C38 +319250000 C39 +325250000 C40 +331250000 C41 +337250000 C42 +343250000 C43 +349250000 C44 +355250000 C45 +361250000 C46 +367250000 C47 +373250000 C48 +379250000 C49 +385250000 C50 +391250000 C51 +397250000 C52 +403250000 C53 +409250000 C54 +415250000 C55 +421250000 C56 +427250000 C57 +433250000 C58 +439250000 C59 +445250000 C60 +451250000 C61 +457250000 C62 +463250000 C63 diff --git a/data/settings/media/usb_vision/Locales/UK Air b/data/settings/media/usb_vision/Locales/UK Air new file mode 100644 index 0000000000..cce3ff4f51 --- /dev/null +++ b/data/settings/media/usb_vision/Locales/UK Air @@ -0,0 +1,104 @@ +; +; Tuner locale file for BeOS USBVision driver +; +; "Great Britain Broadcast channels" +; +;=========================================================== +; This file is a part of BeOS USBVision driver project. +; Copyright (c) 2003 by Siarzuk Zharski +; +; This file may be used under the terms of the BSD License +; Look into the file "License" for details. +; +; $Source: /cvsroot/sis4be/usbvision/Locales/UK\040Air,v $ +; $Author: zharik $ +; $Revision: 1.2 $ +; $Date: 2003/07/09 04:58:08 $ +;=========================================================== +; +; Format of this file: +; +; The file begins with the name of locale preceded with "@"-sign. This name will be +; visible for user in Tuner Locale settings. +; Channels are presented as frequency <-> name pairs. +; The Frequency is in Hz and name begins just after the first space character +; after frequency number. The name ends at the end of line. +; +; All lines beginning with ";"-sign are comments and will be ignored. +; +@UK Air + 45750000 A + 53750000 B + 61750000 C +175250000 D +183250000 E +191250000 F +199250000 G +207250000 H +215250000 J +223250000 C10 +231250000 C11 +247250000 C13 +471250000 B21 +479250000 B22 +487250000 B23 +495250000 B24 +503250000 B25 +511250000 B26 +519250000 B27 +527250000 B28 +535250000 B29 +543250000 B30 +551250000 B31 +559250000 B32 +567250000 B33 +575250000 B34 +583250000 B35 +591250000 B36 +599250000 B37 +607250000 B38 +615250000 B39 +623250000 B40 +631250000 B41 +639250000 B42 +647250000 B43 +655250000 B44 +663250000 B45 +671250000 B46 +679250000 B47 +687250000 B48 +695250000 B49 +703250000 B50 +711250000 B51 +719250000 B52 +727250000 B53 +735250000 B54 +743250000 B55 +751250000 B56 +759250000 B57 +767250000 B58 +775250000 B59 +783250000 B60 +791250000 B61 +799250000 B62 +807250000 B63 +815250000 B64 +823250000 B65 +831250000 B66 +839250000 B67 +847250000 B68 +855250000 B69 + 45000000 B1 + 51750000 B2 + 56750000 B3 + 61750000 B4 + 66750000 B5 +179750000 B6 +184750000 B7 +189750000 B8 +194750000 B9 +199750000 B10 +204750000 B11 +209750000 B12 +214750000 B13 +219750000 B14 diff --git a/data/settings/media/usb_vision/Locales/UKW Radio b/data/settings/media/usb_vision/Locales/UKW Radio new file mode 100644 index 0000000000..4f944e0258 --- /dev/null +++ b/data/settings/media/usb_vision/Locales/UKW Radio @@ -0,0 +1,113 @@ +; +; Tuner locale file for BeOS USBVision driver +; +; "Ex USSR UKW Radio channels" +; +;=========================================================== +; This file is a part of BeOS USBVision driver project. +; Copyright (c) 2003 by Siarzuk Zharski +; +; This file may be used under the terms of the BSD License +; Look into the file "License" for details. +; +; $Source: /cvsroot/sis4be/usbvision/Locales/UKW\040Radio,v $ +; $Author: zharik $ +; $Revision: 1.2 $ +; $Date: 2003/07/09 04:58:08 $ +;=========================================================== +; +; Format of this file: +; +; The file begins with the name of locale preceded with "@"-sign. This name will be +; visible for user in Tuner Locale settings. +; Channels are presented as frequency <-> name pairs. +; The Frequency is in Hz and name begins just after the first space character +; after frequency number. The name ends at the end of line. +; +; All lines beginning with ";"-sign are comments and will be ignored. +; +; The word "Radio" in angle brakets means that this channels is radio channels. +; +@UKW Radio +; +66000000 66,0 +66100000 66,1 +66200000 66,2 +66300000 66,3 +66400000 66,4 +66500000 66,5 +66600000 66,6 +66700000 66,7 +66800000 66,8 +66900000 66,9 +67000000 67,0 +67100000 67,1 +67200000 67,2 +67300000 67,3 +67400000 67,4 +67500000 67,5 +67600000 67,6 +67700000 67,7 +67800000 67,8 +67900000 67,9 +68000000 68,0 +68100000 68,1 +68200000 68,2 +68300000 68,3 +68400000 68,4 +68500000 68,5 +68600000 68,6 +68700000 68,7 +68800000 68,8 +68900000 68,9 +69000000 69,0 +69100000 69,1 +69200000 69,2 +69300000 69,3 +69400000 69,4 +69500000 69,5 +69600000 69,6 +69700000 69,7 +69800000 69,8 +69900000 69,9 +70000000 70,0 +70100000 70,1 +70200000 70,2 +70300000 70,3 +70400000 70,4 +70500000 70,5 +70600000 70,6 +70700000 70,7 +70800000 70,8 +70900000 70,9 +71000000 71,0 +71100000 71,1 +71200000 71,2 +71300000 71,3 +71400000 71,4 +71500000 71,5 +71600000 71,6 +71700000 71,7 +71800000 71,8 +71900000 71,9 +72000000 72,0 +72100000 72,1 +72200000 72,2 +72300000 72,3 +72400000 72,4 +72500000 72,5 +72600000 72,6 +72700000 72,7 +72800000 72,8 +72900000 72,9 +73000000 73,0 +73100000 73,1 +73200000 73,2 +73300000 73,3 +73400000 73,4 +73500000 73,5 +73600000 73,6 +73700000 73,7 +73800000 73,8 +73900000 73,9 +74000000 74,0 diff --git a/data/settings/media/usb_vision/Locales/US Air b/data/settings/media/usb_vision/Locales/US Air new file mode 100644 index 0000000000..01ff680896 --- /dev/null +++ b/data/settings/media/usb_vision/Locales/US Air @@ -0,0 +1,97 @@ +; +; Tuner locale file for BeOS USBVision driver +; +; "US Broadcast channels" +; +;=========================================================== +; This file is a part of BeOS USBVision driver project. +; Copyright (c) 2003 by Siarzuk Zharski +; +; This file may be used under the terms of the BSD License +; Look into the file "License" for details. +; +; $Source: /cvsroot/sis4be/usbvision/Locales/US\040Air,v $ +; $Author: zharik $ +; $Revision: 1.2 $ +; $Date: 2003/07/09 04:58:08 $ +;=========================================================== +; +; Format of this file: +; +; The file begins with the name of locale preceded with "@"-sign. This name will be +; visible for user in Tuner Locale settings. +; Channels are presented as frequency <-> name pairs. +; The Frequency is in Hz and name begins just after the first space character +; after frequency number. The name ends at the end of line. +; +; All lines beginning with ";"-sign are comments and will be ignored. +; +@US Air + 55250000 2 + 61250000 3 + 67250000 4 + 77250000 5 + 83250000 6 +175250000 7 +181250000 8 +187250000 9 +193250000 10 +199250000 11 +205250000 12 +211250000 13 +471250000 14 +477250000 15 +483250000 16 +489250000 17 +495250000 18 +501250000 19 +507250000 20 +513250000 21 +519250000 22 +525250000 23 +531250000 24 +537250000 25 +543250000 26 +549250000 27 +555250000 28 +561250000 29 +567250000 30 +573250000 31 +579250000 32 +585250000 33 +591250000 34 +597250000 35 +603250000 36 +609250000 37 +615250000 38 +621250000 39 +627250000 40 +633250000 41 +639250000 42 +645250000 43 +651250000 44 +657250000 45 +663250000 46 +669250000 47 +675250000 48 +681250000 49 +687250000 50 +693250000 51 +699250000 52 +705250000 53 +711250000 54 +717250000 55 +723250000 56 +729250000 57 +735250000 58 +741250000 59 +747250000 60 +753250000 61 +759250000 62 +765250000 63 +771250000 64 +777250000 65 +783250000 66 +789250000 67 +795250000 68 +801250000 69 diff --git a/data/settings/media/usb_vision/Locales/US Cable b/data/settings/media/usb_vision/Locales/US Cable new file mode 100644 index 0000000000..7d17246b8c --- /dev/null +++ b/data/settings/media/usb_vision/Locales/US Cable @@ -0,0 +1,154 @@ +; +; Tuner locale file for BeOS USBVision driver +; +; "US Cable channels" +; +;=========================================================== +; This file is a part of BeOS USBVision driver project. +; Copyright (c) 2003 by Siarzuk Zharski +; +; This file may be used under the terms of the BSD License +; Look into the file "License" for details. +; +; $Source: /cvsroot/sis4be/usbvision/Locales/US\040Cable,v $ +; $Author: zharik $ +; $Revision: 1.2 $ +; $Date: 2003/07/09 04:58:08 $ +;=========================================================== +; +; Format of this file: +; +; The file begins with the name of locale preceded with "@"-sign. This name will be +; visible for user in Tuner Locale settings. +; Channels are presented as frequency <-> name pairs. +; The Frequency is in Hz and name begins just after the first space character +; after frequency number. The name ends at the end of line. +; +; All lines beginning with ";"-sign are comments and will be ignored. +; +@US Cable + 73250000 4A + 55250000 2 + 61250000 3 + 67250000 4 + 77250000 5 + 83250000 6 +175250000 7 +181250000 8 +187250000 9 +193250000 10 +199250000 11 +205250000 12 +211250000 13 +121250000 A +127250000 B +133250000 C +139250000 D +145250000 E +151250000 F +157250000 G +163250000 H +169250000 I +217250000 J +223250000 K +229250000 L +235250000 M +241250000 N +247250000 O +253250000 P +259250000 Q +265250000 R +271250000 S +277250000 T +283250000 U +289250000 V +295250000 W +301250000 W+1 +307250000 W+2 +313250000 W+3 +319250000 W+4 +325250000 W+5 +331250000 W+6 +337250000 W+7 +343250000 W+8 +349250000 W+9 +355250000 W+10 +361250000 W+11 +367250000 W+12 +373250000 W+13 +379250000 W+14 +385250000 W+15 +391250000 W+16 +397250000 W+17 +403250000 W+18 +409250000 W+19 +415250000 W+20 +421250000 W+21 +427250000 W+22 +433250000 W+23 +439250000 W+24 +445250000 W+25 +451250000 W+26 +457250000 W+27 +463250000 W+28 +469250000 65 +475250000 66 +481250000 67 +487250000 68 +493250000 69 +499250000 70 +505250000 71 +511250000 72 +517250000 73 +523250000 74 +529250000 75 +535250000 76 +541250000 77 +547250000 78 +553250000 79 +559250000 80 +565250000 81 +571250000 82 +577250000 83 +583250000 84 +589250000 85 +595250000 86 +601250000 87 +607250000 88 +613250000 89 +619250000 90 +625250000 91 +631250000 92 +637250000 93 +643250000 94 + 91250000 A­5 + 97250000 A­4 +103250000 A­3 +109250000 A­2 +115250000 A-1 +649250000 100 +655250000 101 +661250000 102 +667250000 103 +673250000 104 +679250000 105 +685250000 106 +691250000 107 +697250000 108 +703250000 109 +709250000 110 +715250000 111 +721250000 112 +727250000 113 +733250000 114 +739250000 115 +745250000 116 +751250000 117 +757250000 118 +763250000 119 +769250000 120 +775250000 121 +781250000 122 +787250000 123 +793250000 124 +799250000 125 diff --git a/data/settings/media/usb_vision/Locales/US Cable HRC b/data/settings/media/usb_vision/Locales/US Cable HRC new file mode 100644 index 0000000000..3493a381ab --- /dev/null +++ b/data/settings/media/usb_vision/Locales/US Cable HRC @@ -0,0 +1,153 @@ +; +; Tuner locale file for BeOS USBVision driver +; +; "US Cable HRC channels" +; +;=========================================================== +; This file is a part of BeOS USBVision driver project. +; Copyright (c) 2003 by Siarzuk Zharski +; +; This file may be used under the terms of the BSD License +; Look into the file "License" for details. +; +; $Source: /cvsroot/sis4be/usbvision/Locales/US\040Cable\040HRC,v $ +; $Author: zharik $ +; $Revision: 1.2 $ +; $Date: 2003/07/09 04:58:08 $ +;=========================================================== +; +; Format of this file: +; +; The file begins with the name of locale preceded with "@"-sign. This name will be +; visible for user in Tuner Locale settings. +; Channels are presented as frequency <-> name pairs. +; The Frequency is in Hz and name begins just after the first space character +; after frequency number. The name ends at the end of line. +; +; All lines beginning with ";"-sign are comments and will be ignored. +; +@US Cable HRC + 54000000 2 + 60000000 3 + 66000000 4 + 76000000 5 + 82000000 6 +174000000 7 +180000000 8 +186000000 9 +192000000 10 +198000000 11 +204000000 12 +210000000 13 +120000000 A +126000000 B +132000000 C +138000000 D +144000000 E +150000000 F +156000000 G +162000000 H +168000000 I +216000000 J +222000000 K +228000000 L +234000000 M +240000000 N +246000000 O +252000000 P +258000000 Q +264000000 R +270000000 S +276000000 T +282000000 U +288000000 V +294000000 W +300000000 W+1 +306000000 W+2 +312000000 W+3 +318000000 W+4 +324000000 W+5 +330000000 W+6 +336000000 W+7 +342000000 W+8 +348000000 W+9 +354000000 W+10 +360000000 W+11 +366000000 W+12 +372000000 W+13 +378000000 W+14 +384000000 W+15 +390000000 W+16 +396000000 W+17 +402000000 W+18 +408000000 W+19 +414000000 W+20 +420000000 W+21 +426000000 W+22 +432000000 W+23 +438000000 W+24 +444000000 W+25 +450000000 W+26 +456000000 W+27 +462000000 W+28 +468000000 65 +474000000 66 +480000000 67 +486000000 68 +492000000 69 +498000000 70 +504000000 71 +510000000 72 +516000000 73 +522000000 74 +528000000 75 +534000000 76 +540000000 77 +546000000 78 +552000000 79 +558000000 80 +564000000 81 +570000000 82 +576000000 83 +582000000 84 +588000000 85 +594000000 86 +600000000 87 +606000000 88 +612000000 89 +618000000 90 +624000000 91 +630000000 92 +636000000 93 +642000000 94 + 90000000 A­5 + 96000000 A­4 +102000000 A­3 +108000000 A­2 +114000000 A-1 +648000000 100 +654000000 101 +660000000 102 +666000000 103 +672000000 104 +678000000 105 +684000000 106 +690000000 107 +696000000 108 +702000000 109 +708000000 110 +714000000 111 +720000000 112 +726000000 113 +732000000 114 +738000000 115 +744000000 116 +750000000 117 +756000000 118 +762000000 119 +768000000 120 +774000000 121 +780000000 122 +786000000 123 +792000000 124 +798000000 125 diff --git a/data/settings/media/usb_vision/Locales/xUSSR Air b/data/settings/media/usb_vision/Locales/xUSSR Air new file mode 100644 index 0000000000..8fd4b95f5c --- /dev/null +++ b/data/settings/media/usb_vision/Locales/xUSSR Air @@ -0,0 +1,90 @@ +; +; Tuner locale file for BeOS USBVision driver +; +; "Ex USSR Broadcast channels" +; +;=========================================================== +; This file is a part of BeOS USBVision driver project. +; Copyright (c) 2003 by Siarzuk Zharski +; +; This file may be used under the terms of the BSD License +; Look into the file "License" for details. +; +; $Source: /cvsroot/sis4be/usbvision/Locales/xUSSR\040Air,v $ +; $Author: zharik $ +; $Revision: 1.2 $ +; $Date: 2003/07/09 04:58:08 $ +;=========================================================== +; +; Format of this file: +; +; The file begins with the name of locale preceded with "@"-sign. This name will be +; visible for user in Tuner Locale settings. +; Channels are presented as frequency <-> name pairs. +; The Frequency is in Hz and name begins just after the first space character +; after frequency number. The name ends at the end of line. +; +; All lines beginning with ";"-sign are comments and will be ignored. +; +@xUSSR Air + 49750000 1 + 59250000 2 + 77250000 3 + 85250000 4 + 93250000 5 +175250000 6 +183250000 7 +191250000 8 +199250000 9 +207250000 10 +215250000 11 +223250000 12 +471250000 21 +479250000 22 +487250000 23 +495250000 24 +503250000 25 +511250000 26 +519250000 27 +527250000 28 +535250000 29 +543250000 30 +551250000 31 +559250000 32 +567250000 33 +575250000 34 +583250000 35 +591250000 36 +599250000 37 +607250000 38 +615250000 39 +623250000 40 +631250000 41 +639250000 42 +647250000 43 +655250000 44 +663250000 45 +671250000 46 +679250000 47 +687250000 48 +695250000 49 +703250000 50 +711250000 51 +719250000 52 +727250000 53 +735250000 54 +743250000 55 +751250000 56 +759250000 57 +767250000 58 +775250000 59 +783250000 60 +791250000 61 +799250000 62 +807250000 63 +815250000 64 +823250000 65 +831250000 66 +839250000 67 +847250000 68 +855250000 69 diff --git a/data/settings/media/usb_vision/Locales/xUSSR Cable b/data/settings/media/usb_vision/Locales/xUSSR Cable new file mode 100644 index 0000000000..d5f70662c7 --- /dev/null +++ b/data/settings/media/usb_vision/Locales/xUSSR Cable @@ -0,0 +1,67 @@ +; +; Tuner locale file for BeOS USBVision driver +; +; "Ex USSR Cable channels" +; +;=========================================================== +; This file is a part of BeOS USBVision driver project. +; Copyright (c) 2003 by Siarzuk Zharski +; +; This file may be used under the terms of the BSD License +; Look into the file "License" for details. +; +; $Source: /cvsroot/sis4be/usbvision/Locales/xUSSR\040Cable,v $ +; $Author: zharik $ +; $Revision: 1.2 $ +; $Date: 2003/07/09 04:58:08 $ +;=========================================================== +; +; Format of this file: +; +; The file begins with the name of locale preceded with "@"-sign. This name will be +; visible for user in Tuner Locale settings. +; Channels are presented as frequency <-> name pairs. +; The Frequency is in Hz and name begins just after the first space character +; after frequency number. The name ends at the end of line. +; +; All lines beginning with ";"-sign are comments and will be ignored. +; +@xUSSR Cable +111250000 70 +119250000 71 +127250000 72 +135250000 73 +143250000 74 +141250000 75 +159250000 76 +167250000 77 +231250000 78 +239250000 79 +247250000 80 +255250000 81 +263250000 82 +271250000 83 +279250000 84 +287250000 85 +295250000 86 +303250000 87 +311250000 88 +319250000 89 +327250000 90 +335250000 91 +343250000 92 +351250000 93 +359250000 94 +367250000 95 +375250000 96 +383250000 97 +391250000 98 +399250000 99 +407250000 100 +415250000 101 +423250000 102 +431250000 103 +439250000 104 +447250000 105 +455250000 106 +463250000 107 diff --git a/headers/private/audio/R3MediaDefs.h b/headers/private/audio/R3MediaDefs.h new file mode 100644 index 0000000000..b290db6649 --- /dev/null +++ b/headers/private/audio/R3MediaDefs.h @@ -0,0 +1,86 @@ +/****************************************************************************** + + File: MediaDefs.h + + Copyright 1995-1999, Be Incorporated + This file may be used under the terms of the Be Sample Code License. + +******************************************************************************/ +#ifndef _R3_MEDIA_DEFS_H +#define _R3_MEDIA_DEFS_H + +#include +#include +#if defined(__cplusplus) +# include +#else + /* values for byte_ordering */ + enum { B_BIG_ENDIAN, B_LITTLE_ENDIAN }; + + /* values for sample_format */ + enum { + B_UNDEFINED_SAMPLES, + B_LINEAR_SAMPLES, + B_FLOAT_SAMPLES, + B_MULAW_SAMPLES + }; +#endif + +/* Buffer header for audio server */ + +typedef struct audio_buffer_header { + int32 buffer_number; + int32 subscriber_count; + bigtime_t time; + int32 reserved_1; + int32 reserved_2; + bigtime_t sample_clock; +} audio_buffer_header; + + +#define B_MEDIA_LEVEL B_REAL_TIME_PRIORITY + +#define B_NO_CHANGE (-1) + +/* ================ + Subscriber IDs and special values + ================ */ + +#define B_NO_SUBSCRIBER_ID ((subscriber_id)-1) +#define B_NO_SUBSCRIBER_NAME "not subscribed" + +#define B_SHARED_SUBSCRIBER_ID ((subscriber_id)-2) +#define B_SHARED_SUBSCRIBER_NAME "shared subscriber" + +/* ================ + Values for sound files and audio streams + ================ */ + + +/* Audio device codes for BAudioSubscriber's + * Get/SetVolume() and EnableDevice() calls + */ +enum { + B_CD_THROUGH = 0, + B_LINE_IN_THROUGH, + B_ADC_IN, + B_LOOPBACK, + B_DAC_OUT, + B_MASTER_OUT, + B_SPEAKER_OUT, + B_SOUND_DEVICE_END +}; + +/* ADC input codes */ +enum { + B_CD_IN, + B_LINE_IN, + B_MIC_IN +}; + +enum { + B_DAC_STREAM = 2354, + B_ADC_STREAM +}; + +#endif /* #ifndef _R3_MEDIA_DEFS_H */ diff --git a/headers/private/usb_vision/nt100x.h b/headers/private/usb_vision/nt100x.h new file mode 100644 index 0000000000..be75c7f905 --- /dev/null +++ b/headers/private/usb_vision/nt100x.h @@ -0,0 +1,115 @@ +/* + * This file is a part of BeOS USBVision driver project. + * Copyright (c) 2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * Look into the file "License" for details. + * + * Skeletal part of this code was inherired from original BeOS sample code, + * that is distributed under the terms of the Be Sample Code License. + * Look into the file "Be License" for details. + * + * $Source: /cvsroot/sis4be/usbvision/include/nt100x.h,v $ + * $Author: zharik $ + * $Revision: 1.1 $ + * $Date: 2003/07/15 18:58:05 $ + * + */ + +#ifndef _NT100X_H_ + #define _NT100X_H_ + +#define READ_CMD_PREFIX 0x33C2 +#define WRITE_CMD_PREFIX 0x3342 + +#define COMMAND_DATA_LENGTH 0x08 +typedef struct{ + uint8 reg; + uint8 data_length; + uint8 data[COMMAND_DATA_LENGTH]; +}xet_nt100x_reg; + +#define NT_IOCTL_READ_REGISTER B_DEVICE_OP_CODES_END + 1 +#define NT_IOCTL_WRITE_REGISTER B_DEVICE_OP_CODES_END + 2 + +/*General Control Registers (Power, Restart EP, USB, IO­pins, Camera Control)*/ +#define PWR_REG 0x00 /*0*/ +#define CONFIG_REG 0x01 /*1*/ +#define ADRS_REG 0x02 /*2*/ +#define ALTER_REG 0x03 /*3*/ +#define FORCE_ALTER_REG 0x04 /*4*/ +#define STATUS_REG 0x05 /*5*/ +#define IOPIN_REG 0x06 /*6*/ +#define SER_MODE 0x07 /*7*/ +#define SER_ADRS 0x08 /*8*/ +#define SER_CONT 0x09 /*9*/ +#define SER_DAT1 0x0a /*10*/ +#define SER_DAT2 0x0b /*11*/ +#define SER_DAT3 0x0c /*12*/ +#define SER_DAT4 0x0d /*13*/ + +/*EEPROM Read/Write Registers*/ +#define EE_DATA 0x0e /*14*/ +#define EE_LSBAD 0x0f /*15*/ +#define EE_CONT 0x10 /*16*/ + +/*17: 0x11*/ + +/*DRAM and Memory Buffers Setup Registers*/ +#define DRM_CONT 0x12 /*18*/ +#define DRM_PRM1 0x13 /*19*/ +#define DRM_PRM2 0x14 /*20*/ +#define DRM_PRM3 0x15 /*21*/ +#define DRM_PRM4 0x16 /*22*/ +#define DRM_PRM5 0x17 /*23*/ +#define DRM_PRM6 0x18 /*24*/ +#define DRM_PRM7 0x19 /*25*/ +#define DRM_PRM8 0x1a /*26*/ + +/*Video Setup and Control Registers*/ +#define VIN_REG1 0x1b /*27*/ +#define VIN_REG2 0x1c /*28*/ +#define LXSIZE_IN 0x1d /*29*/ +#define MXSIZE_IN 0x1e /*30*/ +#define LYSIZE_IN 0x1f /*31*/ +#define MYSIZE_IN 0x20 /*32*/ +#define LX_OFFST 0x21 /*33*/ +#define MX_OFFST 0x22 /*34*/ +#define LY_OFFST 0x23 /*35*/ +#define MY_OFFST 0x24 /*36*/ +#define FRM_RATE 0x25 /*37*/ +#define LXSIZE_O 0x26 /*38*/ +#define MXSIZE_O 0x27 /*39*/ +#define LYSIZE_O 0x28 /*40*/ +#define MYSIZE_O 0x29 /*41*/ +#define FILT_CONT 0x2a /*42*/ +#define VO_MODE 0x2b /*43*/ +#define INTRA_CYC 0x2c /*44*/ +#define STRIP_SZ 0x2d /*45*/ +#define FORCE_INTRA 0x2e /*46*/ +#define FORCE_UP 0x2f /*47*/ +#define BUF_THR 0x30 /*48*/ +#define DVI_YUV 0x31 /*49*/ +#define AUDIO_CONT 0x32 /*50*/ +#define AUD_PK_LEN 0x33 /*51*/ +#define BLK_PK_LEN 0x34 /*52*/ + +/*USB Watch­Dog Register*/ +#define WD_COUNT 0x35 /*53*/ + +/*54 0x36*/ +/*55 0x37*/ + +/*Compression Ratio Management Registers*/ +#define PCM_THR1 0x38 /*56*/ +#define PCM_THR2 0x39 /*57*/ +#define DIST_THR_I 0x3a /*58*/ +#define DIST_THR_A 0x3b /*59*/ +#define MAX_DIST_I 0x3c /*60*/ +#define MAX_DIST_A 0x3d /*61*/ +#define VID_BUF_ 0x3e /*62*/ +#define LFP_LSB 0x3f /*63*/ +#define LFP_MSB 0x40 /*64*/ +#define VID_LPF 0x41 /*65*/ + +#endif //_NT100X_H_ \ No newline at end of file diff --git a/src/add-ons/kernel/busses/Jamfile b/src/add-ons/kernel/busses/Jamfile index d5ab964aab..84f7392775 100644 --- a/src/add-ons/kernel/busses/Jamfile +++ b/src/add-ons/kernel/busses/Jamfile @@ -1,4 +1,5 @@ SubDir HAIKU_TOP src add-ons kernel busses ; SubInclude HAIKU_TOP src add-ons kernel busses ide ; +SubInclude HAIKU_TOP src add-ons kernel busses scsi ; SubInclude HAIKU_TOP src add-ons kernel busses usb ; diff --git a/src/add-ons/kernel/busses/scsi/Jamfile b/src/add-ons/kernel/busses/scsi/Jamfile new file mode 100644 index 0000000000..f9cf48f6c7 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/Jamfile @@ -0,0 +1,3 @@ +SubDir HAIKU_TOP src add-ons kernel busses scsi ; + +SubInclude HAIKU_TOP src add-ons kernel busses scsi usb ; diff --git a/src/add-ons/kernel/busses/scsi/usb/Jamfile b/src/add-ons/kernel/busses/scsi/usb/Jamfile new file mode 100644 index 0000000000..e3d6922fef --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/Jamfile @@ -0,0 +1,30 @@ +SubDir HAIKU_TOP src add-ons kernel busses scsi usb ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +KernelAddon usb : kernel busses scsi : + usb_scsi.c + tracing.c + transform_procs.c + proto_common.c + proto_bulk.c + proto_cbi.c + settings.c + fake_device.c + sg_buffer.c +; + +# BUILD_LOG_DAEMON +#App usb_scsi_logging : kernel drivers busses scsi : +# tracing.c +# tracing_daemon.c +#; + +Package haiku-usb_scsi-cvs + : + usb + : + boot home config add-ons kernel busses scsi ; + +Package haiku-usb_scsi-cvs : usb_scsi.settings.sample + : boot home config settings kernel drivers sample ; diff --git a/src/add-ons/kernel/busses/scsi/usb/ReadMe.html b/src/add-ons/kernel/busses/scsi/usb/ReadMe.html new file mode 100644 index 0000000000..9f3c3db9b8 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/ReadMe.html @@ -0,0 +1,745 @@ + + + + + USB mass storage support for BeOS + + +

USB mass storage support for + BeOS

+ +This is yet another piece of hardware support for BeOS/Dano/Zeta operating systems. +This USB Storage Module (The Module) is designed to support a wide variety +of standard USB mass storage devices. Those devices are: +
    +
  • memory (flash) keys,
  • +
  • external HDD/CD/DVD/ZIP/Floppy drives with USB connection,
  • +
  • digital cameras/camcorders with USBMS protocol,
  • +
  • MP3 players,
  • +
  • card readers,
  • +
  • Jukeboxes
  • +
  • etc.
  • +
+

In other (more special and technical) words this Module +works with standard USB class 8 devices, both Bulk-Only and CB[I] ones, +with all standard command sets used in such devices. +

+

Table of Contents

+ + +

1. Installation and using

+

(!!!) FIRST EMERGENCY TIP: If your system +crashes with this Module - reboot and press "Space" +during load. In boot menu select "Disable user add-ons" and continue +booting. Uninstall and reboot again into normal mode. Please, inform the developer about this problem. +

+
    +
  1. Please check, that you have supported version of BeOS. Minimal system +requirement is R5 + BeOS.USB-patches. No support for "plain" R5! More +information about USB-patches you can find in +corresponding clause of this document. +Note that Dan0, all it's successors and Zeta already have compatible USB stack - no patches +are required.
  2. +
  3. Contents of distribution archive: +
        ReadMe.html      <--- file you are reading now
    +    install.sh       <--- installation script
    +    uninstall.sh     <--- uninstallation script
    +    usb              <--- The Module binary
    +    usb_scsi.sample  <--- settings file sample
    +    usb_scsi_logging <--- logging daemon
    +    usb_scsi.devices <--- definitions for "non-standard" devices
    +    usb_dev_info     <--- the tool to obtain device inforamtion
    +
  4. +
  5. Run ./install.sh to install The Module on your system. +This script do the following:
  6. +
      +
    • copies The Module binary to + /boot/home/config/add-ons/kernel/busses/scsi/usb + directory
    • +
    +
      +
    • copies settings file to + /boot/home/config/settings/kernel/drivers/usb_scsi + file
    • +
    • ask you to reboot your system or edit settings file. More +information on settings file is here. +If you doesn't reboot from script - you +have to do it manually to let The Module work with updated settings. +
    • +
    +
  7. After system rebooted, plug in your USB device into USB slot and +try to open Tracker's "Mount" menu some times. In case if all goes OK - +you'll see some additional volumes available for mounting. Mount that +one you +think is your USB mass storage and use it as usual "real" drives.
  8. +
  9. It is highly recommended to unmount your USB volume before +unplugging device from USB slot. Some pending read/write operations can +be still active in background. If you break this process - +YOU CAN LOOSE YOUR DATA. Unmount +it and wait until your USB volume icon is +disappeared from desktop and led on your device ( in case this led +exists, of course ) turns off. To be sure you can run "sync" command from the Terminal.
  10. +
  11. [optional] To uninstall The Module from your system - run uninstall.sh +from distribution archive or delete files mentioned in +clause 3 of this section manually.
  12. +
+Table +of Contents +

2. Troubleshooting

+
    +
  1. Is my USB device supported? +
      +
    • May be. Install this software, plug your device in and +try to mount it. Or look for class / subclass / protocol values +in usb device description and check against the following lists. +
        +
      • Supported class : 8
      • +
      • Supported subclasses ( command sets ) : 1, 2, 3, 4, 5, 6
      • +
      • Supported protocols: 0, 1, 80
      • +
      +Any combination of mentioned above class / subclass / protocol is supported. +
    • +
    +
  2. +
  3. I have installed this software on R5 + USB.patches but my system +goes to Kernel Debugger on very early booting stage. Help! +
      +
    • Edit settings +file and activate the following key: +
        +
      • ignore_sysinit2 true
      • +
      +
    • +
    +
  4. +
  5. I have installed this software and there are still no additional +volumes in Tracker's "Mount" menu. +
      +
    • Sometimes it is required to open "Mount" menu more than +one time to see volumes. +
    • +
    • You can try open "Mount" menu with "Shift" button pressed and +select "Rescan All Devices" menu item to help the system recognize your device. +
    • +
    • Try to Rescan SCSI in DriveSetup. +
    • +
    +
  6. +
  7. I still have no volumes to mount!!! +
      +
    • Please check the following: +
        +
      • [for R5 only. Not required for Dano/Zeta etc. ] your system +has USB patches installed;
      • +
      • the binary file /boot/home/config/add-ons/kernel/busses/scsi/usb +exists on your system; +
      • +
      • the settings file /boot/home/config/settings/kernel/drivers/usb_scsi +exists on your system;
      • +
      • check that your device uses standard protocols and should be supported by +this module ( see clause 1 of this section ) +
      • +
      • Despite of fact that latest versions of Zeta OS use this module, some of +pre-releases of this OS have completely different stuff to support USB storage devices. +In some circumstances those Zeta's modules can prevent this USB Support Module from correct working. +In this situation you have to disable Zeta's USB Storage support. To do this go to +/boot/beos/system/add-ons/kernel/busses/scsi/ diectory and rename or remove the +usb and usb_scsi files. After rebooting your system +you should have updated USB Storage support. +
      • +
      +
    • +
    +
  8. +
  9. STILL NOTHING TO MOUNT ! ! ! + +
  10. +
  11. I see a lot of empty SCSI devices in DriveSetup and SCSIProbe. +What is it? +
      +
    • Those "disks" are just reserved device entries - some kind of +placeholders for real devices you'll attach to your computer. Read +about this technique here. +
    • +
    +
  12. +
  13. DriveSetup hangs on exit!?! +
      +
    • It is known bug. I don't know who is wrong with it. No +solution at this time. Just kill this zombie. +
    • +
    +
  14. +
  15. I have found a bug! I have unmounted my USB floppy, unplug it +than plug in another device but still see the "floppy" volume in the mount +list. +
      +
    • The mounting in BeOS is broken. Just press "Shift" key before +opening Tracker's "Mount" menu than select "Rescan Devices" +After some seconds try to mount your device again. Should work now. +
    • +
    +
  16. +
  17. I have set reserve_devices to maximal value but still no reserved device +entries in DriveSetup. +
      +
    • Known bug. In some situations reservation doesn't work. +It's reproducible with Adaptec SCSI controllers installed on your +system. You have to use DriveSetup for first mounting of device in this +situation. Nothing is perfect in this World. +
    • +
    +
  18. +
  19. Does my Canon PowerShot A70 digital camera supported by this software? +
      +
    • No. It uses Picture Transfer Protocol (PTP) instead of USB Mass Storage (USBMS) +one. You can check your camera information for Interface class. For USBMS it should +be 8, for PTP - 6. +
    • +
    +
  20. +
  21. Help me! No more than 2 devices visible by module at the same time. + +
  22. +
  23. My 9-in-1 card reader works only with media in first 4 slots! No +reaction on media in 5th - 9th slots! Is it a trial version of a driver? Where can I buy full version? + +
  24. +
  25. "Mount" menu hangs for a time +
      +
    • System requires some time to ask all available volumes for media +availability, filesystem data format etc. This check is performed any time you opening "Mount" +menu. In case you have many devices reserved in your configuration - you can be in such +trouble. Read about device entries +reservation and optimize your settings to more reasonable values. +
    • +
    +
  26. +
  27. I see the Generic OS Error message any time I want to mount my device. +

    In most of such situations your hardware is OK. The problem is that standard filesystem + addon doesn't recognize the filesystem on volume as correct. Unfortunatley BeOS is + "to close to standard" to be compatible with all bugs of Windows. Do not + forget to backup your data before trying to solve this problem!

    +

    First of all try to reformat your media.

    +

    If formatting doesn't help or doesn't work with your hardware - open DriveSetup + and [re]create partition on your device. Rescan SCSI bus if required. + Note that you have to make your partition a bit smaller as physical + size of your device. Try to initialize and reformat your media with new size.

    +
  28. +
  29. Your software sucks!!! + +
  30. +
+Table of Contents +

3. Writing a problem report

+Either something goes wrong with this software or nothing goes right +you have to write a bug report about it. +
    +
  1. Obtain your USB device information and +save it in safe place
  2. +
  3. now investigate device information for interface class. If it is +not equal to 8 go to step 12
  4. +
  5. open your settings file +( /boot/home/config/settings/kernel/drivers/usb_scsi +) in editor you prefer to use
  6. +
  7. activate following keys if they are still not activated
  8. +
        debug_output true
    +    debug_output_in_file true
    +    debug_output_file_rewrite true
    +    debug_trace_protocol true
    +    debug_trace_sense_data true
    +
  9. save your changes and close your editor
  10. +
  11. reboot your system keeping your devices switched off from your computer
  12. +
  13. after reboot run usb_scsi_logging application from distribution pack
  14. +
  15. plug your device in free USB slot
  16. +
  17. try to mount it again.
  18. +
  19. unplug your device from computer
  20. +
  21. copy the /var/log/usb_scsi.log file into same place as in step 1.
  22. +
  23. Get the information, obtained on step 1 and step 12 and let +developer know about your problem
  24. +
+Table of Contents +

4. Technical notes

+

4.1. BeOS USB patches

+To work with this software on +original BeOS R5 Pro/PE versions and it's successors your system need +to be improved to newer version of USB. This version is available +on well-known BeOS file-sharing network as BeOS.USB-patches.zip. Get it, unpack and +install it as required in corresponding readme. Note that, there +are 3 patches in this archive: +
    +
  1. beos-usb-patch
  2. +
  3. beos-usb.modem-patch
  4. +
  5. beos-usb.modem-patch.sm
  6. +
+

At least first one should be installed on your system to make using of +The USB Support Module possible. Note that Dan0, all it's successors and Zeta don't +require this patches.

+Table of Contents +

4.2. USB Device information

+

4.2.1. How to obtain +USB device information for your hardware

+There is an usb_dev_info tool inside of distribution +archive. It can +be used to obtain this information. Someone prefers USBCommander. +
    +
  1. Unplug all USB devices and hubs from your PC.
  2. +
  3. Go into Terminal and run the following command: ls -alR /dev/bus/usb + You should see something like this: +
        $ ls -alR /dev/bus/usb/
    +    /dev/bus/usb:
    +    total 0
    +    drw-r--r--   1 walther  users           0 May 31 23:16 .
    +    drw-r--r--   1 walther  users           0 Jun  1  2003 ..
    +    drw-r--r--   1 walther  users           0 May 31 23:16 0
    +    drw-r--r--   1 walther  users           0 May 31 23:16 1
    +    crw-r--r--   1 walther  users      0,   0 May 31 23:16 unload
    +    
    +    /dev/bus/usb/0:
    +    total 0
    +    drw-r--r--   1 walther  users           0 May 31 23:16 .
    +    drw-r--r--   1 walther  users           0 May 31 23:16 ..
    +    crw-r--r--   1 walther  users      0,   0 May 31 23:16 hub
    +    
    +    /dev/bus/usb/1:
    +    total 0
    +    drw-r--r--   1 walther  users           0 May 31 23:16 .
    +    drw-r--r--   1 walther  users           0 May 31 23:16 ..
    +    crw-r--r--   1 walther  users      0,   0 May 31 23:16 hub
    +
  4. +
  5. Note this information.
  6. +
  7. Now plug your USB device into PC and run ls -alR /dev/bus/usb/ again. +You'll get something slightly different: +
        $ ls -alR /dev/bus/usb/
    +    /dev/bus/usb:
    +    total 0
    +    drw-r--r--   1 walther  users           0 May 31 23:16 .
    +    drw-r--r--   1 walther  users           0 Jun  1  2003 ..
    +    drw-r--r--   1 walther  users           0 May 31 23:16 0
    +    drw-r--r--   1 walther  users           0 May 31 23:16 1
    +    crw-r--r--   1 walther  users      0,   0 May 31 23:16 unload
    +    
    +    /dev/bus/usb/0:
    +    total 0
    +    drw-r--r--   1 walther  users           0 May 31 23:16 .
    +    drw-r--r--   1 walther  users           0 May 31 23:16 ..
    +    crw-r--r--   1 walther  users      0,   0 May 31 23:17 1
    +    crw-r--r--   1 walther  users      0,   0 May 31 23:16 hub
    +    
    +    /dev/bus/usb/1:
    +    total 0
    +    drw-r--r--   1 walther  users           0 May 31 23:16 .
    +    drw-r--r--   1 walther  users           0 May 31 23:16 ..
    +    crw-r--r--   1 walther  users      0,   0 May 31 23:16 hub
    +
  8. +
  9. Compare this results with previous one and look for file, +that appeared (is selected for our sample case). This file is your +"unknown" USB device (in our sample it is /dev/bus/usb/0/1).
  10. +
  11. Now you can run usb_dev_info tool to obtain device information: +
    $ usb_dev_info /dev/bus/usb/0/1
    +
  12. +
+Table of Contents +

4.2.2. How USB device information +looks like and what does it mean

+

After performing tasks, described in previous clause you'll +receive something like the following. Note that some details can be +different for your hardware +

    $ usb_dev_info /dev/bus/usb/0/1
+    [Device]
+    Class .................. 0
+    Subclass ............... 0
+    Protocol ............... 0
+    Vendor ID .............. 0x08ec   <---------- Vendor ID of your hardware manufacturer
+    Product ID ............. 0x0011   <---------- unique Product ID of your hardware
+    Version ................ 0x0200
+    Manufacturer String .... "      "
+    Product String ......... "      "
+    Serial Number .......... "      "
+      [Configuration 0]               <---------- begin of configuration description 
+        [Interface 0]                 <---------- begin of interface description
+        Class .............. 8        <---------- this interface class. 
+        Subclass ........... 6        <---------- this interface subclass
+        Protocol ........... 80       <---------- protocol used by this interface
+          [Endpoint 0]
+          MaxPacketSize .... 64
+          Interval ......... 0
+          Type ............. Bulk
+          Direction ........ Input
+          [Endpoint 1]
+          MaxPacketSize .... 64
+          Interval ......... 0
+          Type ............. Bulk
+          Direction ........ Output
+ + +Table of Contents +

4.3. Device entries +reservation technique

+

Some tricks are required to implement simple and natural ( "one-click" +) volumes mounting in Tracker. Current versions of BeOS don't fully conform to +SCSI Common Access Model specifications. Particularly that is mean, +that there are no possibility to tell system about mass storage devices, +attached after system boot. If you already used usb mass storage driver +from Dano you should know this problem - you have to go to DriveSetup +than Rescan SCSI bus and only after this mount your volume from DriveSetup.

+

This Module introduces a workaround for such problem - it just let system to +know, that "device is here, but not ready at the moment, keep trying". This allows +to simulate some kind of plug and play in mounting from Tracker. You +can see those reserved device entries in DriveSetup -a lot of SCSI +"drives" without media and with ZIP cartridge icon left of it. This +reservation can be +configured in settings file.

+Table of Contents +

4.4. A couple +of words about usb_scsi settings file

+

You can configure some aspects of this software behavior through +editing it's settings file. This file is placed by installation script into +/boot/home/config/settings/kernel/drivers/ directory +and has the name +usb_scsi. It is usual text file and can be edited by +any text editor you like. Note that improper using of this settings +file can crash your system - please be accurate.

+

Typically the parameters in settings file +can be inactive (commented ) or active. For example the following +quote from settings file contains two parameters: first one +( reserve_devices ) is inactive ( commented by '#'-sign at the begin of +line ) and second one ( reserve_luns ) is active and set to 4: +

#reserve_devices 2 <----------------- inactive
+reserve_luns    4 <----------------- active
+Please use this notation during editing of settings file.

+

4.4.1 The Module configuration parameters

+This set of parameters is loaded by Module during +system boot and is used on permanent basis. To apply changes, made by you in any of +this parameter you have to restart your system +
    +
  • reserve_devices +
      +
    • Amount of device entries to be reserved by The Module. +If you plan to use more than 2 devices simultaneously than increase this +parameter. Note that if you set this parameter to 0 - device entry +reservation will be "switched off" and you have to use DriveSetup for +first mounting.
    • +
    • default value: 2
    • +
    • maximal value: 7
    • +
    +
  • +
  • reserve_luns +
      +
    • Amount of logical unit numbers (LUN) to be reserved by The Module for every + device entry defined in reserve_devices parameter. If you plan to use devices + with more than 4 LUNs than increase this parameter.
    • +
    • default value: 4
    • +
    • maximal value: 8
    • +
    +
  • +
  • ignore_sysinit2
  • +
      +
    • If you have R5 with USB patches and your system goes in kernel debugger on +booting with this software - this parameter is for you. Set it to true +and reboot to avoid such crashing behavior.
    • +
    • default value: false
    • +
    +
+Table of Contents +

4.4.2. Parameters for debugging mode

+
    +
  • debug_output +
  • +
      +
    • This parameter activates / deactivates debug output.
    • +
    • default value: false
    • +
    +
  • debug_output_in_file
  • +
      +
    • This parameter handles redirection of tracing information to +private log file (/var/log/usb_scsi.log). If this +parameter is false - all debuging information goes to system log. +
    • +
    • default value: false
    • +
    +
  • debug_output_file_rewrite
  • +
      +
    • Forces private log file to be truncated on every system restart
    • +
    • default value: false
    • +
    +
  • debug_trace_commands
  • +
      +
    • Activate this to dump SCSI commands to debug output
    • +
    • default value: false
    • +
    +
  • debug_trace_protocol
  • +
      +
    • Activate this to see mass storage protocols work information in debug output
    • +
    • default value: false
    • +
    +
  • debug_trace_data_io
  • +
  • debug_trace_sense_data
  • +
  • debug_trace_bulk_callback
  • +
  • debug_trace_time
  • +
  • debug_trace_threadid
  • +
  • debug_trace_thread_name
  • +
  • debug_trace_capacity
  • +
      +
    • Mean this stuff as undocumented because it is rarely used.
    • +
    • default values: false
    • +
    +
+Table of Contents +

4.4.3 Configuring device definitions

+

Device definition allows to override your hardware parameters and tweak +it's functionality. This parameters are device-specific and reloaded on +physical device attach. You not need to reboot your system to apply +your changes in device descriptions. All you need to use changed device +definitions - unplug your USB hardware from computer and plug it in +again.

+

Typical "non-standard" devices definition looks like this: +

vendor <<vendor id>> {
+  device <<product id 1>> {
+    <<parameter 1>> 
+    <<parameter 2>>
+         ...
+    <<parameter N>>
+  }
+    ....
+  device <<product id N>> {
+    <<parameter 1>> 
+    <<parameter 2>>
+         ...
+    <<parameter N>>
+  }
+}
+

+

The real vendor ID and product ID for your hardware you can obtain from +USB Device information. Note that you can define many devices inside of +single vendor definition. More real samples of device overrides you can +find in usb_scsi.devices file inside of +distribution archive. Just copy the content of corresponding device +description into settings file and re-plug your hardware.

+Table of Contents +

4.4.3.1.Tweaking device definition

+Every parameter of device definition is like switch. It affects on Module behavior +only if exists in device definition and is not commented out. +
    +
  • fake_inquiry
  • +
      +
    • do not send INQUIRY SCSI command to USB device but handle it in Module.
    • +
    +
  • use_6byte_cmd
  • +
      +
    • use 6 byte length SCSI READ/WRITE/MODE SENSE/SELECT SENSE +commands instead of 10 byte ones. Typically BeOS uses 6-byte commands +but many USB mass storage devices doesn't like this. To avoid massive +device +redefinitions this Module automatically translates such commands to +10-byte counterparts. If this default translation doesn't work for you +- set use_6byte_cmd to avoid it.
    • +
    +
  • trans_test_unit
  • +
      +
    • translate TEST UNIT SCSI command to START STOP one.
    • +
    +
  • no_test_unit
  • +
      +
    • do not send TEST UNIT SCSI command to device. At all.
    • +
    +
  • no_get_max_lun
  • +
      +
    • do not ask for maximal number of supported Logical Unit Numbers
    • +
    +
  • no_prevent_media
  • +
      +
    • do not send to device PREVENT ALLOW MEDIA REMOVAL SCSI command.
    • +
    +
  • use_mode_sense_10
  • +
      +
    • force module to use 10-byte MODE SENSE command. Typically this +Module detects automatically the supported MODE SENSE command and you +don't need to set it manually.
    • +
    +
  • force_read_only
  • +
      +
    • force drive to be read-only. It is not 100% guaranteed - but in +many cases works. If you need "true" read-only volumes - than mount it +with corresponding flags from command line.
    • +
    +
+

4.4.3.2. +Overriding device protocol

+There are two special parameters allow to override protocol and +command set used to communicate with device +
    +
  • commandset
  • +
      +
    • forces The Module to use specific command set when +communicating with device. The following command sets are supported
    • +
    +
      +
        +
      • SCSI - transparent SCSI command set. USB subclass 6
      • +
      • UFI - USB subclass 4
      • +
      • ATAPI - USB subclasses 5,2
      • +
      • RBC - USB subclass 1
      • +
      • QIC157 - USB subclass 3. Used for tape drives so, probably is +not be anytime usable... but supported. =-)
      • +
      • <Vendor> - any vendor-specific, non-standard commands +set. Note that to work with it a corresponding protocol extension module is +required.
      • +
      +
    +
  • protocol
  • +
      +
    • forces The Module to use specific protocol when +communicating with device. The following protocols are supported
    • +
        +
      • BULK - bulk-only. USB protocol 80
      • +
      • CB - Control/Bulk/Interrupt protocol (with command +completion interrupt). USB protocol 1
      • +
      • CBI - Control/Bulk/Interrupt protocol (with no command +completion interrupt) USB protocol 0
      • +
      • <Vendor> - any vendor-specific, non-standard protocol. +Note that to work with it a corresponding protocol extension module is +required.
      • +
      +
    +
+Table of Contents +

4.5. Protocol extension modules

+

The BeOS USB Support Module was designed with extensibility in mind. It means, that you +can add support of vendor-specific, non-standard protocols/commandsets without +changing the main Module. All you need is protocol extention module, that implements all +specifics of the data and commands flow.

+

Currently available modules:

+
    +
  • freecom - FREECOM USB-IDE Bridge (ATAPI devices only).
  • +
+

To install protocol extention module obtain it's distribution archive +and read instructions inside of it.

+

For development questions refer to of already existing protocol extention modules +or the Author of UBS Support Module.

+ +Table of Contents +

4.Contact and support information

+The BeOS USB Support Module project is hosted on SourceForge +and uses some it's powerful development services. There are some ways to inform +developer about problems or put feature requests for next version +
    +
  1. Use Bug +Tracker to put problem reports.
  2. +
  3. Use Forum +to ask simple support question, discuss any problems. +Do not put your problem reports here - use Bug +Tracker!
  4. +
  5. Use Mailing-list +to be informed with latest news, ask questions +etc. This is also not right place for your problem reports - use Bug +Tracker instead.
  6. +
  7. If you want to share any ideas, that can be good to implement in +future versions - use Feature +Request Submit form.
  8. +
  9. If you doesn't like any way, mentioned above you can +contact me personally by e-mail but +remember, that I don't like this +way!(Joke!) =-) In my opinion such Community Knowledges like +Forums and mail-lists must be public and available for everyone.
  10. +
+Table of Contents +

5.Credits

+

I want to say my "Thanks" to:

+

... Sergei Dolgov ("fyysik") for pushing me to develop this software +and help in testing,

+

... Valery Rybin for testing a really lot of those USB +gadgets he has at his hands,

+

... them who have spend some time to trying all those "-dev-" +versions in work.

+Table of Contents +

6. The History

+

+ + + + + + + + + + + + +
Date: Version: What's new:
06 June 20040.1.0-alpha-1 first public release.
+

+Table +of Contents +
< End of document >
+ + diff --git a/src/add-ons/kernel/busses/scsi/usb/TODO b/src/add-ons/kernel/busses/scsi/usb/TODO new file mode 100644 index 0000000000..0e935a350a --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/TODO @@ -0,0 +1,68 @@ +# +# This file is a part of BeOS USB SCSI interface module project. +# Copyright (c) 2003-2004 by Siarzhuk Zharski +# +# This file may be used under the terms of the BSD License +# See the file "License" for details. +# +#1) Correct handling of FORMAT_UNIT command +#2) Correct handling of SCSI return codes +#3) Locking of trace file should be not so "hard" +4)(????)Correct locking of driver entry in xpt_scsi_io +#5) Use USB stack 2.0 ? +6)(???) Hang problem with DriveSetup #reproduced on clean system without SCSI... +#7) Support of CBI protocol +#8) Support of FREECOM protocol +#9) Support of read-only forcing (fyysik asks) +#10) Make reservation of devices more flexible (can switch it off). +#11) Transfer should be build on callback ideology +#12) Timeouts should be more adequate +13) Review RBC transform against specs +14) Review QIC-157 transform against specs +#15) Make HBA SCSI ID configurable +#16) Think on possibility to use "one.dev <-> one.path" scheme +#17) Set cam_scsi_status correctly on return! +#18) Support of autosense on fake devices +#-INVALID-19)Locking for fake devices too +#20) What with write-protected devices? +#21) Some kind of investigation - try to return CHECK_CONDITION in case of zero autosense_len - will system resend this command with non-zero autosense len? +#22) mode sense data for 10-byte translated command. Wait for test results. Probably will be not required at all. +#23) implement protocols as modules +#24) Some kind of automatic detection if 6-byte READ/WRITE and MODE SELECT/SENSE commands supported. +#25) Do not let MODE_SENSE go to NOT READY LUNs. It can "kill" the hardware +#26) Replace the write/read to fwrite/fread in tracing daemon (fyysik's request) +27)(???) Looks like system ignores our CHECK_CONDITION (for example on handling 1e, 1b, 2a). Is it our problem? +#-INVALID-28) Clean-up the data buffer before MODE_SENSE request .... +#29) Problem with synchronize cache command (see BePage's log) +#30) Try to workaround R5+patches=KDL problem. Ignore calls from 'sysinit2'? +31) Work with NewFS Tracker and it's derivatives. There are lot of problems with that mad software. +#32) deactivate automatic READ(10)->READ(6) switching. Looks like it's makes more problems than solves. +#33) Are we really need private protocol buffer ? Try to remove this and use stack allocated objects. +#34) Tracing in protocols implementations should be more generic ... +#35) overwrite tracing ... +36) Handle FORMAT_UNIT for UFI devices. +#37) Locking of global devices table +#38) Locking of device_removed - avoid removing during handling xpt_scsi_io +39) Device mounted than unplugged.It stay mounted but doesn't work and get the garbage in "opened" files. Are there solutions? +#40) open log file in /var/log/ instead of home directory +#41) More correct work with MODE_SENSE/MODE_SELECT convertions ... +#42) debug output settings should be used in protocol extensions too ... +#-INVALID!-43) What with sense data? should it be reorganized as MODE_SENSE/MODE_SELECT one? +44) Fix possible problem with READ_CAPACITY command. Some cameras produce "Generic OS Error" during mounting. +#45) Some Minolta cameras have nulified semaphore after creation. :-( ) +#46) Add "invalid" devices entries. Check your mailing for information. +#-DUPLICATE-47) A word about disabling Zeta's modules in manual. +#48) Handle all TODOs in ReadMe.html before releasing RC-1. +#49) Handling 0xA1 (Blank) command for C/DVD-RW devices. Should be like FORMAT UNIT? +#-CDBurner's problem-50) Problems with 35h SYNCHRONIZE_CACHE command with CDBurner on FREECOM module. +#-Problems in current BeOS USB stack- 51) Support for DATAFAB extention +#-INVALID-52)Some kind of reset required for FREECOM. Test it until this MODE_SELECT is not working! +#51) problem with SCSIProbe +#52) Support for Siemens MP3 Player +#53) Stess tests for floppy +54) Handling of transfer timeout should be refactored. +55) Tracing Mode_sense/mode_select data for all case if configured - not only for converting! +#56) Are there problems with simultaneous tracing to log file and system log? Check! +57) Write a ReadMe.html for FREECOM module and make distribution support for it. +#58) Add tracing for READ_CAPACITY results +59) Check again MODE_SENSE/MODE_SELECT pages translations... MYOB has some problems... diff --git a/src/add-ons/kernel/busses/scsi/usb/USB_v3.h b/src/add-ons/kernel/busses/scsi/usb/USB_v3.h new file mode 100644 index 0000000000..79c791d6d9 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/USB_v3.h @@ -0,0 +1,194 @@ +/* +** USB.h - Version 3 USB Device Driver API +** +** Copyright 1999, Be Incorporated. All Rights Reserved. +** +*/ + +#ifndef _USB_V3_H +#define _USB_V3_H + +#include +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct usb_module_info usb_module_info; + +/* these are opaque handles to internal stack objects */ +typedef uint32 usb_id; +typedef usb_id usb_device; +typedef usb_id usb_interface; +typedef usb_id usb_pipe; + +typedef struct usb_endpoint_info usb_endpoint_info; +typedef struct usb_interface_info usb_interface_info; +typedef struct usb_interface_list usb_interface_list; +typedef struct usb_configuration_info usb_configuration_info; + +typedef struct usb_notify_hooks { + status_t (*device_added)(usb_device device, void **cookie); + status_t (*device_removed)(void *cookie); +} usb_notify_hooks; + +typedef struct usb_support_descriptor { + uint8 dev_class; + uint8 dev_subclass; + uint8 dev_protocol; + uint16 vendor; + uint16 product; +} usb_support_descriptor; + +/* ie, I support any hub device: +** usb_support_descriptor hub_devs = { 9, 0, 0, 0, 0 }; +*/ + +struct usb_endpoint_info { + usb_endpoint_descriptor *descr; /* descriptor and handle */ + usb_pipe handle; /* of this endpoint/pipe */ +}; + +struct usb_interface_info { + usb_interface_descriptor *descr; /* descriptor and handle */ + usb_interface handle; /* of this interface */ + + size_t endpoint_count; /* count and list of endpoints */ + usb_endpoint_info *endpoint; /* in this interface */ + + size_t generic_count; /* unparsed descriptors in this */ + usb_descriptor **generic; /* interface */ +}; + +struct usb_interface_list { + size_t alt_count; /* count and list of alternate */ + usb_interface_info *alt; /* interfaces available */ + + usb_interface_info *active; /* currently active alternate */ +}; + +struct usb_configuration_info { + usb_configuration_descriptor *descr; /* descriptor of this config */ + + size_t interface_count; /* interfaces in this config */ + usb_interface_list *interface; +}; + + +typedef void (*usb_callback_func)(void *cookie, uint32 status, + void *data, uint32 actual_len); + +struct usb_module_info { + bus_manager_info binfo; + + /* inform the bus manager of our intent to support a set of devices */ + status_t (*register_driver)(const char *driver_name, + const usb_support_descriptor *descriptors, + size_t count, + const char *optional_republish_driver_name); + + /* request notification from the bus manager for add/remove of devices we + support */ + status_t (*install_notify)(const char *driver_name, + const usb_notify_hooks *hooks); + status_t (*uninstall_notify)(const char *driver_name); + + /* get the device descriptor */ + const usb_device_descriptor *(*get_device_descriptor)(usb_device device); + + /* get the nth supported configuration */ + const usb_configuration_info *(*get_nth_configuration)(usb_device device, uint index); + + /* get the active configuration */ + const usb_configuration_info *(*get_configuration)(usb_device device); + + /* set the active configuration */ + status_t (*set_configuration)(usb_device device, + const usb_configuration_info *configuration); + + status_t (*set_alt_interface)(usb_device device, + const usb_interface_info *ifc); + + /* standard device requests -- convenience functions */ + /* handle may be a usb_device, usb_pipe, or usb_interface */ + status_t (*set_feature)(usb_id handle, uint16 selector); + status_t (*clear_feature)(usb_id handle, uint16 selector); + status_t (*get_status)(usb_id handle, uint16 *status); + + status_t (*get_descriptor)(usb_device device, + uint8 type, uint8 index, uint16 lang, + void *data, size_t len, size_t *actual_len); + + /* generic device request function */ + status_t (*send_request)(usb_device device, + uint8 request_type, uint8 request, + uint16 value, uint16 index, uint16 length, + void *data, size_t *actual_len); + + /* async request queueing */ + status_t (*queue_interrupt)(usb_pipe pipe, + void *data, size_t len, + usb_callback_func notify, void *cookie); + + status_t (*queue_bulk)(usb_pipe pipe, + void *data, size_t len, + usb_callback_func notify, void *cookie); + + status_t (*queue_bulk_v)(usb_pipe pipe, + iovec *vec, size_t count, + usb_callback_func notify, void *cookie); + + status_t (*queue_isochronous)(usb_pipe pipe, + void *data, size_t len, + rlea* rle_array, uint16 buffer_duration_ms, + usb_callback_func notify, void *cookie); + + status_t (*queue_request)(usb_device device, + uint8 request_type, uint8 request, + uint16 value, uint16 index, uint16 length, + void *data, usb_callback_func notify, void *cookie); + + status_t (*set_pipe_policy)(usb_pipe pipe, uint8 max_num_queued_packets, + uint16 max_buffer_duration_ms, uint16 sample_size); + + /* cancel pending async requests to an endpoint */ + status_t (*cancel_queued_transfers)(usb_pipe pipe); + + /* tuning, timeouts, etc */ + status_t (*usb_ioctl)(uint32 opcode, void* buf, size_t buf_size); +}; + +/* status code for usb callback functions */ +/*#define B_USB_STATUS_SUCCESS 0x0000 +#define B_USB_STATUS_DEVICE_CRC_ERROR 0x0002 +#define B_USB_STATUS_DEVICE_TIMEOUT 0x0004 +#define B_USB_STATUS_DEVICE_STALLED 0x0008 +#define B_USB_STATUS_IRP_CANCELLED_BY_REQUEST 0x0010 +#define B_USB_STATUS_DRIVER_INTERNAL_ERROR 0x0020 +#define B_USB_STATUS_ADAPTER_HARDWARE_ERROR 0x0040 +#define B_USB_STATUS_ISOCH_IRP_ABORTED 0x0080 +*/ +/* result codes for usb bus manager functions */ +/*#define B_USBD_SUCCESS 0 +#define B_USBD_BAD_HANDLE 1 +#define B_USBD_BAD_ARGS 2 +#define B_USBD_NO_DATA 3 +#define B_USBD_DEVICE_FAILURE 4 +#define B_USBD_COMMAND_FAILED 5 +#define B_USBD_PIPE_NOT_CONFIGURED 6 +#define B_USBD_DEVICE_ERROR 7 +#define B_USBD_PIPE_ERROR 8 +#define B_USBD_NO_MEMORY 9 +*/ +#define B_USB_MODULE_NAME "bus_managers/usb/v3" + +#ifdef __cplusplus +} +#endif + +#endif // _USB_V3_H diff --git a/src/add-ons/kernel/busses/scsi/usb/datafab/COPYING b/src/add-ons/kernel/busses/scsi/usb/datafab/COPYING new file mode 100644 index 0000000000..60549be514 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/datafab/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/add-ons/kernel/busses/scsi/usb/datafab/datafab.c b/src/add-ons/kernel/busses/scsi/usb/datafab/datafab.c new file mode 100644 index 0000000000..197b591a3f --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/datafab/datafab.c @@ -0,0 +1,850 @@ +/* + * \file: datafab.c + * \brief: USB SCSI module extention for Datafab USB readers + * + * This file is a part of BeOS USB SCSI interface module project. + * Copyright (c) 2005 by Siarzhuk Zharski + * + * 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, 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This protocol extension module was developed using information from + * "Driver for Datafab USB Compact Flash reader" in Linux usb storage driver. + * + * $Source: /cvsroot/sis4be/usb_scsi/datafab/datafab.c,v $ + * $Author: zharik $ + * $Revision: 1.3 $ + * $Date: 2005/03/12 21:18:48 $ + * + */ +#include "usb_scsi.h" + +#include +#include "device_info.h" +#include "proto_module.h" + +#define DATAFAB_MODULE_NAME "datafab" +#define DATAFAB_PROTOCOL_MODULE_NAME \ + MODULE_PREFIX DATAFAB_MODULE_NAME PROTOCOL_SUFFIX + +typedef struct { + usb_device_info *udi; + uint8 *cmd; + uint8 cmdlen; + iovec*sg_data; + int32 sg_count; + int32 transfer_len; + EDirection dir; + CCB_SCSIIO *ccbio; + int32 residue; +} usb_scsi_transport_info; + +typedef struct{ +/* +0 M General configuration bit-significant information: + F 15 0 = ATA device + X 14-8 Retired + F 7 1 = removable media device + X 6 Obsolete + X 5-3 Retired + V 2 Response incomplete + X 1 Retired + F 0 Reserved +*/ + uint16 info; +#define NON_ATA_DEVICE 0x +#define REMOVABLE_DEVICE 0x +/* +1 X Obsolete +2 O V Specific configuration +3 X Obsolete +4-5 X Retired +6 X Obsolete +7-8 O V Reserved for assignment by the CompactFlashä Association +9 X Retired +*/ + uint16 pad1[9]; + /* +10-19 M F Serial number (20 ASCII characters) +*/ + uint16 serial[10]; +/* +20-21 X Retired +22 X Obsolete +*/ + uint16 pad2[3]; + /* +23-26 M F Firmware revision (8 ASCII characters) +*/ + uint16 firmware_rev[4]; + /* +27-46 M F Model number (40 ASCII characters) +*/ + uint16 model_num[20]; +/* +47 M F 15-8 80h + F 7-0 00h = Reserved + F 01h-FFh = Maximum number of sectors that shall be transferred per interrupt on + READ/WRITE MULTIPLE commands +*//* +48 F Reserved +*//* +49 M Capabilities + F 15-14 Reserved for the IDENTIFY PACKET DEVICE command. + F 13 1 = Standby timer values as specified in this standard are supported + 0 = Standby timer values shall be managed by the device + F 12 Reserved for the IDENTIFY PACKET DEVICE command. + F 11 1 = IORDY supported + 0 = IORDY may be supported + F 10 1 = IORDY may be disabled + F 9 1 = LBA supported + F 8 1 = DMA supported. + X 7-0 Retired +*//* +50 M Capabilities + F 15 Shall be cleared to zero. + F 14 Shall be set to one. + F 13-2 Reserved. + X 1 Obsolete + F 0 Shall be set to one to indicate a device specific Standby timer value minimum. +*//* +51-52 X Obsolete +*//* +53 M F 15-3 Reserved + F 2 1 = the fields reported in word 88 are valid + 0 = the fields reported in word 88 are not valid + F 1 1 = the fields reported in words (70:64) are valid + 0 = the fields reported in words (70:64) are not valid + X 0 Obsolete +*//* +54-58 X Obsolete +*//* +59 M F 15-9 Reserved + V 8 1 = Multiple sector setting is valid + V 7-0 xxh = Current setting for number of sectors that shall be transferred per interrupt on + R/W Multiple command +*/ + uint16 pad3[13]; +/* +60-61 M F Total number of user addressable sectors +*/ + uint32 total_secs; +/* +62 X Obsolete +*//* +63 M F 15-11 Reserved + V 10 1 = Multiword DMA mode 2 is selected + 0 = Multiword DMA mode 2 is not selected + V 9 1 = Multiword DMA mode 1 is selected + 0 = Multiword DMA mode 1 is not selected + V 8 1 = Multiword DMA mode 0 is selected + 0 = Multiword DMA mode 0 is not selected + F 7-3 Reserved + F 2 1 = Multiword DMA mode 2 and below are supported + F 1 1 = Multiword DMA mode 1 and below are supported + F 0 1 = Multiword DMA mode 0 is supported +64 M F 15-8 Reserved + F 7-0 PIO modes supported +65 M Minimum Multiword DMA transfer cycle time per word + F 15-0 Cycle time in nanoseconds +66 M Manufacturer’s recommended Multiword DMA transfer cycle time + F 15-0 Cycle time in nanoseconds +67 M Minimum PIO transfer cycle time without flow control + F 15-0 Cycle time in nanoseconds +68 M Minimum PIO transfer cycle time with IORDY flow control + F 15-0 Cycle time in nanoseconds +69-70 F Reserved (for future command overlap and queuing) +71-74 F Reserved for IDENTIFY PACKET DEVICE command. +75 O Queue depth + F 15-5 Reserved + F 4-0 Maximum queue depth – 1 +76-79 F Reserved +80 M Major version number + 0000h or FFFFh = device does not report version + F 15 Reserved + F 14 Reserved for ATA/ATAPI-14 + F 13 Reserved for ATA/ATAPI-13 + F 12 Reserved for ATA/ATAPI-12 + F 11 Reserved for ATA/ATAPI-11 + F 10 Reserved for ATA/ATAPI-10 + F 9 Reserved for ATA/ATAPI-9 + F 8 Reserved for ATA/ATAPI-8 + F 7 Reserved for ATA/ATAPI-7 + F 6 1 = supports ATA/ATAPI-6 + F 5 1 = supports ATA/ATAPI-5 + F 4 1 = supports ATA/ATAPI-4 + F 3 1 = supports ATA-3 + X 2 Obsolete + X 1 Obsolete + F 0 Reserved +81 M F Minor version number + 0000h or FFFFh = device does not report version + 0001h-FFFEh = see 8.15.41 +82 M Command set supported. + X 15 Obsolete + F 14 1 = NOP command supported + F 13 1 = READ BUFFER command supported + F 12 1 = WRITE BUFFER command supported + X 11 Obsolete + F 10 1 = Host Protected Area feature set supported + F 9 1 = DEVICE RESET command supported + F 8 1 = SERVICE interrupt supported + F 7 1 = release interrupt supported + F 6 1 = look-ahead supported + F 5 1 = write cache supported + F 4 Shall be cleared to zero to indicate that the PACKET Command feature set is not + supported. + F 3 1 = mandatory Power Management feature set supported + F 2 1 = Removable Media feature set supported + F 1 1 = Security Mode feature set supported + F 0 1 = SMART feature set supported +83 M Command sets supported. + F 15 Shall be cleared to zero + F 14 Shall be set to one + F 13 1 = FLUSH CACHE EXT command supported + F 12 1 = mandatory FLUSH CACHE command supported + F 11 1 = Device Configuration Overlay feature set supported + F 10 1 = 48-bit Address feature set supported + F 9 1 = Automatic Acoustic Management feature set supported + F 8 1 = SET MAX security extension supported + F 7 See Address Offset Reserved Area Boot, NCITS TR27:2001 + F 6 1 = SET FEATURES subcommand required to spinup after power-up + F 5 1 = Power-Up In Standby feature set supported + F 4 1 = Removable Media Status Notification feature set supported + F 3 1 = Advanced Power Management feature set supported + F 2 1 = CFA feature set supported + F 1 1 = READ/WRITE DMA QUEUED supported + F 0 1 = DOWNLOAD MICROCODE command supported +84 M Command set/feature supported extension. + F 15 Shall be cleared to zero + F 14 Shall be set to one + F 13-6 Reserved + F 5 1 = General Purpose Logging feature set supported + F 4 Reserved + F 3 1 = Media Card Pass Through Command feature set supported + F 2 1 = Media serial number supported + F 1 1 = SMART self-test supported + F 0 1 = SMART error logging supported +85 M Command set/feature enabled. + X 15 Obsolete + F 14 1 = NOP command enabled + F 13 1 = READ BUFFER command enabled + F 12 1 = WRITE BUFFER command enabled + X 11 Obsolete + V 10 1 = Host Protected Area feature set enabled + F 9 1 = DEVICE RESET command enabled + V 8 1 = SERVICE interrupt enabled + V 7 1 = release interrupt enabled + V 6 1 = look-ahead enabled + V 5 1 = write cache enabled + F 4 Shall be cleared to zero to indicate that the PACKET Command feature set is not + supported. + F 3 1 = Power Management feature set enabled + F 2 1 = Removable Media feature set enabled + V 1 1 = Security Mode feature set enabled + V 0 1 = SMART feature set enabled +86 M Command set/feature enabled. + F 15-14 Reserved + F 13 1 = FLUSH CACHE EXT command supported + F 12 1 = FLUSH CACHE command supported + F 11 1 = Device Configuration Overlay supported + F 10 1 = 48-bit Address features set supported + V 9 1 = Automatic Acoustic Management feature set enabled + F 8 1 = SET MAX security extension enabled by SET MAX SET PASSWORD + F 7 See Address Offset Reserved Area Boot, NCITS TR27:2001 + F 6 1 = SET FEATURES subcommand required to spin-up after power-up + V 5 1 = Power-Up In Standby feature set enabled + V 4 1 = Removable Media Status Notification feature set enabled + V 3 1 = Advanced Power Management feature set enabled + F 2 1 = CFA feature set enabled + F 1 1 = READ/WRITE DMA QUEUED command supported + F 0 1 = DOWNLOAD MICROCODE command supported +87 M Command set/feature default. + F 15 Shall be cleared to zero + F 14 Shall be set to one + F 13-6 Reserved + F 5 General Purpose Logging feature set supported + V 4 Reserved + V 3 1 = Media Card Pass Through Command feature set enabled + V 2 1 = Media serial number is valid + F 1 1 = SMART self-test supported + F 0 1 = SMART error logging supported +88 O F 15-14 Reserved + V 13 1 = Ultra DMA mode 5 is selected + 0 = Ultra DMA mode 5 is not selected + V 12 1 = Ultra DMA mode 4 is selected + 0 = Ultra DMA mode 4 is not selected + V 11 1 = Ultra DMA mode 3 is selected + 0 = Ultra DMA mode 3 is not selected + V 10 1 = Ultra DMA mode 2 is selected + 0 = Ultra DMA mode 2 is not selected + V 9 1 = Ultra DMA mode 1 is selected + 0 = Ultra DMA mode 1 is not selected + V 8 1 = Ultra DMA mode 0 is selected + 0 = Ultra DMA mode 0 is not selected + F 7-6 Reserved + F 5 1 = Ultra DMA mode 5 and below are supported + F 4 1 = Ultra DMA mode 4 and below are supported + F 3 1 = Ultra DMA mode 3 and below are supported + F 2 1 = Ultra DMA mode 2 and below are supported + F 1 1 = Ultra DMA mode 1 and below are supported + F 0 1 = Ultra DMA mode 0 is supported +89 O F Time required for security erase unit completion +90 O F Time required for Enhanced security erase completion +91 O V Current advanced power management value +92 O V Master Password Revision Code +93 * Hardware reset result. The contents of bits (12:0) of this word shall change only during the + execution of a hardware reset. + F 15 Shall be cleared to zero. + F 14 Shall be set to one. + V 13 1 = device detected CBLID- above ViH + 0 = device detected CBLID- below ViL + 12-8 Device 1 hardware reset result. Device 0 shall clear these bits to zero. Device 1 + shall set these bits as follows: + F 12 Reserved. + V 11 0 = Device 1 did not assert PDIAG-. + 1 = Device 1 asserted PDIAG-. + V 10-9 These bits indicate how Device 1 determined the device number: + 00 = Reserved. + 01 = a jumper was used. + 10 = the CSEL signal was used. + 11 = some other method was used or the method is unknown. + 8 Shall be set to one. + 7-0 Device 0 hardware reset result. Device 1 shall clear these bits to zero. Device 0 + shall set these bits as follows: + F 7 Reserved. + F 6 0 = Device 0 does not respond when Device 1 is selected. + 1 = Device 0 responds when Device 1 is selected. + V 5 0 = Device 0 did not detect the assertion of DASP-. + 1 = Device 0 detected the assertion of DASP-. + V 4 0 = Device 0 did not detect the assertion of PDIAG-. + 1 = Device 0 detected the assertion of PDIAG-. + V 3 0 = Device 0 failed diagnostics. + 1 = Device 0 passed diagnostics. + V 2-1 These bits indicate how Device 0 determined the device number: + 00 = Reserved. + 01 = a jumper was used. + 10 = the CSEL signal was used. + 11 = some other method was used or the method is unknown. + F 0 Shall be set to one. +94 O V 15-8 Vendor’s recommended acoustic management value. + V 7-0 Current automatic acoustic management value. +95-99 F Reserved +100-103 O V Maximum user LBA for 48-bit Address feature set. +104-126 F Reserved +127 O Removable Media Status Notification feature set support + F 15-2 Reserved + F 1-0 00 = Removable Media Status Notification feature set not supported + 01 = Removable Media Status Notification feature supported + 10 = Reserved + 11 = Reserved +128 O Security status + F 15-9 Reserved + V 8 Security level 0 = High, 1 = Maximum + F 7-6 Reserved + F 5 1 = Enhanced security erase supported + V 4 1 = Security count expired + V 3 1 = Security frozen + V 2 1 = Security locked + V 1 1 = Security enabled + F 0 1 = Security supported +129-159 X Vendor specific +160 O CFA power mode 1 + F 15 Word 160 supported + F 14 Reserved + F 13 CFA power mode 1 is required for one or more commands implemented by the + device + V 12 CFA power mode 1 disabled + F 11-0 Maximum current in ma +161-175 X Reserved for assignment by the CompactFlashä Association +176-205 O V Current media serial number +206-254 F Reserved +255 M X Integrity word + 15-8 Checksum + 7-0 Signature +*/ + uint16 pad4[24]; + uint16 pad5[25]; + uint16 pad6[25]; + uint16 pad7[20]; + uint16 pad8[25]; + uint16 pad9[25]; + uint16 padA[25]; + uint16 padB[25]; +}ATA_DEVICE_INFO; + +#define DEVICE_INFO_SIZE 512 + +typedef struct { + uint8 feature; /* R: error, W:feature */ + uint8 sector_count; /* R: IReason W: Sectors Count*/ + uint8 address[3]; /* part of address */ + uint8 addr_dev; /* part of address and device info*/ +#define ADDR_MASK 0x0F +#define DEV_MASK 0xF0 +#define DEV_ON 0xA0 +#define DEV_LBA 0x40 +#define DEV_MASTER 0x00 +#define DEV_SLAVE 0x10 + uint8 command; /* R: status W:command */ + uint8 intr_reset; /* interrupt/reset register */ +#define IR_IRQ_ENABLE 0x01 +#define IR_RESET 0x02 +}command_registers; + +typedef struct { + uint8 reg1; + uint8 reg2; +}status_registers; + +#define IDE_CMD_IDENTIFY_DEVICE 0xEC +#define IDE_CMD_READ 0x20 +#define IDE_CMD_WRITE 0x30 + +/* duplication! */ +#define INQ_VENDOR_LEN 0x08 +#define INQ_PRODUCT_LEN 0x10 +#define INQ_REVISION_LEN 0x04 + + +/* + B_DEV_INVALID_IOCTL = B_DEVICE_ERROR_BASE, + B_DEV_NO_MEMORY, + B_DEV_BAD_DRIVE_NUM, + B_DEV_NO_MEDIA, + B_DEV_UNREADABLE, + B_DEV_FORMAT_ERROR, + B_DEV_TIMEOUT, + B_DEV_RECALIBRATE_ERROR, + B_DEV_SEEK_ERROR, + B_DEV_ID_ERROR, + B_DEV_READ_ERROR, a + B_DEV_WRITE_ERROR, + B_DEV_NOT_READY, + B_DEV_MEDIA_CHANGED, + B_DEV_MEDIA_CHANGE_REQUESTED, + B_DEV_RESOURCE_CONFLICT, + B_DEV_CONFIGURATION_ERROR, 10 + B_DEV_DISABLED_BY_USER, + B_DEV_DOOR_OPEN, + + B_DEV_INVALID_PIPE, 13 + B_DEV_CRC_ERROR, + B_DEV_STALLED, 15 + B_DEV_BAD_PID, + B_DEV_UNEXPECTED_PID, + B_DEV_DATA_OVERRUN, 18 + B_DEV_DATA_UNDERRUN, + B_DEV_FIFO_OVERRUN, 1a + B_DEV_FIFO_UNDERRUN, + B_DEV_PENDING, + B_DEV_MULTIPLE_ERRORS, 1d + B_DEV_TOO_LATE +*/ + +/** + \fn:datafab_initialize + \param udi: device on wich we should perform initialization + \return:error code if initialization failed or B_OK if it passed + + initialize procedure for bulk only protocol devices. +*/ +status_t +datafab_initialize(usb_device_info *udi) +{ + status_t status = B_OK; +/*TODO*/ + return status; +} +/** + \fn:datafab_reset + \param udi: device on wich we should perform reset + \return:error code if reset failed or B_OK if it passed + + reset procedure for bulk only protocol devices. Tries to send + BulkOnlyReset USB request and clear USB_FEATURE_ENDPOINT_HALT features on + input and output pipes. ([2] 3.1) +*/ +status_t +datafab_reset(usb_device_info *udi) +{ + status_t status = B_OK; + /* not required ? */ + return status; +} + +/** + \fn:usb_callback + \param cookie:??? + \param status:??? + \param data:??? + \param actual_len:??? + \return:??? + + ??? +*/ +static void usb_callback(void *cookie, + uint32 status, + void *data, + uint32 actual_len) +{ + if(cookie){ + usb_device_info *udi = (usb_device_info *)cookie; + udi->status = status; + udi->data = data; + udi->actual_len = actual_len; + if(udi->status != B_CANCELED) + release_sem(udi->trans_sem); + } +} + +/** + \fn:queue_bulk + \param udi: device for which que_bulk request is performed + \param buffer: data buffer, used in bulk i/o operation + \param len: length of data buffer + \param b_in: is "true" if input (device->host) data transfer, "false" otherwise + \return: status of operation. + + performs queue_bulk USB request for corresponding pipe and handle timeout of this + operation. +*/ +static status_t +queue_bulk(usb_device_info *udi, + void *buffer, + size_t len, + bool b_in) +{ + status_t status = B_OK; + usb_pipe pipe = b_in ? udi->pipe_in : udi->pipe_out; + status = (*udi->usb_m->queue_bulk)(pipe, buffer, len, usb_callback, udi); + if(status != B_OK){ + PTRACE_ALWAYS(udi, "datafab_queue_bulk:failed:%08x\n", status); + } else { + status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, + /*DATAFAB_USB_TIMEOUT*/ udi->trans_timeout); + if(status != B_OK){ + PTRACE_ALWAYS(udi, "datafab_queue_bulk:acquire_sem_etc failed:%08x\n", status); + (*udi->usb_m->cancel_queued_transfers)(pipe); + } + } + return status; +} + +/** + \fn:handle_INQUIRY + \param usti: pointer to usb_scsi_transport_info sutruct containing request + information + \return: command execution status + + handles INQUIRY SCSI command +*/ +static status_t +handle_INQUIRY(usb_scsi_transport_info *usti) +{ + status_t status = B_CMD_FAILED; + uint8 *data = usti->ccbio->cam_data_ptr; + if(usti->ccbio->cam_ch.cam_flags & CAM_SCATTER_VALID){ + PTRACE(usti->udi,"handle_INQUIRY: problems!!! scatter gatter ....=-(\n"); + } else { + command_registers cr = { + .feature = 0, + .sector_count = 1, + .address = {0}, + .addr_dev = 0xa0, + .command = 0xec, + .intr_reset = 0x01 + }; + + ATA_DEVICE_INFO adi = {0}; + + PTRACE(usti->udi, "ATA_DEVICE_INFO sizeof:%d pipe_in:%x, pipe_out:%x\n", sizeof(adi), + usti->udi->pipe_in, usti->udi->pipe_out); + + PTRACE(usti->udi, "command_registers sizeof:%d\n", sizeof(cr)); + + memset(data, 0, usti->ccbio->cam_dxfer_len); +//TODO!!! + /* data[0] = 0x1F;*/ /* we can play here with type of device */ + /* data[1] = 0x80; + data[2] = 0x02; + data[3] = 0x02; + data[4] = (0 != usti->udi) ? 5 : 31; / * udi != 0 - mean FIX_NO_INQUIRY * / + if(usti->ccbio->cam_dxfer_len >= 0x24){ + strncpy(&data[8], "USB SCSI", INQ_VENDOR_LEN); + strncpy(&data[16], "Reserved", INQ_PRODUCT_LEN); + strncpy(&data[32], "N/A", INQ_REVISION_LEN); + } */ + status = queue_bulk(usti->udi, &cr, sizeof(cr), false); + if(B_OK != status){ + PTRACE(usti->udi, "write command 1 status:%08x\n", status); + //goto finalize; + } + + status = queue_bulk(usti->udi, &adi, sizeof(adi), true); + if(B_OK != status){ + PTRACE(usti->udi, "write command 2 status:%08x\n", status); + goto finalize; + } + + PTRACE(usti->udi, "ADI::info:%08x\n", adi.info); + usti->udi->trace_bytes("ADI::pad1:", (char*)adi.pad1, sizeof(adi.pad1)); + usti->udi->trace_bytes("ADI::serial:", (char*)adi.serial, sizeof(adi.serial)); + usti->udi->trace_bytes("ADI::pad2:", (char*)adi.pad2, sizeof(adi.pad2)); + usti->udi->trace_bytes("ADI::firmware_rev:", (char*)adi.firmware_rev, sizeof(adi.firmware_rev)); + usti->udi->trace_bytes("ADI::model_num:", (char*)adi.model_num, sizeof(adi.model_num)); + usti->udi->trace_bytes("ADI::pad3:", (char*)adi.pad3, sizeof(adi.pad3)); + usti->udi->trace_bytes("ADI::total_secs:", (char*)&adi.total_secs, sizeof(adi.total_secs)); + usti->udi->trace_bytes("ADI::pad4:", (char*)adi.pad4, sizeof(adi.pad4)); + usti->udi->trace_bytes("ADI::pad5:", (char*)adi.pad5, sizeof(adi.pad5)); + usti->udi->trace_bytes("ADI::pad6:", (char*)adi.pad6, sizeof(adi.pad6)); + usti->udi->trace_bytes("ADI::pad7:", (char*)adi.pad7, sizeof(adi.pad7)); + usti->udi->trace_bytes("ADI::pad8:", (char*)adi.pad8, sizeof(adi.pad8)); + usti->udi->trace_bytes("ADI::pad9:", (char*)adi.pad9, sizeof(adi.pad9)); + usti->udi->trace_bytes("ADI::padA:", (char*)adi.padA, sizeof(adi.padA)); + usti->udi->trace_bytes("ADI::padB:", (char*)adi.padB, sizeof(adi.padB)); + +finalize: + status = B_CMD_WIRE_FAILED; + } + return status; +} + +/** + \fn:handle_TEST_UNIT_READY + \param usti: pointer to usb_scsi_transport_info sutruct containing request + information + \return: command execution status + + handles TEST_UNIT_READY SCSI command +*/ +static status_t +handle_TEST_UNIT_READY(usb_scsi_transport_info *usti) +{ + status_t status = B_CMD_FAILED; + return status; +} + +/** + \fn:handle_READ_CAPACITY + \param usti: pointer to usb_scsi_transport_info sutruct containing request + information + \return: command execution status + + handles READ_CAPACITY SCSI command +*/ +static status_t +handle_READ_CAPACITY(usb_scsi_transport_info *usti) +{ + status_t status = B_CMD_FAILED; + return status; +} + +/** + \fn:handle_REQUEST_SENSE + \param usti: pointer to usb_scsi_transport_info sutruct containing request + information + \return: command execution status + + handles REQUEST_SENSE SCSI command +*/ +static status_t +handle_REQUEST_SENSE(usb_scsi_transport_info *usti) +{ + status_t status = B_CMD_FAILED; + return status; +} + +/** + \fn:handle_MODE_SENSE + \param usti: pointer to usb_scsi_transport_info sutruct containing request + information + \return: command execution status + + handles MODE_SENSE SCSI command +*/ +static status_t +handle_MODE_SENSE(usb_scsi_transport_info *usti) +{ + status_t status = B_CMD_FAILED; + return status; +} + +/** + \fn:handle_MODE_SELECT + \param usti: pointer to usb_scsi_transport_info sutruct containing request + information + \return: command execution status + + handles MODE_SELECT SCSI command +*/ +static status_t +handle_MODE_SELECT(usb_scsi_transport_info *usti) +{ + status_t status = B_CMD_FAILED; + return status; +} + +/** + \fn:handle_READ + \param usti: pointer to usb_scsi_transport_info sutruct containing request + information + \return: command execution status + + handles READ SCSI command +*/ +static status_t +handle_READ(usb_scsi_transport_info *usti) +{ + status_t status = B_CMD_FAILED; + return status; +} + +/** + \fn:handle_WRITE + \param usti: pointer to usb_scsi_transport_info sutruct containing request + information + \return: command execution status + + handles WRITE SCSI command +*/ +static status_t +handle_WRITE(usb_scsi_transport_info *usti) +{ + status_t status = B_CMD_FAILED; + return status; +} + +/** + \fn:handle_UnknownCommand + \param usti: pointer to usb_scsi_transport_info sutruct containing request + information + \return: command execution status + + handles "Unknown" SCSI command that were not handled +*/ +static status_t +handle_UnknownCommand(usb_scsi_transport_info *usti) +{ + status_t status = B_CMD_FAILED; + return status; +} + +/** + \fn:datafab_transfer + \param udi: corresponding device + \param cmd: SCSI command to be performed on USB device + \param cmdlen: length of SCSI command + \param data_sg: io vectors array with data to transfer + \param sglist_count: count of entries in io vector array + \param transfer_len: overall length of data to be transferred + \param dir: direction of data transfer + \param ccbio: CCB_SCSIIO struct for original SCSI command + \param cb: callback to handle of final stage of command performing (autosense \ + request etc.) + + transfer procedure for bulk-only protocol. Performs SCSI command on USB device + [2] +*/ +void +datafab_transfer(usb_device_info *udi, + uint8 *cmd, + uint8 cmdlen, + iovec*sg_data, + int32 sg_count, + int32 transfer_len, + EDirection dir, + CCB_SCSIIO *ccbio, + ud_transfer_callback cb) +{ + status_t command_status = B_CMD_WIRE_FAILED;//B_OK; + int32 residue = transfer_len; + usb_scsi_transport_info usti = { + .udi = udi, + .cmd = cmd, + .cmdlen = cmdlen, + .sg_data = sg_data, + .sg_count = sg_count, + .transfer_len = transfer_len, + .dir = dir, + .ccbio = ccbio, + .residue = transfer_len + }; + + switch(cmd[0]){ + case TEST_UNIT_READY: + command_status = handle_TEST_UNIT_READY(&usti); + break; + case INQUIRY: + command_status = handle_INQUIRY(&usti); + break; + case READ_CAPACITY: + command_status = handle_READ_CAPACITY(&usti); + break; + case REQUEST_SENSE: + command_status = handle_REQUEST_SENSE(&usti); + break; + case MODE_SENSE_6: + case MODE_SENSE_10: + command_status = handle_MODE_SENSE(&usti); + break; + case MODE_SELECT_6: + case MODE_SELECT_10: + command_status = handle_MODE_SELECT(&usti); + break; +/* case ALLOW_MEDIUM_REMOVAL: + command_status = handle_ALLOW_MEDIUM_REMOVAL(); + break;*/ + case READ_6: + case READ_10: + case READ_12: + command_status = handle_READ(&usti); + break; + case WRITE_6: + case WRITE_10: + case WRITE_12: + command_status = handle_WRITE(&usti); + break; + default: + command_status = handle_UnknownCommand(&usti); + break; + } + /* finalize transfer */ + cb(udi, ccbio, residue, command_status); +} + +static status_t +std_ops(int32 op, ...) +{ + switch(op) { + case B_MODULE_INIT: + return B_OK; + case B_MODULE_UNINIT: + return B_OK; + default: + return B_ERROR; + } +} + +static protocol_module_info datafab_protocol_module = { + { DATAFAB_PROTOCOL_MODULE_NAME, 0, std_ops }, + datafab_initialize, + datafab_reset, + datafab_transfer, +}; + +_EXPORT protocol_module_info *modules[] = { + &datafab_protocol_module, + NULL +}; diff --git a/src/add-ons/kernel/busses/scsi/usb/datafab/makefile b/src/add-ons/kernel/busses/scsi/usb/datafab/makefile new file mode 100644 index 0000000000..66098b3207 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/datafab/makefile @@ -0,0 +1,146 @@ +## +## This file is a part of BeOS USB Serial driver project. +## Copyright (c) 2005 by Siarzhuk Zharski +## All rights reserved. +## +## Based on BeOS Generic Makefile v2.2 ## + +## Fill in this file to specify the project being created, and the referenced +## makefile-engine will do all of the hard work for you. This handles both +## Intel and PowerPC builds of the BeOS. + +## Application Specific Settings --------------------------------------------- +#SETVERSION=setversion +#GETVERSION=version +#ZIP=zip +#ZIPOPT=-j + +# specify the name of the binary +NAME=datafab + +# specify the type of binary +# APP: Application +# SHARED: Shared library or add-on +# STATIC: Static library archive +# DRIVER: Kernel Driver +TYPE=DRIVER + +# some version definitions +#VER_MAJ = 0 +#VER_MID = 1 +#VER_MIN = 0 +#VER_TYP = d #d-development a-alpha b-beta g-RC f-release +#VER_BLD = 18 +#VER_SHORT = $(NAME) +#VER_LONG = "The module for SCSI interface to USB mass storage devices. Copyright "`echo -n -e '\302\251'`" 2003-2004 by Siarzhuk Zharski" + +# add support for new Pe and Eddie features +# to fill in generic makefile + +#%{ +# @src->@ + +# specify the source files to use +# full paths or paths relative to the makefile can be included +# all files, regardless of directory, will have their object +# files created in the common object directory. +# Note that this means this makefile will not work correctly +# if two source files with the same name (source.c or source.cpp) +# are included from different directories. Also note that spaces +# in folder names do not work well with this makefile. +SRCS=datafab.c + +# specify the resource files to use +# full path or a relative path to the resource file can be used. +RSRCS= + +# @<-src@ +#%} + +# end support for Pe and Eddie + +# specify additional libraries to link against +# there are two acceptable forms of library specifications +# - if your library follows the naming pattern of: +# libXXX.so or libXXX.a you can simply specify XXX +# library: libbe.so entry: be +# +# - if your library does not follow the standard library +# naming scheme you need to specify the path to the library +# and it's name +# library: my_lib.a entry: my_lib.a or path/my_lib.a +LIBS= + +# specify additional paths to directories following the standard +# libXXX.so or libXXX.a naming scheme. You can specify full paths +# or paths relative to the makefile. The paths included may not +# be recursive, so include all of the paths where libraries can +# be found. Directories where source files are found are +# automatically included. +LIBPATHS= + +# additional paths to look for system headers +# thes use the form: #include
+# source file directories are NOT auto-included here +SYSTEM_INCLUDE_PATHS = + +# additional paths to look for local headers +# thes use the form: #include "header" +# source file directories are automatically included +LOCAL_INCLUDE_PATHS = ../ + +# specify the level of optimization that you desire +# NONE, SOME, FULL +OPTIMIZE= + +# specify any preprocessor symbols to be defined. The symbols will not +# have their values set automatically; you must supply the value (if any) +# to use. For example, setting DEFINES to "DEBUG=1" will cause the +# compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" +# would pass "-DDEBUG" on the compiler's command line. +#DEFINES=DEBUG=1 + +# specify special warning levels +# if unspecified default warnings will be used +# NONE = supress all warnings +# ALL = enable all warnings +WARNINGS= + +# specify whether image symbols will be created +# so that stack crawls in the debugger are meaningful +# if TRUE symbols will be created +SYMBOLS=TRUE + +# specify debug settings +# if TRUE will allow application to be run from a source-level +# debugger. Note that this will disable all optimzation. +DEBUGGER=TRUE + +# specify additional compiler flags for all files +COMPILER_FLAGS = + +# specify additional linker flags +LINKER_FLAGS = + +# specify the version of this particular item +# (for example, -app 3 4 0 d 0 -short 340 -long "340 "`echo -n -e '\302\251'`"1999 GNU GPL") +# This may also be specified in a resource. +#APP_VERSION = +#VERSION = $(VER_MAJ) $(VER_MID) $(VER_MIN) $(VER_TYP) $(VER_BLD) -short $(VER_SHORT) -long $(VER_LONG) +#APP_VERSION = -app $(VERSION) +#SYS_VERSION = -system $(VERSION) + +# (for TYPE == DRIVER only) Specify desired location of driver in the /dev +# hierarchy. Used by the driverinstall rule. E.g., DRIVER_PATH = video/usb will +# instruct the driverinstall rule to place a symlink to your driver's binary in +# ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will appear at +# /dev/video/usb when loaded. Default is "misc". +DRIVER_PATH= + +CFLAGS += -Wall + +## include the makefile-engine +include $(BUILDHOME)/etc/makefile-engine + +install: default + copyattr --data $(TARGET) /boot/home/config/add-ons/kernel/generic/usb_scsi_extensions/$(NAME) diff --git a/src/add-ons/kernel/busses/scsi/usb/device_info.h b/src/add-ons/kernel/busses/scsi/usb/device_info.h new file mode 100644 index 0000000000..cdbac7577e --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/device_info.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ +#ifndef _DEVICE_INFO_H_ + #define _DEVICE_INFO_H_ + +#ifndef _SCSI_COMMANDS_H_ + #include "scsi_commands.h" +#endif /*_SCSI_COMMANDS_H_*/ + +#ifndef _PROTO_MODULE_H_ + #include "proto_module.h" +#endif /* _PROTO_MODULE_H_ */ + +typedef struct _usb_device_info{ + uint8 dev_num; /**/ + const usb_device device; /**/ + uint16 interface; /**/ + uint8 max_lun; /**/ + + uint32 properties; + + usb_pipe pipe_in; /**/ + usb_pipe pipe_out; /**/ + usb_pipe pipe_intr; /**/ + + sem_id lock_sem; /**/ + sem_id trans_sem; /**/ + uint32 tag; /**/ + status_t status; /**/ + + bigtime_t trans_timeout; + usb_module_info *usb_m; + + void *data; /**/ + int actual_len; /**/ + + protocol_module_info *protocol_m; + char *protocol_m_path; + + transform_module_info *transform_m; + char *transform_m_path; + + bool b_trace; + void (*trace)(bool b_force, const char *fmt, ...); + void (*trace_bytes)(const char *prefix, const uint8 *bytes, size_t bytes_len); + + uint8 scsi_command_buf[IOCDBLEN]; + /* auto sense buffer. Some commands doesn't have it. emulate */ + scsi_sense_data autosense_data; + /* iovec autosense_sg; DO NOT RESTORE IT !!!*/ + uint8 not_ready_luns; +} usb_device_info; + +#endif /* _DEVICE_INFO_H_ */ diff --git a/src/add-ons/kernel/busses/scsi/usb/fake_device.c b/src/add-ons/kernel/busses/scsi/usb/fake_device.c new file mode 100644 index 0000000000..7b74a8eda6 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/fake_device.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ +#include "usb_scsi.h" + +#include +#include "device_info.h" +#include "tracing.h" + +#include "fake_device.h" + +/* duplication! Hope this fake file will be not required in Haiku version*/ +#define INQ_VENDOR_LEN 0x08 +#define INQ_PRODUCT_LEN 0x10 +#define INQ_REVISION_LEN 0x04 + + +void fake_inquiry_request(usb_device_info *udi, CCB_SCSIIO *ccbio) +{ + uint8 *data = ccbio->cam_data_ptr; + if(ccbio->cam_ch.cam_flags & CAM_SCATTER_VALID){ + TRACE_ALWAYS("fake_inquiry: problems!!! scatter gatter ....=-(\n"); + } else { + memset(data, 0, ccbio->cam_dxfer_len); + /* data[0] = 0x1F;*/ /* we can play here with type of device */ + data[1] = 0x80; + data[2] = 0x02; + data[3] = 0x02; + data[4] = (0 != udi) ? 5 : 31; /* udi != 0 - mean FIX_NO_INQUIRY */ + if(ccbio->cam_dxfer_len >= 0x24){ + strncpy(&data[8], "USB SCSI", INQ_VENDOR_LEN); + strncpy(&data[16], "Reserved", INQ_PRODUCT_LEN); + strncpy(&data[32], "N/A", INQ_REVISION_LEN); + } + } +} + +void fake_test_unit_ready_request(CCB_SCSIIO *ccbio) +{ + if(ccbio->cam_sense_ptr != NULL){ + scsi_sense_data *sense_data = (scsi_sense_data *)ccbio->cam_sense_ptr; + memset(sense_data, 0, ccbio->cam_sense_len); + sense_data->error_code = SSD_CURRENT_ERROR; + sense_data->flags = SSD_KEY_NOT_READY; + ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR | CAM_AUTOSNS_VALID; + ccbio->cam_scsi_status = SCSI_STATUS_CHECK_CONDITION; + } else { + ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR; + ccbio->cam_scsi_status = SCSI_STATUS_OK; + } +} + +/** + \fn:fake_scsi_io + \param ccbio: ???? + \return: ??? + + xpt_scsi_io - handle XPT_SCSI_IO sim action +*/ +status_t fake_scsi_io(CCB_SCSIIO *ccbio) +{ + status_t status = B_BAD_VALUE; + uint8 *cmd; + scsi_cmd_generic *command; + if(ccbio->cam_ch.cam_flags & CAM_CDB_POINTER){ + cmd = ccbio->cam_cdb_io.cam_cdb_ptr; + }else{ + cmd = ccbio->cam_cdb_io.cam_cdb_bytes; + } + command = (scsi_cmd_generic *)cmd; + switch(command->opcode){ + case TEST_UNIT_READY:{ + fake_test_unit_ready_request(ccbio); + status = B_OK; + }break; + case INQUIRY:{ + fake_inquiry_request(NULL, ccbio); + ccbio->cam_ch.cam_status = CAM_REQ_CMP; + status = B_OK; + }break; + default: + ccbio->cam_ch.cam_status = CAM_REQ_INVALID; + break; + } + return status; +} diff --git a/src/add-ons/kernel/busses/scsi/usb/fake_device.h b/src/add-ons/kernel/busses/scsi/usb/fake_device.h new file mode 100644 index 0000000000..f7e0b6cc4f --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/fake_device.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ +#ifndef _FAKE_DEVICE_H_ + #define _FAKE_DEVICE_H_ + +void fake_inquiry_request(usb_device_info *udi, CCB_SCSIIO *ccbio); +void fake_test_unit_ready_request(CCB_SCSIIO *ccbio); +status_t fake_scsi_io(CCB_SCSIIO *ccbio); + +#endif /* _FAKE_DEVICE_H_ */ diff --git a/src/add-ons/kernel/busses/scsi/usb/freecom/COPYING b/src/add-ons/kernel/busses/scsi/usb/freecom/COPYING new file mode 100644 index 0000000000..60549be514 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/freecom/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/add-ons/kernel/busses/scsi/usb/freecom/ReadMe.freecom.html b/src/add-ons/kernel/busses/scsi/usb/freecom/ReadMe.freecom.html new file mode 100644 index 0000000000..f7782023ea --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/freecom/ReadMe.freecom.html @@ -0,0 +1,176 @@ + + + + + FREECOM extension module for BeOS USB mass storage support + + +

FREECOM extension module for + BeOS + USB mass storage support

+ +

This FREECOM extension module (The Extension) is kind of the helper for +BeOS USB Storage Module (The Module) that is designed to support +external CD/DVD drives connected with FREECOM USB 1.1 Cable. +This software is for BeOS/Dano/Zeta operating systems. +

+

Note that this manual contains only FREECOM extension specific information. For general USB +Storage Module questions look into the corresponding manual. +

+ +

Table of Contents

+ + +

1. Installation and using

+
    +
  1. Contents of distribution archive: +
        ReadMe.freecom.html      <--- file you are reading now
    +    install.sh       <--- installation script
    +    uninstall.sh     <--- uninstallation script
    +    freecom              <--- The Extension binary
    +    device_info.sample  <--- device description sample
    +
    +
  2. +
  3. Run ./install.sh to install The Extension on your system. +This script do the following:
  4. +
      +
    • copies The Extension binary to + /boot/home/config/add-ons/kernel/generic/usb_scsi_extensions/ + directory
    • +
    +
      +
    • add device definition into + /boot/home/config/settings/kernel/drivers/usb_scsi + file
    • +
    • ask you to edit settings file. Note that you have to check vendor and product ids for + your FREECOM device and edit device settings correspondently! It is not required to reboot your PC after installing +The Extension and changing it's definitions.
    • +
    +
  5. Plug in your FREECOM CD/DVD drive into USB slot, load a media into it and +try to open Tracker's "Mount" menu some times. In case if all goes OK - +you'll see your CD/DVD volume available for mounting. You can of course use your CD/DVD burning +software with this drive.
  6. +
  7. [optional] To uninstall The Module from your system - run uninstall.sh +from distribution archive or delete files mentioned in +clause 3 of this section manually.
  8. +
+Table +of Contents +

2. Troubleshooting

+
    +
  1. Is my external USB CD/DVD device supported? +
      +
    • Only "old" FREECOM USB 1.1 cable connected drives are supported. Obtain your device + vendor and product ids as described in ReadMe.html for + BeOS USB storage Module, edit the device description in settings file correspondently and try + to work with it. Be sure that your FREECOM device is really non-standard and has 255 as class in + usb device description. Vendor id for FREECOM is 0x07ab. +
    • +
    +
  2. +
  3. Cannot mount my CD/DVDs. +
      +
    • Please check the following: +
        +
      • the binary file /boot/home/config/add-ons/kernel/generic/usb_scsi_extensions/freecom +exists on your system; +
      • +
      • the settings file /boot/home/config/settings/kernel/drivers/usb_scsi +exists on your system and contains description for your FREECOM device;
      • +
      • check that device description correspond to your real device information; +
      • +
      +
    • +
    +
  4. +
  5. My external USB HDD in FREECOM case doesn't work +
      +
    • Only ATAPI devices are supported. ATA protocol doesn't uses SCSI-like commands.
    • +
    +
  6. +
  7. Mmmm... another question... +
      +
    • Please refer to Troubleshooting section of ReadMe.html for BeOS USB Storage Support Module and + contact the developer if you still have a problem. +
    • +
    +
  8. +
+Table of Contents +

3. Writing a problem report

+Refer to corresponding section of ReadMe.html file for BeOS USB Storage Support Module. +Table of Contents +

4.Contact and support information

+The Extension is a part of BeOS USB Support Module project that is hosted on SourceForge +and uses some it's powerful development services. There are some ways to inform +developer about problems or put feature requests for next version +
    +
  1. Use Bug +Tracker to put problem reports.
  2. +
  3. Use Forum +to ask simple support question, discuss any problems. +
  4. Use Mailing-list +to be informed with latest news, ask questions +etc.
  5. +
  6. Also you can contact me personally by e-mail.
  7. +
+Table of Contents +

5.Credits

+

I want to say my "Thanks" to:

+

brave testers...

+Table of Contents +

6. The History

+

+ + + + + + + + + + + + +
Date: Version: What's new:
?? ??April 20050.1.0-alpha-1 first public release.
+

+Table +of Contents +
< End of document >
+ + diff --git a/src/add-ons/kernel/busses/scsi/usb/freecom/device_info.sample b/src/add-ons/kernel/busses/scsi/usb/freecom/device_info.sample new file mode 100644 index 0000000000..9f5aebbe2f --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/freecom/device_info.sample @@ -0,0 +1,21 @@ +########################################################## +## +## USB Storage Module non-standard devices definitions +## +## This file is a part of BeOS USB SCSI interface module project. +## Copyright (c) 2003-2005 by Siarzhuk Zharski +## All rights reserved. +## +########################################################## +# +# FREECOM USB-ATAPI bridge. +# +# Supports FREECOM USB Cable connected CD/DVD drives/burners +# +# +vendor 0x07ab { + device 0xfc01 { + protocol freecom + commandset ATAPI + } +} diff --git a/src/add-ons/kernel/busses/scsi/usb/freecom/freecom.c b/src/add-ons/kernel/busses/scsi/usb/freecom/freecom.c new file mode 100644 index 0000000000..351a679006 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/freecom/freecom.c @@ -0,0 +1,590 @@ +/* + * \file: freecom.c + * \brief: USB SCSI module extention for Freecom USB/IDE adaptor + * + * This file is a part of BeOS USB SCSI interface module project. + * Copyright (c) 2003-2004 by Siarzhuk Zharski + * + * 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, 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This protocol extension module was developed using information from + * "Driver for Freecom USB/IDE adaptor" in Linux usb storage driver and + * "Mac OS X driver for the Freecom Traveller CD writer". + * + * $Source: /cvsroot/sis4be/usb_scsi/freecom/freecom.c,v $ + * $Author: zharik $ + * $Revision: 1.11 $ + * $Date: 2005/04/01 22:39:23 $ + * + */ +#include "usb_scsi.h" + +#include +#include "device_info.h" +#include "proto_module.h" + +#define FREECOM_MODULE_NAME "freecom" +#define FREECOM_PROTOCOL_MODULE_NAME \ + MODULE_PREFIX FREECOM_MODULE_NAME PROTOCOL_SUFFIX + +/** + \struct:fcm_command +*/ +typedef struct { + uint8 type; /* block type. */ +#define FCMT_ATAPI 0x21 /* send command. low bit indicates waiting for interrupt */ +#define FCMT_STATUS 0x20 /* request for status */ +#define FCMT_IN 0x81 /* request read data transfer. */ +#define FCMT_OUT 0x01 /* request write data transfer */ +#define FCMT_REG_IN 0xC0 /* read value from IDE regsiter */ +#define FCMT_REG_OUT 0x40 /* write value to IDE register */ + /* to use FCMT_REG_ combine it with register */ +#define FCMR_DATA 0x10 /* data register */ + /* ... */ +#define FCMR_CMD 0x16 /* status-command register */ +#define FCMR_INT 0x17 /* interrupt-error register */ + uint8 timeout; /* timeout (seconds?) */ +#define FCMTO_DEF 0xfe /* default timeout */ +#define FCMTO_TU 0x14 /* timeout for TEST UNIT READY command */ + union{ + uint8 cmd[12]; /* An ATAPI command. */ + uint32 count; /* number of bytes to transfer. */ + uint16 reg_val; /* Value to write to IDE register. */ + uint8 pad[62]; /* Padding Data. All FREECOM commands are 64 bytes long */ + }_PACKED data; +}_PACKED fcm_command; + +/** + \struct:fcm_status +*/ +typedef struct { + uint8 status; +#define FCMS_BSY 0x80 /* device is busy */ +#define FCMS_DRDY 0x40 /* */ +#define FCMS_DMA 0x20 /* */ +#define FCMS_SEEK 0x10 /* */ +#define FCMS_DRQ 0x08 /* */ +#define FCMS_CORR 0x04 /* */ +#define FCMS_INTR 0x02 /*FREECOM specific: use obsolete bit*/ +#define FCMS_CHECK 0x01 /* device is in error condition */ + uint8 reason; +#define FCMR_REL 0x04 /* */ +#define FCMR_IO 0x02 /* */ +#define FCMR_COD 0x01 /* */ + uint16 count; +}_PACKED fcm_status; + +// Timeout value (in us) for the freecom packet USB BulkRead and BulkWrite functions +#define FREECOM_USB_TIMEOUT 30000000 + +/** + \fn: + \param udi: + \param st: + \return: + +*/ +void trace_status(usb_device_info *udi, const fcm_status *st) +{ + char ch_status[] = "BDFSRCIE"; + char ch_reason[] = ".....RIC"; + int i = 0; + for(; i < 8; i++){ + if(!(st->status & (1 << i))) + ch_status[7 - i] = '.'; + if(!(st->reason & (1 << i))) + ch_reason[7 - i] = '.'; + } + PTRACE(udi, "FCM:Status:{%s; Reason:%s; Count:%d}\n", + ch_status, ch_reason, st->count); +} + +/** + \fn:freecom_initialize + \param udi: device on wich we should perform initialization + \return:error code if initialization failed or B_OK if it passed + + initialize procedure. +*/ +status_t +freecom_initialize(usb_device_info *udi) +{ + status_t status = B_OK; +#define INIT_BUFFER_SIZE 0x20 + char buffer[INIT_BUFFER_SIZE + 1]; + size_t len = 0; + + if(B_OK != (status = (*udi->usb_m->send_request)(udi->device, + USB_REQTYPE_DEVICE_IN | USB_REQTYPE_VENDOR, + 0x4c, 0x4346, 0x0, INIT_BUFFER_SIZE, + buffer, &len))) + { + PTRACE_ALWAYS(udi, "FCM:init[%d]: init failed: %08x\n", udi->dev_num, status); + } else { + buffer[len] = 0; + PTRACE(udi, "FCM:init[%d]: init '%s' OK\n", udi->dev_num, buffer); + } + + if(B_OK != (status = (*udi->usb_m->send_request)(udi->device, + USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_VENDOR, + 0x4d, 0x24d8, 0x0, 0, 0, &len))) + { + PTRACE_ALWAYS(udi, "FCM:init[%d]: reset on failed:%08x\n", udi->dev_num, status); + } + + snooze(250000); + + if(B_OK != (status = (*udi->usb_m->send_request)(udi->device, + USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_VENDOR, + 0x4d, 0x24f8, 0x0, 0, 0, &len))) + { + PTRACE_ALWAYS(udi, "FCM:init[%d]: reset off failed:%08x\n", udi->dev_num, status); + } + + snooze(3 * 1000000); + + return status; +} +/** + \fn:freecom_reset + \param udi: device on wich we should perform reset + \return:error code if reset failed or B_OK if it passed + + reset procedure. +*/ +status_t +freecom_reset(usb_device_info *udi) +{ + status_t status = B_OK; + /* not required ? */ + return status; +} + +/** + \fn:usb_callback + \param cookie:??? + \param status:??? + \param data:??? + \param actual_len:??? + \return:??? + + ??? +*/ +static void usb_callback(void *cookie, + uint32 status, + void *data, + uint32 actual_len) +{ + if(cookie){ + usb_device_info *udi = (usb_device_info *)cookie; +// PTRACE(udi, "FCM:usb_callback:status:0x%08x,len:%d\n", status, actual_len); + udi->status = status; + udi->data = data; + udi->actual_len = actual_len; + if(udi->status != B_CANCELED) + release_sem(udi->trans_sem); + } +} + +/** + \fn:queue_bulk + \param udi: device for which que_bulk request is performed + \param buffer: data buffer, used in bulk i/o operation + \param len: length of data buffer + \param b_in: is "true" if input (device->host) data transfer, "false" otherwise + \return: status of operation. + + performs queue_bulk USB request for corresponding pipe and handle timeout of this + operation. +*/ +static status_t +queue_bulk(usb_device_info *udi, + void *buffer, + size_t len, + bool b_in) +{ + status_t status = B_OK; + usb_pipe pipe = b_in ? udi->pipe_in : udi->pipe_out; + status = (*udi->usb_m->queue_bulk)(pipe, buffer, len, usb_callback, udi); + if(status != B_OK){ + PTRACE_ALWAYS(udi, "FCM:queue_bulk:failed:%08x\n", status); + } else { + status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, FREECOM_USB_TIMEOUT/*udi->trans_timeout*/); + if(status != B_OK){ + PTRACE_ALWAYS(udi, "FCM:queue_bulk:acquire_sem_etc failed:%08x\n", status); + (*udi->usb_m->cancel_queued_transfers)(pipe); + } + } + return status; +} + +/** + \fn:write_command +*/ +static status_t +write_command(usb_device_info *udi, uint8 type, uint8 *cmd, uint8 timeout) +{ + status_t status = B_OK; + /* initialize and fill in command block*/ + fcm_command fc = { + .type = type, + .timeout = FCMTO_DEF, + }; + if(0 != cmd){ + memcpy(fc.data.cmd, cmd, sizeof(fc.data.cmd)); + if(cmd[0] == 0x00){ + fc.timeout = FCMTO_TU; + } + } + PTRACE(udi, "FCM:FC:{Type:0x%02x; TO:%d;}\n", fc.type, fc.timeout); + udi->trace_bytes("FCM:FC::Cmd:\n", fc.data.cmd, sizeof(fc.data.cmd)); + udi->trace_bytes("FCM:FC::Pad:\n", fc.data.pad, sizeof(fc.data.pad)); +PTRACE(udi,"sizeof:%d\n",sizeof(fc)); + /* send command block to device */ + status = queue_bulk(udi, &fc, sizeof(fc), false); + if(status != B_OK || udi->status != B_OK){ + PTRACE_ALWAYS(udi, "FCM:write_command failed:status:%08x usb status:%08x\n", + status, udi->status); + //(*udi->protocol_m->reset)(udi); + status = B_CMD_WIRE_FAILED; + } + return status; +} + +/** + \fn:read_status +*/ +static status_t +read_status(usb_device_info *udi, fcm_status *fst) +{ + status_t status = B_OK; + do{ + /* cleanup structure */ + memset(fst, 0, sizeof(fcm_status)); + /* read status */ + status = queue_bulk(udi, fst, sizeof(fcm_status), true); + if(status != B_OK || udi->status != B_OK){ + PTRACE_ALWAYS(udi, "FCM:read_status failed:" + "status:%08x usb status:%08x\n", status, udi->status); + //(*udi->protocol_m->reset)(udi); + status = B_CMD_WIRE_FAILED; + break; + } + if(udi->actual_len != sizeof(fcm_status)){ + PTRACE_ALWAYS(udi, "FCM:read_status failed:requested:%d, readed %d bytes\n", + sizeof(fcm_status), udi->actual_len); + status = B_CMD_WIRE_FAILED; + break; + } + /* trace readed status info. if required. */ + trace_status(udi, fst); + if(fst->status & FCMS_BSY){ + PTRACE(udi, "FCM:read_status:Timeout. Poll device with another status request.\n"); + if(B_OK != (status = write_command(udi, FCMT_STATUS, 0, 0))){ + PTRACE_ALWAYS(udi, "FCM:read_status failed:write_command_block failed %08x\n", status); + break; + } + } + }while(fst->status & FCMS_BSY); /* repeat until device is busy */ + return status; +} + +/** + \fn:request_transfer +*/ +static status_t +request_transfer(usb_device_info *udi, uint8 type, uint32 length, uint8 timeout) +{ + status_t status = B_OK; + /* initialize and fill in Command Block */ + fcm_command fc = { + .type = type, + .timeout = timeout, + }; + fc.data.count = length; + + PTRACE(udi, "FCM:FC:{Type:0x%02x; TO:%d; Count:%d}\n", fc.type, fc.timeout, fc.data.count); + udi->trace_bytes("FCM:FC::Pad:\n", fc.data.pad, sizeof(fc.data.pad)); +PTRACE(udi,"sizeof:%d\n",sizeof(fc)); + /* send command block to device */ + status = queue_bulk(udi, &fc, sizeof(fc), false); + if(status != B_OK || udi->status != B_OK){ + PTRACE_ALWAYS(udi, "FCM:request_transfer:fc send failed:" + "status:%08x usb status:%08x\n", status, udi->status); + status = B_CMD_WIRE_FAILED; + } + return status; +} + + +/** + \fn:transfer_sg + \param udi: corresponding device + \param data_sg: io vectors array with data to transfer + \param sglist_count: count of entries in io vector array + \param offset: + \param block_len: + \param b_in: direction of data transfer) + + +*/ +static status_t +transfer_sg(usb_device_info *udi, + iovec *data_sg, + int32 sglist_count, + int32 offset, + int32 *block_len, + bool b_in) +{ + status_t status = B_OK; + usb_pipe pipe = (b_in) ? udi->pipe_in : udi->pipe_out; + int32 off = offset; + int32 to_xfer = *block_len; + /* iterate through SG list */ + int i = 0; + for(; i < sglist_count && to_xfer > 0; i++) { + if(off < data_sg[i].iov_len) { + int len = min(to_xfer, (data_sg[i].iov_len - off)); + char *buf = ((char *)data_sg[i].iov_base) + off; + /* transfer linear block of data to/from device */ + if(B_OK == (status = (*udi->usb_m->queue_bulk)(pipe, buf, len, usb_callback, udi))) { + status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, FREECOM_USB_TIMEOUT); + if(status == B_OK){ + status = udi->status; + if(B_OK != status){ + PTRACE_ALWAYS(udi, "FCM:transfer_sg:usb transfer status is not OK:%08x\n", status); + } + } else { + PTRACE_ALWAYS(udi, "FCM:transfer_sg:acquire_sem_etc failed:%08x\n", status); + goto finalize; + } + } else { + PTRACE_ALWAYS(udi, "FCM:transfer_sg:queue_bulk failed:%08x\n", status); + goto finalize; + } + /*check amount of transferred data*/ + if(len != udi->actual_len){ + PTRACE_ALWAYS(udi, "FCM:transfer_sg:WARNING!!!Length reported:%d required:%d\n", + udi->actual_len, len); + } + /* handle offset logic */ + to_xfer -= len; + off = 0; + } else { + off -= data_sg[i].iov_len; + } + } +finalize: + *block_len -= to_xfer; + return (B_OK != status) ? B_CMD_WIRE_FAILED : status; +} + +static status_t +transfer_data(usb_device_info *udi, + iovec *data_sg, + int32 sglist_count, + int32 transfer_length, + int32 *residue, + fcm_status *fst, + bool b_in) +{ + status_t status = B_OK; + int32 readed_len = 0; + uint8 xfer_type = b_in ? FCMT_IN : FCMT_OUT; + int32 block_len = (FCMR_COD == (fst->reason & FCMR_COD)) ? + transfer_length : fst->count; + /* Strange situation with SCSIProbe - device say about 6 bytes available for 5-bytes + request. Read 5 and all is ok. Hmm... */ + if(block_len > transfer_length){ + PTRACE_ALWAYS(udi, "FCM:transfer_data:TRUNCATED! " + "requested:%d available:%d.\n", transfer_length, block_len); + block_len = transfer_length; + } + /* iterate until data will be transferred */ + while(readed_len < transfer_length && block_len > 0){ + /* send transfer block */ + if(B_OK != (status = request_transfer(udi, xfer_type, block_len, 0))){ + goto finalize; + } + /* check if data available/awaited */ + if(FCMS_DRQ != (fst->status & FCMS_DRQ)){ + PTRACE_ALWAYS(udi, "FCM:transfer_data:device doesn't want to transfer anything!!!\n"); + status = B_CMD_FAILED; + goto finalize; + } + /* check the device state */ + if(!((fst->reason & FCMR_REL) == 0 && + (fst->reason & FCMR_IO) == ((b_in) ? FCMR_IO : 0) && + (fst->reason & FCMR_COD) == 0)) + { + PTRACE_ALWAYS(udi, "FCM:transfer_data:device doesn't ready to transfer?\n"); + status = B_CMD_FAILED; + goto finalize; + } + /* transfer scatter/gather safely only for length bytes at specified offset */ + if(B_OK != (status = transfer_sg(udi, data_sg, + sglist_count, readed_len, &block_len, b_in))) + { + goto finalize; + } + /* read status */ + if(B_OK != (status = read_status(udi, fst))){ + goto finalize; + } + /* check device error state */ + if(fst->status & FCMS_CHECK){ + PTRACE(udi, "FCM:transfer_data:data transfer failed?\n", fst->status); + status = B_CMD_FAILED; + goto finalize; + } + /* we have read block successfully */ + readed_len += block_len; + /* check device state and amount of data */ + if((fst->reason & FCMR_COD) == FCMR_COD){ +#if 0 /* too frequently reported - disabled to prevent log trashing */ + if(readed_len < transfer_length){ + PTRACE_ALWAYS(udi, "FCM:transfer_data:Device had LESS data that we wanted.\n"); + } +#endif + break; /* exit iterations - device has finished the talking */ + } else { + if(readed_len >= transfer_length){ + PTRACE_ALWAYS(udi, "FCM:transfer_data:Device had MORE data that we wanted.\n"); + break; + } + block_len = fst->count; /* still have something to read */ + } + } + /* calculate residue */ + *residue -= readed_len; + if(*residue < 0) + *residue = 0; /* TODO: consistency between SG length and transfer length - + in MODE_SENSE_10 converted commands f.example ... */ + PTRACE(udi,"FCM:transfer_data:was requested:%d, residue:%d\n", transfer_length, *residue); +finalize: + return status; /* TODO: MUST return B_CMD_*** error codes !!!!! */ +} + +/** + \fn:freecom_transfer + \param udi: corresponding device + \param cmd: SCSI command to be performed on USB device + \param cmdlen: length of SCSI command + \param data_sg: io vectors array with data to transfer + \param sglist_count: count of entries in io vector array + \param transfer_len: overall length of data to be transferred + \param dir: direction of data transfer + \param ccbio: CCB_SCSIIO struct for original SCSI command + \param cb: callback to handle of final stage of command performing (autosense \ + request etc.) + + transfer procedure for bulk-only protocol. Performs SCSI command on USB device + [2] +*/ +void +freecom_transfer(usb_device_info *udi, + uint8 *cmd, + uint8 cmdlen, + iovec*sg_data, + int32 sg_count, + int32 transfer_len, + EDirection dir, + CCB_SCSIIO *ccbio, + ud_transfer_callback cb) +{ + status_t command_status = B_CMD_WIRE_FAILED; + int32 residue = transfer_len; + fcm_status fst = {0}; + + /* Current BeOS scsi_cd driver bombs us with lot of + MODE_SENSE/MODE_SELECT commands. Unfortunately some of them + hangs the Freecom firmware. Try to ignore translated ones */ +#if 1 + if((MODE_SENSE_10 == cmd[0] && 0x0e == cmd[2]) || + (MODE_SELECT_10 == cmd[0] && 0x10 == cmd[1])) + { + uint8 *cmd_org = 0; + /* set the command data pointer */ + if(ccbio->cam_ch.cam_flags & CAM_CDB_POINTER){ + cmd_org = ccbio->cam_cdb_io.cam_cdb_ptr; + }else{ + cmd_org = ccbio->cam_cdb_io.cam_cdb_bytes; + } + if(cmd_org[0] != cmd[0]){ + if(MODE_SENSE_10 == cmd[0]){ /* emulate answer - return empty pages */ + scsi_mode_param_header_10 *hdr = (scsi_mode_param_header_10*)sg_data[0].iov_base; + memset(hdr, 0, sizeof(scsi_mode_param_header_10)); + hdr->mode_data_len[1] = 6; + PTRACE(udi, "FCM:freecom_transfer:MODE_SENSE_10 ignored %02x->02x\n", cmd_org[0], cmd[0]); + } else { + PTRACE(udi, "FCM:freecom_transfer:MODE_SELECT_10 ignored %02x->%02x\n", cmd_org[0], cmd[0]); + } + command_status = B_OK; /* just say that command processed OK */ + goto finalize; + } + } +#endif + /* write command to device */ + if(B_OK != (command_status = write_command(udi, FCMT_ATAPI, cmd, 0))){ + PTRACE_ALWAYS(udi, "FCM:freecom_transfer:" + "send command failed. Status:%08x\n", command_status); + goto finalize; + } + /* obtain status */ + if(B_OK != (command_status = read_status(udi, &fst))){ + PTRACE_ALWAYS(udi, "FCM:freecom_transfer:" + "read status failed. Status:%08x\n", command_status); + goto finalize; + } + /* check device error state */ + if(fst.status & FCMS_CHECK){ + PTRACE_ALWAYS(udi, "FCM:freecom_transfer:FST.Status is not OK\n"); + command_status = B_CMD_FAILED; + goto finalize; + } + /* transfer data */ + if(transfer_len != 0x0 && dir != eDirNone){ + command_status = transfer_data(udi, sg_data, sg_count, transfer_len, + &residue, &fst, (eDirIn == dir)); + } +finalize: + /* finalize transfer */ + cb(udi, ccbio, residue, command_status); +} + +static status_t +std_ops(int32 op, ...) +{ + switch(op) { + case B_MODULE_INIT: + return B_OK; + case B_MODULE_UNINIT: + return B_OK; + default: + return B_ERROR; + } +} + +static protocol_module_info freecom_protocol_module = { + { FREECOM_PROTOCOL_MODULE_NAME, 0, std_ops }, + freecom_initialize, + freecom_reset, + freecom_transfer, +}; + +_EXPORT protocol_module_info *modules[] = { + &freecom_protocol_module, + NULL +}; diff --git a/src/add-ons/kernel/busses/scsi/usb/freecom/install.sh b/src/add-ons/kernel/busses/scsi/usb/freecom/install.sh new file mode 100755 index 0000000000..2236a511cd --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/freecom/install.sh @@ -0,0 +1,41 @@ +#!/bin/sh +########################################################## +## +## USB Storage Module installation script +## +## This file is a part of BeOS USB SCSI interface module project. +## Copyright (c) 2003-2004 by Siarzhuk Zharski +## All rights reserved. +## +## $Source: /cvsroot/sis4be/usb_scsi/freecom/install.sh,v $ +## $Author: zharik $ +## $Revision: 1.1 $ +## $Date: 2005/04/09 22:16:17 $ +## +########################################################## + +MODULE_TITLE="FREECOM extension for USB Storage Module" +MODULE_NAME=freecom +SETTINGS_NAME=usb_scsi + +answer=`alert "Do you really want to install the $MODULE_TITLE ?" "No" "Yes"` +if [ $answer == "No" ]; then + exit +fi + +/boot/beos/bin/install -d ~/config/add-ons/kernel/generic/usb_scsi_extension/ +/boot/beos/bin/install `dirname $0`/$MODULE_NAME ~/config/add-ons/kernel/generic/usb_scsi_extension/$MODULE_NAME + +# TODO!!! +#if [ -e ~/config/settings/kernel/drivers/$SETTINGS_NAME ]; then +#/boot/beos/bin/cp `dirname $0`/$SETTINGS_NAME.sample ~/config/settings/kernel/drivers/ +#else +#/boot/beos/bin/cp `dirname $0`/$SETTINGS_NAME.sample ~/config/settings/kernel/drivers/$SETTINGS_NAME +#fi + +mimeset ~/config/add-ons/kernel/generic/usb_scsi_extension/$MODULE_NAME + +INSTALLED_MESSAGE="The $MODULE_TITLE has been installed on your system. You have to review/edit settings for your FREECOM device." +alert "$INSTALLED_MESSAGE" "Edit settings" + +StyledEdit /boot/home/config/settings/kernel/drivers/$SETTINGS_NAME diff --git a/src/add-ons/kernel/busses/scsi/usb/freecom/makefile b/src/add-ons/kernel/busses/scsi/usb/freecom/makefile new file mode 100644 index 0000000000..82714117d7 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/freecom/makefile @@ -0,0 +1,151 @@ +## +## This file is a part of BeOS USB Serial driver project. +## Copyright (c) 2003-2004 by Siarzhuk Zharski +## All rights reserved. +## +## $Source: /cvsroot/sis4be/usb_scsi/freecom/makefile,v $ +## $Author: zharik $ +## $Revision: 1.5 $ +## $Date: 2005/04/09 22:23:20 $ +## +## Based on BeOS Generic Makefile v2.2 ## + +## Fill in this file to specify the project being created, and the referenced +## makefile-engine will do all of the hard work for you. This handles both +## Intel and PowerPC builds of the BeOS. + +## Application Specific Settings --------------------------------------------- +#SETVERSION=setversion +#GETVERSION=version +#ZIP=zip +#ZIPOPT=-j + +# specify the name of the binary +NAME=freecom + +# specify the type of binary +# APP: Application +# SHARED: Shared library or add-on +# STATIC: Static library archive +# DRIVER: Kernel Driver +TYPE=DRIVER + +# some version definitions +#VER_MAJ = 0 +#VER_MID = 1 +#VER_MIN = 0 +#VER_TYP = d #d-development a-alpha b-beta g-RC f-release +#VER_BLD = 18 +#VER_SHORT = $(NAME) +#VER_LONG = "The module for SCSI interface to USB mass storage devices. Copyright "`echo -n -e '\302\251'`" 2003-2004 by Siarzhuk Zharski" + +# add support for new Pe and Eddie features +# to fill in generic makefile + +#%{ +# @src->@ + +# specify the source files to use +# full paths or paths relative to the makefile can be included +# all files, regardless of directory, will have their object +# files created in the common object directory. +# Note that this means this makefile will not work correctly +# if two source files with the same name (source.c or source.cpp) +# are included from different directories. Also note that spaces +# in folder names do not work well with this makefile. +SRCS=freecom.c + +# specify the resource files to use +# full path or a relative path to the resource file can be used. +RSRCS= + +# @<-src@ +#%} + +# end support for Pe and Eddie + +# specify additional libraries to link against +# there are two acceptable forms of library specifications +# - if your library follows the naming pattern of: +# libXXX.so or libXXX.a you can simply specify XXX +# library: libbe.so entry: be +# +# - if your library does not follow the standard library +# naming scheme you need to specify the path to the library +# and it's name +# library: my_lib.a entry: my_lib.a or path/my_lib.a +LIBS= + +# specify additional paths to directories following the standard +# libXXX.so or libXXX.a naming scheme. You can specify full paths +# or paths relative to the makefile. The paths included may not +# be recursive, so include all of the paths where libraries can +# be found. Directories where source files are found are +# automatically included. +LIBPATHS= + +# additional paths to look for system headers +# thes use the form: #include
+# source file directories are NOT auto-included here +SYSTEM_INCLUDE_PATHS = + +# additional paths to look for local headers +# thes use the form: #include "header" +# source file directories are automatically included +LOCAL_INCLUDE_PATHS = ../ + +# specify the level of optimization that you desire +# NONE, SOME, FULL +OPTIMIZE= + +# specify any preprocessor symbols to be defined. The symbols will not +# have their values set automatically; you must supply the value (if any) +# to use. For example, setting DEFINES to "DEBUG=1" will cause the +# compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" +# would pass "-DDEBUG" on the compiler's command line. +#DEFINES=DEBUG=1 + +# specify special warning levels +# if unspecified default warnings will be used +# NONE = supress all warnings +# ALL = enable all warnings +WARNINGS= + +# specify whether image symbols will be created +# so that stack crawls in the debugger are meaningful +# if TRUE symbols will be created +SYMBOLS=TRUE + +# specify debug settings +# if TRUE will allow application to be run from a source-level +# debugger. Note that this will disable all optimzation. +DEBUGGER=TRUE + +# specify additional compiler flags for all files +COMPILER_FLAGS = + +# specify additional linker flags +LINKER_FLAGS = + +# specify the version of this particular item +# (for example, -app 3 4 0 d 0 -short 340 -long "340 "`echo -n -e '\302\251'`"1999 GNU GPL") +# This may also be specified in a resource. +#APP_VERSION = +#VERSION = $(VER_MAJ) $(VER_MID) $(VER_MIN) $(VER_TYP) $(VER_BLD) -short $(VER_SHORT) -long $(VER_LONG) +#APP_VERSION = -app $(VERSION) +#SYS_VERSION = -system $(VERSION) + +# (for TYPE == DRIVER only) Specify desired location of driver in the /dev +# hierarchy. Used by the driverinstall rule. E.g., DRIVER_PATH = video/usb will +# instruct the driverinstall rule to place a symlink to your driver's binary in +# ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will appear at +# /dev/video/usb when loaded. Default is "misc". +DRIVER_PATH= + +CFLAGS += -Wall + +## include the makefile-engine +include $(BUILDHOME)/etc/makefile-engine + +install: default + copyattr --data $(TARGET) /boot/home/config/add-ons/kernel/generic/usb_scsi_extensions/$(NAME) diff --git a/src/add-ons/kernel/busses/scsi/usb/freecom/uninstall.sh b/src/add-ons/kernel/busses/scsi/usb/freecom/uninstall.sh new file mode 100755 index 0000000000..98d8e15621 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/freecom/uninstall.sh @@ -0,0 +1,33 @@ +#!/bin/sh +########################################################## +## +## USB Storage Module uninstallation script +## +## This file is a part of BeOS USB SCSI interface module project. +## Copyright (c) 2003-2004 by Siarzhuk Zharski +## All rights reserved. +## +## $Source: /cvsroot/sis4be/usb_scsi/freecom/uninstall.sh,v $ +## $Author: zharik $ +## $Revision: 1.1 $ +## $Date: 2005/04/09 22:16:17 $ +## +########################################################## + +DRIVER_TITLE="FREECOM extension for USB Storage Module" +SETTINGS_NAME=usb_scsi +DRIVER_TARGET_NAME=freecom + +answer=`alert "Do you really want to uninstall the $DRIVER_TITLE ?" "No" "Yes"` +if [ $answer == "No" ]; then + exit +fi + +rm ~/config/add-ons/kernel/generic/usb_scsi_extension/$DRIVER_TARGET_NAME + +answer=`alert "The $DRIVER_TITLE has been removed from your system. You can now remove FREECOM device description for settings file." "OK" "Edit settings"` +if [ $answer == "OK" ]; then + exit +fi + +StyledEdit /boot/home/config/settings/kernel/drivers/$SETTINGS_NAME diff --git a/src/add-ons/kernel/busses/scsi/usb/install.sh b/src/add-ons/kernel/busses/scsi/usb/install.sh new file mode 100755 index 0000000000..5390c2a03f --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/install.sh @@ -0,0 +1,45 @@ +#!/bin/sh +########################################################## +## +## USB Storage Module installation script +## +## This file is a part of BeOS USB SCSI interface module project. +## Copyright (c) 2003-2004 by Siarzhuk Zharski +## All rights reserved. +## +## $Source: /cvsroot/sis4be/usb_scsi/install.sh,v $ +## $Author: zharik $ +## $Revision: 1.5 $ +## $Date: 2004/06/06 09:19:47 $ +## +########################################################## + +MODULE_TITLE="USB Storage Module" +MODULE_NAME=usb +SETTINGS_NAME=usb_scsi + +answer=`alert "Do you really want to install the $MODULE_TITLE ?" "No" "Yes"` +if [ $answer == "No" ]; then + exit +fi + +/boot/beos/bin/install -d ~/config/add-ons/kernel/busses/scsi/ +/boot/beos/bin/install `dirname $0`/$MODULE_NAME ~/config/add-ons/kernel/busses/scsi/$MODULE_NAME +if [ -e ~/config/settings/kernel/drivers/$SETTINGS_NAME ]; then +/boot/beos/bin/cp `dirname $0`/$SETTINGS_NAME.sample ~/config/settings/kernel/drivers/ +else +/boot/beos/bin/cp `dirname $0`/$SETTINGS_NAME.sample ~/config/settings/kernel/drivers/$SETTINGS_NAME +fi + +mimeset ~/config/add-ons/kernel/busses/scsi/$MODULE_NAME +mimeset ~/config/settings/kernel/drivers/$SETTINGS_NAME + +INSTALLED_MESSAGE="The $MODULE_TITLE has been installed on your system.You have to reboot your system before using it." +answer=`alert "$INSTALLED_MESSAGE" "Edit settings" "Reboot" "OK"` +if [ $answer == "OK" ]; then + exit +elif [ $answer == "Reboot" ]; then + shutdown -r +fi + +StyledEdit /boot/home/config/settings/kernel/drivers/$SETTINGS_NAME diff --git a/src/add-ons/kernel/busses/scsi/usb/proto_bulk.c b/src/add-ons/kernel/busses/scsi/usb/proto_bulk.c new file mode 100644 index 0000000000..dc89975c25 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/proto_bulk.c @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/** bulk-only protocol specific implementation */ + +/* References: + * USB Mass Storage Class specifications: + * http://www.usb.org/developers/data/devclass/usbmassover_11.pdf [1] + * http://www.usb.org/developers/data/devclass/usbmassbulk_10.pdf [2] + */ +#include "usb_scsi.h" + +#include "device_info.h" + +#include "proto_module.h" +#include "proto_common.h" +#include "proto_bulk.h" + +#include "usb_defs.h" + +#include /* strncpy */ + +/*Bulk-Only protocol specifics*/ +#define USB_REQ_MS_RESET 0xff /* Bulk-Only reset */ +#define USB_REQ_MS_GET_MAX_LUN 0xfe /* Get maximum lun */ + +/* Command Block Wrapper */ +typedef struct _usb_mass_CBW{ + uint32 signature; + uint32 tag; + uint32 data_transfer_len; + uint8 flags; + uint8 lun; + uint8 cdb_len; +#define CBW_CDB_LENGTH 16 + uint8 CDB[CBW_CDB_LENGTH]; +} usb_mass_CBW; /*sizeof(usb_mass_CBW) must be 31*/ +#define CBW_LENGTH 0x1f + +/* Command Status Wrapper */ +typedef struct _usb_mass_CSW{ + uint32 signature; + uint32 tag; + uint32 data_residue; + uint8 status; +} usb_mass_CSW; /*sizeof(usb_mass_CSW) must be 13*/ +#define CSW_LENGTH 0x0d + +#define CSW_STATUS_GOOD 0x0 +#define CSW_STATUS_FAILED 0x1 +#define CSW_STATUS_PHASE 0x2 + +#define CBW_SIGNATURE 0x43425355 +#define CSW_SIGNATURE 0x53425355 + +#define CBW_FLAGS_OUT 0x00 +#define CBW_FLAGS_IN 0x80 + +/*=========================== tracing helpers ==================================*/ +void trace_CBW(usb_device_info *udi, const usb_mass_CBW *cbw) +{ + char buf[sizeof(uint32) + 1] = {0}; + strncpy(buf, (char *)&cbw->signature, sizeof(uint32)); + PTRACE(udi, "\nCBW:{'%s'; tag:%d; data_len:%d; flags:0x%02x; lun:%d; cdb_len:%d;}\n", + buf, + cbw->tag, + cbw->data_transfer_len, + cbw->flags, + cbw->lun, + cbw->cdb_len); + udi->trace_bytes("CDB:\n", cbw->CDB, CBW_CDB_LENGTH); +} + +void trace_CSW(usb_device_info *udi, const usb_mass_CSW *csw) +{ + char buf[sizeof(uint32) + 1] = {0}; + strncpy(buf, (char *)&csw->signature, sizeof(uint32)); + PTRACE(udi, "CSW:{'%s'; tag:%d; residue:%d; status:0x%02x}\n", + buf, + csw->tag, + csw->data_residue, + csw->status); +} + +/** + \fn:get_max_luns + \param udi: device for wich max LUN info is requested + \return:always B_OK - if info was not retrieved max LUN is defaulted to 0 + + tries to retrieve the maximal Logical Unit Number supported by + this device. If device doesn't support GET_MAX_LUN request - single LUN is + assumed. ([2] 3.2) +*/ +static status_t +get_max_luns(usb_device_info *udi) +{ + status_t status = B_OK; + udi->max_lun = 0; + if(!HAS_FIXES(udi->properties, FIX_NO_GETMAXLUN)){ + size_t len = 0; + if(B_OK != (status = (*udi->usb_m->send_request)(udi->device, + USB_REQTYPE_INTERFACE_IN | USB_REQTYPE_CLASS, + USB_REQ_MS_GET_MAX_LUN, 0x0, udi->interface, + 0x1, &udi->max_lun, &len))) + { + if(status == B_DEV_STALLED){ + PTRACE_ALWAYS(udi, "get_max_luns[%d]:not supported. " + "Assuming single LUN available.\n", udi->dev_num); + } else { + PTRACE(udi, "get_max_luns[%d]:failed(%08x)." + "Assuming single LUN available.\n", udi->dev_num, status); + } + udi->max_lun = 0; + status = B_OK; + } /* else - all is OK - max luns info readed */ + } + return status; +} +/** + \fn:queue_bulk + \param udi: device for which que_bulk request is performed + \param buffer: data buffer, used in bulk i/o operation + \param len: length of data buffer + \param b_in: is "true" if input (device->host) data transfer, "false" otherwise + \return: status of operation. + + performs queue_bulk USB request for corresponding pipe and handle timeout of this + operation. +*/ +static status_t +queue_bulk(usb_device_info *udi, + void *buffer, + size_t len, + bool b_in) +{ + status_t status = B_OK; + usb_pipe pipe = b_in ? udi->pipe_in : udi->pipe_out; + status = (*udi->usb_m->queue_bulk)(pipe, buffer, len, bulk_callback, udi); + if(status != B_OK){ + PTRACE_ALWAYS(udi, "queue_bulk:failed:%08x\n", status); + } else { + status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, udi->trans_timeout/*LOCK_TIMEOUT*/); + if(status != B_OK){ + PTRACE_ALWAYS(udi, "queue_bulk:acquire_sem_etc failed:%08x\n", status); + (*udi->usb_m->cancel_queued_transfers)(pipe); + } + } + return status; +} +/** + \fn:check_CSW + \param udi:corresponding device info + \param csw: CSW to be checked for validity and meaningfullness + \param transfer_len: data transferred during operation, which is checked for status + \return: "true" if CSW valid and meanigfull, "false" otherwise + + checks CSW for validity and meaningfullness as required by USB mass strorge + BulkOnly specification ([2] 6.3) +*/ +static bool +check_CSW(usb_device_info *udi, + usb_mass_CSW *csw, + int transfer_len) +{ + bool is_valid = false; + do{ + /* check for CSW validity */ + if(udi->actual_len != CSW_LENGTH){ + PTRACE_ALWAYS(udi, "check_CSW:wrong length %d instead of %d\n", + udi->actual_len, CSW_LENGTH); + break;/* failed */ + } + if(csw->signature != CSW_SIGNATURE){ + PTRACE_ALWAYS(udi, "check_CSW:wrong signature %08x instead of %08x\n", + csw->signature, CSW_SIGNATURE); + break;/* failed */ + } + if(csw->tag != udi->tag - 1){ + PTRACE_ALWAYS(udi, "check_CSW:tag mismatch received:%d, awaited:%d\n", + csw->tag, udi->tag-1); + break;/* failed */ + } + /* check for CSW meaningfullness */ + if(CSW_STATUS_PHASE == csw->status){ + PTRACE_ALWAYS(udi, "check_CSW:not meaningfull: phase error\n"); + break;/* failed */ + } + if(transfer_len < csw->data_residue){ + PTRACE_ALWAYS(udi, "check_CSW:not meaningfull: " + "residue:%d is greater than transfer length:%d\n", + csw->data_residue, transfer_len); + break;/* failed */ + } + is_valid = true; + }while(false); + return is_valid; +} +/** + \fn:read_status + \param udi: corresponding device + \param csw: buffer for CSW data + \param transfer_len: data transferred during operation, which is checked for status + \return: success status code + + reads CSW from device as proposed in ([2] 5.3.3; Figure 2.). +*/ +static status_t +read_status(usb_device_info *udi, + usb_mass_CSW *csw, + int transfer_len) +{ + status_t status = B_ERROR; + int try = 0; + do{ + status = queue_bulk(udi, csw, CSW_LENGTH, true); + if(0 == try){ + if(B_OK != status || B_OK != udi->status){ + status = (*udi->usb_m->clear_feature)(udi->pipe_in, USB_FEATURE_ENDPOINT_HALT); + if(status != 0){ + PTRACE_ALWAYS(udi, "read_status:failed 1st try, " + "status:%08x; usb_status:%08x\n", status, udi->status); + (*udi->protocol_m->reset)(udi); + break; + } + continue; /* go to second try*/ + } + /* CSW was readed without errors */ + } else { /* second try */ + if(B_OK != status || B_OK != udi->status){ + PTRACE_ALWAYS(udi, "read_status:failed 2nd try status:%08x; usb_status:%08x\n", + status, udi->status); + (*udi->protocol_m->reset)(udi); + status = (B_OK == status) ? udi->status : status; + break; + } + } + if(!check_CSW(udi, csw, transfer_len)){ + (*udi->protocol_m->reset)(udi); + status = B_ERROR; + break; + } + trace_CSW(udi, csw); + break; /* CSW was read successfully */ + }while(try++ < 2); + return status; +} + +/*================= "standard" protocol procedures ==============================*/ + +/** + \fn:bulk_only_initialize + \param udi: device on wich we should perform initialization + \return:error code if initialization failed or B_OK if it passed + + initialize procedure for bulk only protocol devices. +*/ +status_t +bulk_only_initialize(usb_device_info *udi) +{ + status_t status = B_OK; + status = get_max_luns(udi); + return status; +} +/** + \fn:bulk_only_reset + \param udi: device on wich we should perform reset + \return:error code if reset failed or B_OK if it passed + + reset procedure for bulk only protocol devices. Tries to send + BulkOnlyReset USB request and clear USB_FEATURE_ENDPOINT_HALT features on + input and output pipes. ([2] 3.1) +*/ +status_t +bulk_only_reset(usb_device_info *udi) +{ + status_t status = B_ERROR; + status = (*udi->usb_m->send_request)(udi->device, + USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, + USB_REQ_MS_RESET, 0, + udi->interface, 0, 0, 0); + if(status != B_OK){ + PTRACE_ALWAYS(udi, "bulk_only_reset: reset request failed: %08x\n", status); + } + if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_in, + USB_FEATURE_ENDPOINT_HALT))) + { + PTRACE_ALWAYS(udi, "bulk_only_reset: clear_feature on pipe_in failed: %08x\n", status); + } + if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_out, + USB_FEATURE_ENDPOINT_HALT))) + { + PTRACE_ALWAYS(udi, "bulk_only_reset: clear_feature on pipe_out failed: %08x\n", status); + } + PTRACE(udi, "bulk_only_reset:%08x\n", status); + return status; +} +/** + \fn:bulk_only_transfer + \param udi: corresponding device + \param cmd: SCSI command to be performed on USB device + \param cmdlen: length of SCSI command + \param data_sg: io vectors array with data to transfer + \param sglist_count: count of entries in io vector array + \param transfer_len: overall length of data to be transferred + \param dir: direction of data transfer + \param ccbio: CCB_SCSIIO struct for original SCSI command + \param cb: callback to handle of final stage of command performing (autosense \ + request etc.) + + transfer procedure for bulk-only protocol. Performs SCSI command on USB device + [2] +*/ +void +bulk_only_transfer(usb_device_info *udi, + uint8 *cmd, + uint8 cmdlen, + //sg_buffer *sgb, + iovec *sg_data, + int32 sg_count, + int32 transfer_len, + EDirection dir, + CCB_SCSIIO *ccbio, + ud_transfer_callback cb) +{ + status_t status = B_OK; + status_t command_status = B_OK; + int32 residue = transfer_len; + usb_mass_CSW csw = {0}; + /* initialize and fill in Command Block Wrapper */ + usb_mass_CBW cbw = { + .signature = CBW_SIGNATURE, + .tag = atomic_add(&udi->tag, 1), + .data_transfer_len = transfer_len, + .flags = (dir == eDirIn) ? CBW_FLAGS_IN : CBW_FLAGS_OUT, + .lun = ccbio->cam_ch.cam_target_lun & 0xf, + .cdb_len = cmdlen, + }; + memcpy(cbw.CDB, cmd, cbw.cdb_len); + do{ + trace_CBW(udi, &cbw); + /* send CBW to device */ + status = queue_bulk(udi, &cbw, CBW_LENGTH, false); + if(status != B_OK || udi->status != B_OK){ + PTRACE_ALWAYS(udi, "bulk_only_transfer: queue_bulk failed:" + "status:%08x usb status:%08x\n", status, udi->status); + (*udi->protocol_m->reset)(udi); + command_status = B_CMD_WIRE_FAILED; + break; + } + /* perform data transfer if required */ + if(transfer_len != 0x0){ + status = process_data_io(udi, sg_data, sg_count, dir); + if(status != B_OK && status != B_DEV_STALLED){ + command_status = B_CMD_WIRE_FAILED; + break; + } + } + /* get status of command */ + status = read_status(udi, &csw, transfer_len); + if(B_OK != status){ + command_status = B_CMD_WIRE_FAILED; + break; + } + residue = csw.data_residue; + if(csw.status == CSW_STATUS_FAILED){ + command_status = B_CMD_FAILED; + }else{ + command_status = B_OK; + } + }while(false); + /* finalize transfer */ + cb(udi, ccbio, residue, command_status); +} + +protocol_module_info bulk_only_protocol_m = { + {0, 0, 0}, /* this is not a real kernel module - just interface */ + bulk_only_initialize, + bulk_only_reset, + bulk_only_transfer, +}; diff --git a/src/add-ons/kernel/busses/scsi/usb/proto_bulk.h b/src/add-ons/kernel/busses/scsi/usb/proto_bulk.h new file mode 100644 index 0000000000..9d2588462f --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/proto_bulk.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/** bulk-only protocol "standard" procedures */ + + +#ifndef _PROTO_BULK_H_ + #define _PROTO_BULK_H_ + +#ifndef _PROTO_MODULE_H_ +#include "proto_module.h" +#endif /* _PROTO_MODULE_H_ */ + +extern protocol_module_info bulk_only_protocol_m; + +#endif /*_PROTO_BULK_H_*/ diff --git a/src/add-ons/kernel/busses/scsi/usb/proto_cbi.c b/src/add-ons/kernel/busses/scsi/usb/proto_cbi.c new file mode 100644 index 0000000000..6ffaa6de57 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/proto_cbi.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/* References: + * USB Mass Storage Class specifications: + * http://www.usb.org/developers/data/devclass/usbmassover_11.pdf + * http://www.usb.org/developers/data/devclass/usbmass-ufi10.pdf + * http://www.usb.org/developers/data/devclass/usbmass-cbi10.pdf + */ + +#include + +#include "usb_scsi.h" + +#include "device_info.h" + +#include "proto_module.h" +#include "proto_common.h" +#include "proto_cbi.h" + +#include "usb_defs.h" + +#define USB_REQ_CBI_ADSC 0x00 + + +typedef struct _usb_mass_CBI_CB{ + uint8 op; + uint8 op2; + uint8 padding[14]; +} usb_mass_CBI_CB; + +#define CDB_LEN 16 +#define CDB_RESET_LEN 12 + +//typedef uint8 usb_mass_CDB[CDB_LEN]; + +typedef union _usb_mass_CBI_IDB{ + struct { + uint8 type; + uint8 value; + } common; + struct { + uint8 asc; + uint8 ascq; + } ufi; +} usb_mass_CBI_IDB; + +#define CBI_IDB_TYPE_CCI 0x00 +#define CBI_IDB_VALUE_PASS 0x00 +#define CBI_IDB_VALUE_FAIL 0x01 +#define CBI_IDB_VALUE_PHASE 0x02 +#define CBI_IDB_VALUE_PERSISTENT 0x03 +#define CBI_IDB_VALUE_STATUS_MASK 0x03 + +/** returns size of private protocol buffer */ +//int cbi_buffer_length(){ return sizeof(usb_mass_CBI_CB) + sizeof(usb_mass_CBI_IDB); } +/** casts private protocol buffer to CBI_IDB */ +/*#define IDB_BUFFER(__buff)\ + ((usb_mass_CBI_IDB*)(((uint8*)__buff) + sizeof(usb_mass_CBI_CB))) +*/ +/** casts private protocol buffer to CBI_CB */ +/*#define CB_BUFFER(__buff)\ + ((usb_mass_CBI_CB*)(__buff)) +*/ +void trace_CDB(usb_device_info *udi, const usb_mass_CBI_CB *cb, int len) +{ + PTRACE(udi, "CB:{op:0x%02x; op2:0x%02x;}\n", cb->op, cb->op2); + udi->trace_bytes(" padding:", cb->padding, len - 2); +} + +static status_t +send_request_adsc(usb_device_info *udi, + void *cb, + int length) +{ + status_t status = B_ERROR; + size_t len = 0; + trace_CDB(udi, cb, length); + status = (*udi->usb_m->send_request)(udi->device, + USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, + USB_REQ_CBI_ADSC, 0, + udi->interface, length, + cb, &len); + return status; +} + +static status_t +request_interrupt(usb_device_info *udi, + usb_mass_CBI_IDB *idb) +{ + status_t status = B_ERROR; + status = (*udi->usb_m->queue_interrupt)(udi->pipe_intr, idb, + sizeof(usb_mass_CBI_IDB), bulk_callback, udi); + if(status != B_OK){ + PTRACE(udi, "request_interrupt:failed:%08x\n", status); + } else { + status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, udi->trans_timeout/*LOCK_TIMEOUT*/); + if(status != B_OK){ + PTRACE(udi, "request_interrupt:acquire_sem_etc failed:%08x\n", status); + (*udi->usb_m->cancel_queued_transfers)(udi->pipe_intr); + } + } + udi->trace_bytes("Intr status:", (uint8*)idb, sizeof(usb_mass_CBI_IDB)); + return status; +} + +static status_t +parse_status(usb_device_info *udi, + usb_mass_CBI_IDB *idb) +{ + status_t command_status = B_OK; + if(CMDSET(udi->properties) == CMDSET_UFI){ + if(idb->ufi.asc == 0 && idb->ufi.ascq == 0){ + command_status = B_OK; + }else{ + command_status = B_CMD_FAILED; + } + } else { + if(idb->common.type == CBI_IDB_TYPE_CCI){ + switch(idb->common.value & CBI_IDB_VALUE_STATUS_MASK){ + case CBI_IDB_VALUE_PASS: + command_status = B_OK; + break; + case CBI_IDB_VALUE_FAIL: + case CBI_IDB_VALUE_PERSISTENT: + command_status = B_CMD_FAILED; + break; + case CBI_IDB_VALUE_PHASE: + default: + command_status = B_CMD_WIRE_FAILED; + break; + } + } /* else ?? */ + } + return command_status; +} + +/*================= "standard" protocol procedures ==============================*/ + +/** + \fn: + \param udi: ??? + \return:?? + + ?? +*/ +status_t +cbi_reset(usb_device_info *udi) +{ + status_t status = B_ERROR; + //usb_mass_CBI_CB *cb = CB_BUFFER(udi->proto_buf); + //usb_mass_CDB cdb = {0x1d, 0x04, 0x00}; + //memset(cdb + 2, 0xff, CDB_RESET_LEN - 2); + usb_mass_CBI_CB cb = { + .op = 0x1D, + .op2 = 0x04, + }; + memset(cb.padding , 0xff, sizeof(cb.padding)); + status = send_request_adsc(udi, &cb, CDB_RESET_LEN); + if(status != B_OK) + PTRACE_ALWAYS(udi, "command_block_reset: reset request failed: %08x\n", status); + + if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_in, + USB_FEATURE_ENDPOINT_HALT))) + PTRACE_ALWAYS(udi, "command_block_reset: clear_feature on pipe_in failed: %08x\n", status); + + if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_out, + USB_FEATURE_ENDPOINT_HALT))) + PTRACE_ALWAYS(udi, "command_block_reset: clear_feature on pipe_out failed: %08x\n", status); + PTRACE(udi, "command_block_reset:%08x\n", status); + + return status; +} + +/** + \fn: +*/ +status_t +cbi_initialize(usb_device_info *udi) +{ + status_t status = B_OK; + udi->max_lun = 0; + return status; +} + +/** + \fn:bulk_only_transfer + \param udi: ??? + \param cmd: ??? + \param cmdlen: ??? + \return:??? + + ??? +*/ +void +cbi_transfer(usb_device_info *udi, + uint8 *cmd, + uint8 cmdlen, + //sg_buffer *sgb, + iovec *sg_data, + int32 sg_count, + int32 transfer_len, + EDirection dir, + CCB_SCSIIO *ccbio, + ud_transfer_callback cb) +{ + status_t status = B_OK; + status_t command_status = B_OK; + int32 residue = transfer_len; + usb_mass_CBI_IDB idb = {{0}}; + do{ + status = send_request_adsc(udi, cmd, cmdlen); + if(status != B_OK){ + PTRACE(udi, "cbi_transfer:send command block failed: %08x\n", status); + if(status == B_DEV_STALLED){ + command_status = B_CMD_FAILED; + } else { + command_status = B_CMD_WIRE_FAILED; + (*udi->protocol_m->reset)(udi); + } + break; + } + if(transfer_len != 0){ + status = process_data_io(udi, sg_data, sg_count, dir); + if(status != B_OK){ + command_status = B_CMD_WIRE_FAILED; + break; + } + } + + if(PROTO(udi->properties) == PROTO_CBI){ + status = request_interrupt(udi, &idb); + PTRACE(udi, "cbi_transfer:request interrupt: %08x(%08x)\n", status, udi->status); + if(status != B_OK){ + command_status = B_CMD_WIRE_FAILED; + break; + } + if(udi->status == B_DEV_STALLED){ + } + command_status = parse_status(udi, &idb); + } else { /* PROP_CB ???*/ + command_status = B_CMD_UNKNOWN; + } + residue = 0; /* DEBUG!!!!!!!!!*/ + }while(false); + cb(udi, ccbio, residue, command_status); +} + +protocol_module_info cbi_protocol_m = { + {0, 0, 0}, /* this is not a real kernel module - just interface */ + cbi_initialize, + cbi_reset, + cbi_transfer, +}; diff --git a/src/add-ons/kernel/busses/scsi/usb/proto_cbi.h b/src/add-ons/kernel/busses/scsi/usb/proto_cbi.h new file mode 100644 index 0000000000..3121f923c1 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/proto_cbi.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +#ifndef _PROTO_CBI_H_ + #define _PROTO_CBI_H_ + +#ifndef _PROTO_MODULE_H_ +#include "proto_module.h" +#endif /* _PROTO_MODULE_H_ */ + +extern protocol_module_info cbi_protocol_m; + +#endif /*_PROTO_CBI_H_*/ diff --git a/src/add-ons/kernel/busses/scsi/usb/proto_common.c b/src/add-ons/kernel/busses/scsi/usb/proto_common.c new file mode 100644 index 0000000000..9c4e98836a --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/proto_common.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +#include + +#include "usb_scsi.h" + +#include "device_info.h" +#include "proto_common.h" +#include "tracing.h" +#include "usb_defs.h" +#include "scsi_commands.h" + +/** + \fn:bulk_callback + \param cookie:??? + \param status:??? + \param data:??? + \param actual_len:??? + \return:??? + + ??? +*/ +void bulk_callback(void *cookie, + uint32 status, + void *data, + uint32 actual_len) +{ + TRACE_BULK_CALLBACK(status, actual_len); + if(cookie){ + usb_device_info *udi = (usb_device_info *)cookie; + udi->status = status; + udi->data = data; + udi->actual_len = actual_len; + if(udi->status != B_CANCELED) + release_sem(udi->trans_sem); + } +} + +/** + \fn:exec_io + \param udi: ??? + \return:??? + + ??? +*/ +status_t process_data_io(usb_device_info *udi, + //sg_buffer *sgb, + iovec *sg_data, int32 sg_count, + EDirection dir) +{ + status_t status = B_OK; + usb_pipe pipe = (dir == eDirIn) ? udi->pipe_in : udi->pipe_out; +// TRACE_DATA_IO_SG(data_sg, sglist_count); + status = (*udi->usb_m->queue_bulk_v)(pipe, sg_data, sg_count, bulk_callback, udi); + if(status == B_OK){ + status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, udi->trans_timeout/*LOCK_TIMEOUT*/); + if(status == B_OK){ + status = udi->status; + if(udi->status == B_DEV_STALLED){ + status_t st=(*udi->usb_m->clear_feature)(pipe, USB_FEATURE_ENDPOINT_HALT); + TRACE_ALWAYS("clear_on_STALL:%08x\n",st); + } + }else{ + TRACE_ALWAYS("process_data_io:acquire_sem failed:%08x\n", status); + (*udi->usb_m->cancel_queued_transfers)(pipe); + } + } else { + TRACE_ALWAYS("process_data_io:queue_bulk_v failed:%08x\n", status); + } + TRACE_DATA_IO("process_data_io:processed:%d;status:%08x\n", udi->actual_len, status); + return status; +} + +void transfer_callback(struct _usb_device_info *udi, + CCB_SCSIIO *ccbio, + int32 residue, + status_t status) +{ + ccbio->cam_resid = residue; + switch(status){ + case B_OK: + ccbio->cam_ch.cam_status = CAM_REQ_CMP; + break; + case B_CMD_FAILED: + case B_CMD_UNKNOWN:{ + size_t sense_data_len = (0 != ccbio->cam_sense_len) ? + ccbio->cam_sense_len : SSD_MIN_SIZE; + uchar *sense_data_ptr = (NULL != ccbio->cam_sense_ptr) ? + ccbio->cam_sense_ptr : (uchar*)&udi->autosense_data; + uint8 lun = ((ccbio->cam_ch.cam_target_lun) << CMD_LUN_SHIFT) & CMD_LUN; + scsi_cmd_generic_6 cmd = { REQUEST_SENSE, {lun, 0}, sense_data_len, 0}; + /* transform command as required by protocol */ + uint8 *rcmd = udi->scsi_command_buf; + uint8 rcmdlen = sizeof(udi->scsi_command_buf); + iovec sense_sg = { sense_data_ptr, sense_data_len }; + TRACE("transfer_callback:requesting sense information " + "due status:%08x\n", status); + memset(&udi->autosense_data, 0, SSD_FULL_SIZE); /* just to be sure */ + if(B_OK != (*udi->transform_m->transform)(udi, (uint8 *)&cmd, sizeof(cmd), &rcmd, &rcmdlen)){ + TRACE_ALWAYS("transfer_callback: REQUEST SENSE command transform failed\n"); + ccbio->cam_ch.cam_status = CAM_IDE; //????????? + break; + } + /* transfer command to device. SCSI status will be handled in callback */ + (*udi->protocol_m->transfer)(udi, rcmd, rcmdlen, &sense_sg, 1, sense_data_len, + eDirIn, ccbio, sense_callback); + } + break; + case B_CMD_WIRE_FAILED: + ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR; + break; + default: + TRACE_ALWAYS("transfer_callback:unknown status:%08x\n", status); + ccbio->cam_ch.cam_status = CAM_IDE; + break; + } +} + +void sense_callback(struct _usb_device_info *udi, + CCB_SCSIIO *ccbio, + int32 residue, + status_t status) +{ + ccbio->cam_sense_resid = residue; + switch(status){ + case B_CMD_UNKNOWN: + case B_CMD_FAILED: + case B_OK:{ + bool b_own_data = (ccbio->cam_sense_ptr == NULL); + scsi_sense_data *sense_data = b_own_data ? + &udi->autosense_data : (scsi_sense_data *)ccbio->cam_sense_ptr; + int data_len = (ccbio->cam_sense_len != 0) ? ccbio->cam_sense_len : SSD_MIN_SIZE; + TRACE_SENSE_DATA((uint8*)sense_data, data_len); + if((sense_data->flags & SSD_KEY) == SSD_KEY_NO_SENSE){ + /* no problems. normal case for CB handling */ + TRACE("sense_callback: key OK\n"); + ccbio->cam_ch.cam_status = CAM_REQ_CMP; + } else { + if(!b_own_data){ /* we have used CCBIO provided buffer for sense data */ + TRACE("sense_callback:sense info OK????:%08x \n", sense_data); + ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR | CAM_AUTOSNS_VALID; + ccbio->cam_scsi_status = SCSI_STATUS_CHECK_CONDITION; + } else { + /*TODO: ?????????????????????????????????????? */ + ccbio->cam_ch.cam_status = CAM_REQ_CMP; + // ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR /*| CAM_AUTOSNS_VALID*/; + // ccbio->cam_scsi_status = SCSI_STATUS_CHECK_CONDITION; + TRACE("sense_callback: sense still not handled...\n"); + } + } + } + break; + default: + TRACE_ALWAYS("sense_callback:unknown status:%08x\n", status); + case B_CMD_WIRE_FAILED: + ccbio->cam_ch.cam_status = CAM_AUTOSENSE_FAIL; + break; + } +} + diff --git a/src/add-ons/kernel/busses/scsi/usb/proto_common.h b/src/add-ons/kernel/busses/scsi/usb/proto_common.h new file mode 100644 index 0000000000..f1ea0f2d2e --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/proto_common.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ +#ifndef _PROTO_COMMON_H_ + #define _PROTO_COMMON_H_ + +#ifndef _DEVICE_INFO_H_ + #include "device_info.h" +#endif /* _DEVICE_INFO_H_ */ + +void bulk_callback(void *cookie, + uint32 status, + void *data, + uint32 actual_len); + +status_t process_data_io(usb_device_info *udi, iovec *sg_data, int32 sg_count/*sg_buffer *sgb*/, EDirection dir); + +void transfer_callback(usb_device_info *udi, + CCB_SCSIIO *ccbio, + int32 residue, + status_t status); +void sense_callback(usb_device_info *udi, + CCB_SCSIIO *ccbio, + int32 residue, + status_t status); +#endif /*_PROTO_COMMON_H_*/ diff --git a/src/add-ons/kernel/busses/scsi/usb/proto_module.h b/src/add-ons/kernel/busses/scsi/usb/proto_module.h new file mode 100644 index 0000000000..6cc87d2981 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/proto_module.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ +#ifndef _PROTO_MODULE_H_ + #define _PROTO_MODULE_H_ + +#ifndef _MODULE_H + #include +#endif /*_MODULE_H*/ + +/*#ifndef _SG_BUFFER_H_ + #include "sg_buffer.h" +#endif / *_SG_BUFFER_H_*/ + +enum { + /* B_OK */ /* JFYI:command is OK */ + B_CMD_FAILED = B_ERRORS_END + 1, /* command failed */ + B_CMD_WIRE_FAILED, /* device problems */ + B_CMD_UNKNOWN, /* command state unknown */ +}; + +typedef enum{ + eDirNone = 0, + eDirIn, + eDirOut, +} EDirection; + +struct _usb_device_info; /* forward, we can be included from device_info.h */ + +typedef void (*ud_transfer_callback)(struct _usb_device_info *udi, + CCB_SCSIIO *ccbio, + int32 residue, + status_t status); + +typedef struct { + module_info module; + + status_t (*init)(struct _usb_device_info *udi); + status_t (*reset)(struct _usb_device_info *udi); + void (*transfer)(struct _usb_device_info *udi, + uint8 *cmd, uint8 cmdlen, + //sg_buffer *sgb, + iovec *sg_data, + int32 sg_count, + int32 transfer_len, + EDirection dir, + CCB_SCSIIO *ccbio, + ud_transfer_callback cb); +} protocol_module_info; + + +typedef struct { + module_info module; + + status_t (*transform)(struct _usb_device_info *udi, + uint8 *cmd, uint8 len, + uint8 **rcmd, uint8 *rlen); +} transform_module_info; + +#define MODULE_PREFIX "generic/usb_scsi_extensions/" +#define PROTOCOL_SUFFIX "/protocol/v1" +#define TRANSFORM_SUFFIX "/transform/v1" +#define PROTOCOL_MODULE_MASK MODULE_PREFIX"%s"PROTOCOL_SUFFIX +#define TRANSFORM_MODULE_MASK MODULE_PREFIX"%s"TRANSFORM_SUFFIX + +/** + \define:_TRACE_ALWAYS + trace always - used mainly for error messages +*/ +#define PTRACE_ALWAYS(__udi, __x...) \ + { /*if(__udi->b_trace)*/ __udi->trace(true, __x); } +/** + \define:TRACE + trace only if logging is activated +*/ +#define PTRACE(__udi, __x...) \ + { if(__udi->b_trace) __udi->trace(false, __x); } + +#endif /* _PROTO_MODULE_H_ */ diff --git a/src/add-ons/kernel/busses/scsi/usb/scsi_commands.h b/src/add-ons/kernel/busses/scsi/usb/scsi_commands.h new file mode 100644 index 0000000000..ecc3e2528d --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/scsi_commands.h @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/** definitions for SCSI commands, structures etc. */ + +#ifndef _SCSI_COMMANDS_H_ + #define _SCSI_COMMANDS_H_ + +/* References: + * http://www.t10.org/ftp/t10/drafts/rbc/rbc-r10a.pdf + * http://www.t10.org/ftp/t10/drafts/rbc/rbc-a101.pdf + * http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf + * http://www.t10.org/ftp/t10/drafts/cam/cam-r12b.pdf + * http://www.qic.org/html/standards/15x.x/qic157d.pdf + * + * http://www.usb.org/developers/data/devclass/usbmass-ufi10.pdf + */ + +#define CAM_DIR_MASK (CAM_DIR_IN | CAM_DIR_OUT | CAM_DIR_NONE ) + +/* SCSI status defines */ +#define SCSI_STATUS_OK 0x00 +#define SCSI_STATUS_CHECK_CONDITION 0x02 + +/* SCSI command opcodes */ +#define READ_6 0x08 +#define WRITE_6 0x0a +#define READ_10 0x28 +#define WRITE_10 0x2a +#define MODE_SELECT_6 0x15 +#define MODE_SENSE_6 0x1a +#define MODE_SELECT_10 0x55 +#define MODE_SENSE_10 0x5a +#define READ_CAPACITY 0x25 +#define TEST_UNIT_READY 0x00 +#define START_STOP_UNIT 0x1b + +/* come from UFI specs */ +#define FORMAT_UNIT 0x04 +#define INQUIRY 0x12 +/*#define START_STOP_UNIT 0x1b +#define MODE_SELECT 0x55 +#define MODE_SENSE 0x5a */ +#define PREVENT_ALLOW_MEDIA_REMOVAL 0x1e +#define READ_10 0x28 +#define READ_12 0xa8 +/*#define READ_CAPACITY 0x25*/ +#define READ_FORMAT_CAPACITY 0x23 +#define REQUEST_SENSE 0x03 +#define REZERO_UNIT 0x01 +#define SEEK_10 0x2b +#define SEND_DIAGNOSTICS 0x1d +/*#define TEST_UNIT_READY 0x00*/ +#define VERIFY 0x2f +#define WRITE_10 0x2a +#define WRITE_12 0xaa +#define WRITE_AND_VERIFY 0x2e +/* end of UFI commands*/ + +/* come from ATAPI specs*/ +/*#define FORMAT_UNIT 0x04 +#define INQUIRY 0x12 +#define MODE_SELECT 0x55 +#define MODE_SENSE 0x5a +#define PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define READ_10 0x28 +#define READ_12 0xa8 +#define READ_CAPACITY 0x25 +#define READ_FORMAT_CAPACITIES 0x23 +#define REQUEST_SENSE 0x03 +#define SEEK 0x2b +#define START_STOP_UNIT 0x1b +#define TEST_UNIT_READY 0x00 +#define VERIFY 0x2f +#define WRITE_10 0x2a +#define WRITE_12 0xaa +#define WRITE_AND_VEIRIFY 0x2e */ +#define PAUSE_RESUME 0x4b +#define PLAY_AUDIO 0x45 +#define PLAY_AUDIO_MSF 0x47 +#define REWIND 0x01 +#define PLAY_AUDIO_TRACK 0x48 + +/* end of ATAPI commands*/ + +/* come from MMC2 specs */ +#define READ_BUFFER 0x3c +#define READ_SUBCHANNEL 0x42 +#define READ_TOC 0x43 +#define READ_HEADER 0x44 +#define READ_DISK_INFO 0x51 +#define READ_TRACK_INFO 0x52 +#define SEND_OPC 0x54 +#define READ_MASTER_CUE 0x59 +#define CLOSE_TR_SESSION 0x5b +#define READ_BUFFER_CAP 0x5c +#define SEND_CUE_SHEET 0x5d +#define BLANK 0xa1 +#define EXCHANGE_MEDIUM 0xa6 +#define READ_DVD_STRUCTURE 0xad +#define DVD_REPORT_KEY 0xa4 +#define DVD_SEND_KEY 0xa3 +#define SET_CD_SPEED 0xbb +#define GET_CONFIGURATION 0x46 +/* end of MMC2 specs */ + +/* come from RBC specs */ +/*#define FORMAT_UNIT 0x04 +#define INQUIRY 0x12 +#define MODE_SELECT_6 0x15 +#define MODE_SENSE_6 0x1a*/ +#define PERSISTENT_RESERVE_IN 0x5e +#define PERSISTENT_RESERVE_OUT 0x5f +/*#define PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define READ_10 0x28 +#define READ_CAPACITY 0x25*/ +#define RELEASE_6 0x17 +/*#define REQUEST_SENSE 0x03*/ +#define RESERVE_6 0x16 +/*#define START_STOP_UNIT 0x1b*/ +#define SYNCHRONIZE_CACHE 0x35 +/*#define TEST_UNIT_READY 0x00 +#define VERIFY_10 0x2f +#define WRITE_10 0x2a*/ +#define WRITE_BUFFER 0x3b +/* end of RBC commands */ + +/* come from QIC-157 specvs */ +#define ERASE 0x19 +/*#define INQUIRY 0x12*/ +#define LOAD_UNLOAD 0x1b +#define LOCATE 0x2b +#define LOG_SELECT 0x4c +#define LOG_SENSE 0x4d +/*#define MODE_SELECT 0x15 +#define MODE_SENSE 0x1a +#define READ 0x08*/ +#define READ_POSITION 0x34 +/*#define REQUEST_SENSE 0x03*/ +#define REWIND 0x01 +#define SPACE 0x11 +/*#define TEST_UNIT_READY 0x00 +#define WRITE 0x0a*/ +#define WRITE_FILEMARK 0x10 +/* end of QIC-157 */ + +/* SCSI commands layout*/ +/* generic commands layout*/ +typedef struct{ + uint8 opcode; + uint8 bytes[11]; +}scsi_cmd_generic; +/* six-bytes command*/ +typedef struct{ + uint8 opcode; + uint8 addr[3]; +#define CMD_GEN_6_ADDR 0x1f /* mask used for addr field*/ +#define CMD_LUN 0xE0 /* mask used for LUN */ +#define CMD_LUN_SHIFT 0x05 /* shift for LUN */ + uint8 len; + uint8 ctrl; +}scsi_cmd_generic_6; +/* ten-bytes command*/ +typedef struct{ + uint8 opcode; + uint8 byte2; + uint8 addr[4]; + uint8 reserved; + uint8 len[2]; + uint8 ctrl; +}scsi_cmd_generic_10; +/* twelve-bytes command*/ +typedef struct{ + uint8 opcode; + uint8 byte2; + uint8 addr[4]; + uint8 len[4]; + uint8 reserved; + uint8 ctrl; +}scsi_cmd_generic_12; +/* READ_6 / WRITE_6 */ +typedef scsi_cmd_generic_6 scsi_cmd_rw_6; +/* READ_10 / WRITE_10 */ +typedef struct{ + uint8 opcode; + uint8 byte2; +#define CMD_RW_10_RELADDR 0x01 +#define CMD_RW_10_FUA 0x08 +#define CMD_RW_10_DPO 0x10 + uint8 addr[4]; + uint8 reserved; + uint8 len[2]; + uint8 ctrl; +}scsi_cmd_rw_10; +/* MODE_SELECT_6 */ +typedef struct{ + uint8 opcode; + uint8 byte2; +#define CMD_MSEL_6_SP 0x01 +#define CMD_MSEL_6_PF 0x10 + uint8 reserved[2]; + uint8 len; + uint8 ctrl; +}scsi_cmd_mode_select_6; +/* MODE_SELECT_10 */ +typedef struct{ + uint8 opcode; + uint8 byte2; +#define CMD_MSEL_10_SP 0x01 +#define CMD_MSEL_10_PF 0x10 + uint8 reserved[5]; + uint8 len[2]; + uint8 ctrl; +}scsi_cmd_mode_select_10; +/* MODE_SENSE_6 */ +typedef struct{ + uint8 opcode; + uint8 byte2; +#define CMD_MSENSE_6_DBD 0x08 + uint8 byte3; +#define CMD_MSENSE_6_PC 0x0c + uint8 reserved; + uint8 len; + uint8 ctrl; +}scsi_cmd_mode_sense_6; +typedef struct{ + uint8 mode_data_len; + uint8 medium_type; + uint8 device_spec_params; + uint8 block_descr_len; +}scsi_mode_param_header_6; +/* MODE_SENSE_10 */ +typedef struct{ + uint8 opcode; + uint8 byte2; +#define CMD_MSENSE_10_DBD 0x08 + uint8 byte3; +#define CMD_MSENSE_10_PC 0x0c + uint8 reserved[4]; + uint8 len[2]; + uint8 ctrl; +}scsi_cmd_mode_sense_10; +typedef struct{ + uint8 mode_data_len[2]; + uint8 medium_type; + uint8 device_spec_params; + uint8 reserved1; + uint8 reserved2; + uint8 block_descr_len[2]; +}scsi_mode_param_header_10; +/* TEST_UNIT_READY */ +typedef struct{ + uint8 opcode; + uint8 byte2; + uint8 reserved[3]; + uint8 ctrl; +}scsi_cmd_test_unit_ready; +/* START_STOP_UNIT */ +typedef struct{ + uint8 opcode; + uint8 byte2; +#define CMD_SSU_IMMED 0x01 + uint8 reserved[2]; + uint8 start_loej; +#define CMD_SSU_LOEJ 0x02 +#define CMD_SSU_START 0x01 + uint8 ctrl; +}scsi_cmd_start_stop_unit; + +/* SCSI REQUEST SENSE data. See 8.2.14*/ +typedef struct _scsi_sense_data{ + uint8 error_code; +#define SSD_ERRCODE 0x7F +#define SSD_CURRENT_ERROR 0x70 +#define SSD_DEFERRED_ERROR 0x71 +#define SSD_ERRCODE_VALID 0x80 + uint8 segment; + uint8 flags; +#define SSD_KEY 0x0F +#define SSD_KEY_NO_SENSE 0x00 +#define SSD_KEY_RECOVERED_ERROR 0x01 +#define SSD_KEY_NOT_READY 0x02 +#define SSD_KEY_MEDIUM_ERROR 0x03 +#define SSD_KEY_HARDWARE_ERROR 0x04 +#define SSD_KEY_ILLEGAL_REQUEST 0x05 +#define SSD_KEY_UNIT_ATTENTION 0x06 +#define SSD_KEY_DATA_PROTECT 0x07 +#define SSD_KEY_BLANK_CHECK 0x08 +#define SSD_KEY_Vendor_Specific 0x09 +#define SSD_KEY_COPY_ABORTED 0x0a +#define SSD_KEY_ABORTED_COMMAND 0x0b +#define SSD_KEY_EQUAL 0x0c +#define SSD_KEY_VOLUME_OVERFLOW 0x0d +#define SSD_KEY_MISCOMPARE 0x0e +#define SSD_KEY_RESERVED 0x0f +#define SSD_ILI 0x20 +#define SSD_EOM 0x40 +#define SSD_FILEMARK 0x80 + uint8 info[4]; + uint8 extra_len; + uint8 cmd_spec_info[4]; + uint8 add_sense_code; + uint8 add_sense_code_qual; + uint8 fru; + uint8 sense_key_spec[3]; +#define SSD_SCS_VALID 0x80 +#define SSD_FIELDPTR_CMD 0x40 +#define SSD_BITPTR_VALID 0x08 +#define SSD_BITPTR_VALUE 0x07 +#define SSD_MIN_SIZE 18 + uint8 extra_bytes[14]; +#define SSD_FULL_SIZE sizeof(struct _scsi_sense_data) +}scsi_sense_data; + +#endif /*_SCSI_COMMANDS_H_*/ diff --git a/src/add-ons/kernel/busses/scsi/usb/settings.c b/src/add-ons/kernel/busses/scsi/usb/settings.c new file mode 100644 index 0000000000..cc013fb485 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/settings.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/** driver settings support implementation */ + +#include "usb_scsi.h" +#include "settings.h" +//#include "proto_common.h" + +#include /* strtoul */ +#include /* strncpy */ +#include +#include "tracing.h" + +#define DEF_DEVS 2 /**< default amount of reserved devices */ +#define S_DEF_DEVS "2" /**< default amount of reserved devices */ +#define DEF_LUNS 4 /**< default amount of reserved LUNs */ +#define S_DEF_LUNS "4" /**< default amount of reserved LUNs */ +/** count of device entries, to be reserved for fake devices */ +int reserved_devices = DEF_DEVS; +/** count of Logical Unit Numbers, to be reserved for fake devices */ +int reserved_luns = DEF_LUNS; + +bool b_reservation_on = true; +bool b_ignore_sysinit2 = false; +/** + support of some kind rudimentary "quick" search. Indexes in + settings_keys array. +*/ +enum SKKeys{ + skkVendor = 0, + skkDevice, +// skkName, +// skkTransport, + skkProtocol, + skkCommandSet, + skkFakeInq, + skk6ByteCmd, + skkTransTU, + skkNoTU, + skkNoGetMaxLUN, + skkNoPreventMedia, + skkUseModeSense10, + skkForceReadOnly, + skkProtoBulk, + skkProtoCB, + skkProtoCBI, +// skkProtoFreecom, + skkCmdSetSCSI, + skkCmdSetUFI, + skkCmdSetATAPI, + skkCmdSetRBC, + skkCmdSetQIC157, + + skkKeysCount, +// skkTransportBase = skkSubClassSCSI, + skkProtoBegin = skkProtoBulk, + skkProtoEnd = skkProtoCBI, + skkCmdSetBegin = skkCmdSetSCSI, + skkCmdSetEnd = skkCmdSetQIC157, +}; +/** + helper struct, used in our "quick" search algorithm +*/ +struct _settings_key{ + union _hash{ + char name[32]; + uint16 key; + }hash; + uint32 property; +}settings_keys[] = { /**< array of keys, used in our settings files */ + {{"vendor" }, 0}, /* MUST BE SYNCHRONISED WITH skk*** indexes!!! */ + {{"device" }, 0}, +// {{"name" }, 0}, +// {{"transport"}, 0}, + {{"protocol"}, 0}, + {{"commandset"}, 0}, + {{"fake_inquiry" }, 0}, + {{"use_rw6_byte_cmd" }, 0}, + {{"trans_test_unit" }, 0}, + {{"no_test_unit" }, 0}, + {{"no_get_max_lun"}, 0}, + {{"no_prevent_media"}, 0}, + {{"use_mode_sense_10"}, 0}, + {{"force_read_only"}, 0}, + {{"BULK" }, PROTO_BULK_ONLY}, + {{"CB" }, PROTO_CB}, + {{"CBI" }, PROTO_CBI}, +// {{"Freecom"}, PROTO_FREECOM}, + {{"SCSI" }, CMDSET_SCSI}, + {{"UFI" }, CMDSET_UFI}, + {{"ATAPI" }, CMDSET_ATAPI}, + {{"RBC" }, CMDSET_RBC}, + {{"QIC157" }, CMDSET_QIC157}, +}; +/** + \define:SK_EQUAL + checks is the __name parameter correspond to value, pointed by __id index + in settings_keys array. The magic of our "quick" search algorithm =-)) +*/ +#define CAST_SK(__name) (*(uint16 *)(__name)) +#define SK_EQUAL(__name, __id) ((CAST_SK(__name) == (settings_keys[__id].hash.key)) && \ + (0 == strcmp(__name, settings_keys[__id].hash.name))) +/** + \fn:load_module_settings + loads driver settings from extarnal settings file through BeOS driver + settings API. Called on initialization of the module +*/ +void load_module_settings() +{ + void *sh = load_driver_settings(MODULE_NAME); + if(sh){ + load_log_settings(sh); + /* devices "reservation". Workaround for plug-n-play device attaching*/ + reserved_devices = strtoul(get_driver_parameter(sh, "reserve_devices", + S_DEF_DEVS, S_DEF_DEVS), NULL, 0); + reserved_luns = strtoul(get_driver_parameter(sh, "reserve_luns", + S_DEF_LUNS, S_DEF_LUNS), NULL, 0); + b_ignore_sysinit2 = get_driver_boolean_parameter(sh, "ignore_sysinit2", + b_ignore_sysinit2, false); + if(reserved_devices > MAX_DEVICES_COUNT) + reserved_devices = MAX_DEVICES_COUNT; + if(reserved_luns > MAX_LUNS_COUNT) + reserved_luns = MAX_LUNS_COUNT; + b_reservation_on = (reserved_devices != 0); + + unload_driver_settings(sh); + } else { + TRACE("settings:load:file '%s' was not found. Using default setting...\n", + MODULE_NAME); + } +} +/** + \fn:strncpy_value + \param to: buffer for copied string + \param dp: driver_parameter, from wich copied string come + \param size: maximal size of copied string + copies a string, containing value[0] of this parameter, from driver_parameter, + pointed by dp, to buffer pointed by to. Semantic of this function is similar + to standard strncpy() one. +*/ +/*static void +strncpy_value(char *to, driver_parameter *dp, size_t size) +{ + to[0] = 0; + if(dp->value_count > 0){ + strncpy(to, dp->values[0], size); + } +}*/ +/** + \fn:parse_transport + \param dp: driver_parameter, containing device transport information + \return: a bitmasked value from PROP_-defined flags for USB subclass and \ + protocol + parse the transport driver_parameter for known USB subclasses, protocols and + compose a bitmasked value from those settings +*/ +static uint32 +parse_transport(driver_parameter *dp, + int skkBase, int skkEnd, + uint32 vendor_prop, char *vendor_prop_name) +{ + uint32 ret = 0; + if(dp->value_count > 0){ + char *value = dp->values[0]; + int skkIdx = skkBase; + for(; skkIdx <= skkEnd; skkIdx++){ + if(SK_EQUAL(value, skkIdx)){ + ret |= settings_keys[skkIdx].property; + break; + } + } /* for(...) enumerate protocol and commandset keys */ + if(skkIdx > skkEnd){ /* not found - assume vendor prop */ + ret |= vendor_prop; + strncpy(vendor_prop_name, value, VENDOR_PROP_NAME_LEN); + } + if(dp->value_count > 1){ + TRACE("settings:parse_transport:accept '%s', ignore extra...\n", value); + } + } + return ret; +} +/** + \fn:lookup_device_info + \param product_id: product id of device to be checked for private settings + \param dp: driver_parameter, containing device information + \param udd: on return contains name,protocol etc. information about device + \return: "true" if private settings for device found - "false" otherwise + looks through device parameter, pointed by dp, obtains the name and other + parameters of private device settings if available +*/ +static bool +lookup_device_info(uint16 product_id, + driver_parameter *dp, + usb_device_settings *uds) +{ + bool b_found = false; + if(dp){ + int i = 0; + for(; i < dp->value_count; i++){ + uint16 id = strtoul(dp->values[0], NULL, 0) & 0xffff; + if(product_id == id){ + int prm = 0; + uds->product_id = product_id; + for(; prm < dp->parameter_count; prm++){ +/* if(SK_EQUAL(dp->parameters[prm].name, skkName)){ + strncpy_value(udd->product_name, &dp->parameters[prm], INQ_PRODUCT_LEN); + } else*/ +/* if(SK_EQUAL(dp->parameters[prm].name, skkTransport)){ + udd->properties |= parse_transport(&dp->parameters[prm]); + } else*/ + if(SK_EQUAL(dp->parameters[prm].name, skkProtocol)){ + uds->properties |= parse_transport(&dp->parameters[prm], + skkProtoBegin, skkProtoEnd, + PROTO_VENDOR, + uds->vendor_protocol); + } else + if(SK_EQUAL(dp->parameters[prm].name, skkCommandSet)){ + uds->properties |= parse_transport(&dp->parameters[prm], + skkCmdSetBegin, skkCmdSetEnd, + CMDSET_VENDOR, + uds->vendor_commandset); + } else + if(SK_EQUAL(dp->parameters[prm].name, skkFakeInq)){ + uds->properties |= FIX_NO_INQUIRY; + } else + if(SK_EQUAL(dp->parameters[prm].name, skk6ByteCmd)){ + uds->properties |= FIX_FORCE_RW_TO_6; + } else + if(SK_EQUAL(dp->parameters[prm].name, skkTransTU)){ + uds->properties |= FIX_TRANS_TEST_UNIT; + } else + if(SK_EQUAL(dp->parameters[prm].name, skkNoTU)){ + uds->properties |= FIX_NO_TEST_UNIT; + } else + if(SK_EQUAL(dp->parameters[prm].name, skkNoPreventMedia)){ + uds->properties |= FIX_NO_PREVENT_MEDIA; + } else + if(SK_EQUAL(dp->parameters[prm].name, skkUseModeSense10)){ + uds->properties |= FIX_FORCE_MS_TO_10; + } else + if(SK_EQUAL(dp->parameters[prm].name, skkForceReadOnly)){ + uds->properties |= FIX_FORCE_READ_ONLY; + } else + if(SK_EQUAL(dp->parameters[prm].name, skkNoGetMaxLUN)){ + uds->properties |= FIX_NO_GETMAXLUN; + } else { + TRACE("settings:device:ignore unknown parameter:%s\n", + dp->parameters[prm].name); + } + } /* for(...) enumerate device parameters */ + b_found = true; + break; + } /* if(product_id == id){ */ + } /*enumerate parameter values (product ids) */ + } /* if(dp) */ + return b_found; +} +/** + \fn:lookup_vendor_info + \param vendor_id: vendor id of device to be checked for private settings + \param product_id: product id of device to be checked for private settings + \param dp: driver_parameter, containing vendor information + \param udd: on return contains name, protocol etc. information about device + \return: "true" if private settings for device found - "false" otherwise + looks through vendor parameter, pointed by dp, obtains the name of vendor and + device information if available +*/ +static bool +lookup_vendor_info(uint16 vendor_id, + uint16 product_id, + driver_parameter *dp, + usb_device_settings *uds) +{ + bool b_found = false; + if(dp && dp->value_count > 0 && dp->values[0]){ + uint16 id = strtoul(dp->values[0], NULL, 0) & 0xffff; + if(vendor_id == id){ + int i = 0; + for( i = 0; i < dp->parameter_count; i++){ + if(!b_found && SK_EQUAL(dp->parameters[i].name, skkDevice)){ + b_found = lookup_device_info(product_id, &dp->parameters[i], uds); + } /*else + if(SK_EQUAL(dp->parameters[i].name, skkName)){ + strncpy_value(udd->vendor_name, &dp->parameters[i], INQ_VENDOR_LEN); + } */else { + TRACE("settings:vendor:ignore unknown parameter:%s\n", + dp->parameters[i].name); + } + } /*for(...) enumerate "vendor" parameters*/ + } /*if(vendor_id == id){*/ + } /* if(dp && ... etc */ + return b_found; +} +/** + \fn:lookup_device_settings + \param vendor_id: vendor id of device to be checked for private settings + \param product_id: product id of device to be checked for private settings + \param udd: on return contains name,protocol etc. information about device + \return: "true" if private settings for device found - "false" otherwise + looks through driver settings file for private device description and load it + if available into struct pointed by udd +*/ +bool lookup_device_settings(const usb_device_descriptor *udd, + usb_device_settings *uds) +{ + bool b_found = false; + if(uds){ + void *sh = load_driver_settings(MODULE_NAME); + if(sh){ + const driver_settings *ds = get_driver_settings(sh); + if(ds){ + int i = 0; + for(i = 0; i < ds->parameter_count; i++){ + if(SK_EQUAL(ds->parameters[i].name, skkVendor)){ + b_found = lookup_vendor_info(udd->vendor_id, + udd->product_id, + &ds->parameters[i], uds); + if(b_found){ + uds->vendor_id = udd->vendor_id; + break; //we've got it - stop enumeration. + } + } + } /*for(...) - enumerate "root" parameters*/ + } /* if(ds) */ + unload_driver_settings(sh); + } /* if(sh) */ + if(b_found){ + //TRACE("settings:loaded settings:'%s(%04x)/%s(%04x)/%08x'\n", + TRACE("settings:loaded settings:'%04x/%04x/%08x'\n", + /*descr->vendor_name,*/ uds->vendor_id, + /*descr->product_name,*/ + uds->product_id, uds->properties); + } + } /* if(descr)*/ + return b_found; +} diff --git a/src/add-ons/kernel/busses/scsi/usb/settings.h b/src/add-ons/kernel/busses/scsi/usb/settings.h new file mode 100644 index 0000000000..10cb13c551 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/settings.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/** driver settings support definitions */ + +#ifndef _USB_SCSI_SETTINGS_H_ + #define _USB_SCSI_SETTINGS_H_ + +void load_module_settings(); + +typedef struct{ + uint16 vendor_id; + uint16 product_id; + uint32 properties; +#define VENDOR_PROP_NAME_LEN 0x08 + char vendor_protocol[VENDOR_PROP_NAME_LEN + 1]; + char vendor_commandset[VENDOR_PROP_NAME_LEN + 1]; +}usb_device_settings; + +bool lookup_device_settings(const usb_device_descriptor *udd, + usb_device_settings *uds); + +extern int reserved_devices; +extern int reserved_luns; +extern bool b_reservation_on; +extern bool b_ignore_sysinit2; + +#endif /*_USB_SCSI_SETTINGS_H_*/ diff --git a/src/add-ons/kernel/busses/scsi/usb/sg_buffer.c b/src/add-ons/kernel/busses/scsi/usb/sg_buffer.c new file mode 100644 index 0000000000..0952192e73 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/sg_buffer.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/** handling SCSI data-buffer (both usual "plain" and scatter/gather ones) */ + +#include + +#include "usb_scsi.h" + +#include +#include "tracing.h" +#include "sg_buffer.h" + +/** + \fn:init_sg_buffer + TODO!!! +*/ +status_t +init_sg_buffer(sg_buffer *sgb, CCB_SCSIIO *ccbio) +{ + status_t status = B_NO_INIT; + if(0 != sgb){ + memset(sgb, 0, sizeof(sg_buffer)); + /* setup scatter/gather if exists in CCBIO*/ + if(ccbio->cam_ch.cam_flags & CAM_SCATTER_VALID) { + sgb->piov = (iovec *) ccbio->cam_data_ptr; + sgb->count = ccbio->cam_sglist_cnt; + } else { + sgb->iov.iov_base = (iovec *) ccbio->cam_data_ptr; + sgb->iov.iov_len = ccbio->cam_dxfer_len; + sgb->piov = &sgb->iov; + sgb->count = 1; + } + status = B_OK; + } else { + TRACE_ALWAYS("init_sg_buffer fatal: not initialized!\n"); + } + return status; +} + +/** + \fn:alloc_sg_buffer + TODO!!! +*/ +status_t +realloc_sg_buffer(sg_buffer *sgb, size_t size) +{ + status_t status = B_NO_INIT; + if(0 != sgb){ + /* NOTE: no check for previously allocations! May be dangerous!*/ + void *ptr = malloc(size); + status = (0 != ptr) ? B_OK : B_NO_MEMORY; + if(B_OK == status) { + memset(ptr, 0, size); + sgb->iov.iov_base = (iovec *)ptr; + sgb->iov.iov_len = size; + sgb->piov = &sgb->iov; + sgb->count = 1; + sgb->b_own = true; + status = B_OK; + } + } else { + TRACE_ALWAYS("realloc_sg_buffer fatal: not initialized!\n"); + } + return status; +} + +status_t +sg_access_byte(sg_buffer *sgb, off_t offset, uchar *byte, bool b_set) +{ + status_t status = B_ERROR; + int i = 0; + for(; i < sgb->count; i++){ + if(offset >= sgb->piov[i].iov_len){ + offset -= sgb->piov[i].iov_len; + } else { + uchar *ptr = (uchar *)sgb->piov[i].iov_base; + if(b_set){ + ptr[offset] = *byte; + }else{ + *byte = ptr[offset]; + } + status = B_OK; + break; + } + } + return status; +} + +status_t +sg_memcpy(sg_buffer *d_sgb, off_t d_offset, + sg_buffer *s_sgb, off_t s_offset, size_t size) +{ + status_t status = B_NO_INIT; + while(0 != d_sgb && 0 != s_sgb){ + uchar *d_ptr = 0; + uchar *s_ptr = 0; + status = B_ERROR; + if(1 == d_sgb->count){ + d_ptr = d_sgb->piov->iov_base + d_offset; + if((d_offset + size) > d_sgb->piov->iov_len){ + TRACE_ALWAYS("sg_memcpy fatal: dest buffer overflow: has:%d req:%d\n", + d_sgb->piov->iov_len, d_offset + size); + break; + } + } + if(1 == s_sgb->count){ + s_ptr = s_sgb->piov->iov_base + s_offset; + if((s_offset + size) > s_sgb->piov->iov_len){ + TRACE_ALWAYS("sg_memcpy fatal: src buffer overflow: has:%d req:%d\n", + s_sgb->piov->iov_len, s_offset + size); + break; + } + } + if(0 != d_ptr && 0 != s_ptr){ + memcpy(d_ptr, s_ptr, size); + } else { + uchar byte = 0; + int i = 0; + for(; i < size; i++){ + status = sg_access_byte(s_sgb, s_offset + i, &byte, false); + if(B_OK == status) + status = sg_access_byte(d_sgb, d_offset + i, &byte, true); + if(B_OK != status){ + TRACE_ALWAYS("sg_memcpy fatal: dest:%d src:%d size:%d/%d\n", + d_offset, s_offset, i, size); + break; + } + } + } + status = B_OK; + break; + } + if(B_NO_INIT == status) + TRACE_ALWAYS("sg_memcpy fatal: not initialized"); + return status; +} + +/** + \fn:free_sg_buffer + TODO!!! +*/ +void +free_sg_buffer(sg_buffer *sgb) +{ + if(0 != sgb && sgb->b_own){ + int i = 0; + for(; i < sgb->count; i++){ + free(sgb->piov[i].iov_base); + } + memset(sgb, 0, sizeof(sg_buffer)); + } +} + +status_t +sg_buffer_len(sg_buffer *sgb, size_t *size) +{ + status_t status = B_NO_INIT; + if(0!=sgb && 0!=size){ + int i = 0; + *size = 0; + for(; i < sgb->count; i++){ + *size += sgb->piov[i].iov_len; + } + status = B_OK; + } else { + TRACE_ALWAYS("sg_buffer_len fatal: not initialized (sgb:%x/size:%x)", sgb, size); + } + return status; +} diff --git a/src/add-ons/kernel/busses/scsi/usb/sg_buffer.h b/src/add-ons/kernel/busses/scsi/usb/sg_buffer.h new file mode 100644 index 0000000000..50c685e8e7 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/sg_buffer.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/** handling SCSI data-buffer (both usual "plain" and scatter/gather ones) */ + +#ifndef _SG_BUFFER_H_ + #define _SG_BUFFER_H_ + +#ifndef _IOVEC_H + #include +#endif/*_IOVEC_H*/ + +/** + \struct:_sg_buffer +*/ +typedef struct _sg_buffer{ + iovec iov; /**< to avoid extra memory allocations */ + iovec *piov; /**< ptr to scatter/gather list, default is equal to &iov */ + int count; /**< count of scatter/gather vector entries */ + bool b_own; /**< was allocated - must be freed */ +} sg_buffer; + +#define member_offset(__type, __member) ((size_t)&(((__type *)0)->__member)) +#define member_size(__type, __member) sizeof(((__type *)0)->__member) + +status_t init_sg_buffer(sg_buffer *sgb, CCB_SCSIIO *ccbio); +status_t realloc_sg_buffer(sg_buffer *sgb, size_t size); +status_t sg_buffer_len(sg_buffer *sgb, size_t *size); +status_t sg_access_byte(sg_buffer *sgb, off_t offset, uchar *byte, bool b_set); +status_t sg_memcpy(sg_buffer *dest_sgb, off_t dest_offset, + sg_buffer *src_sgb, off_t src_offset, size_t size); +void free_sg_buffer(sg_buffer *sgb); + +#endif /*_SG_BUFFER_H_*/ diff --git a/src/add-ons/kernel/busses/scsi/usb/tracing.c b/src/add-ons/kernel/busses/scsi/usb/tracing.c new file mode 100644 index 0000000000..c530dbe412 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/tracing.c @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/** tracing support implementation */ + +#include "usb_scsi.h" +#include "tracing.h" + +#include +#include /* posix file i/o - create, write, close */ +#include +#include +#include + +/** private log path name */ +static const char *private_log_path = "/var/log/"MODULE_NAME".log"; + +static const char *log_port_name = MODULE_NAME"-logging"; + +#ifdef BUILD_LOG_DAEMON + +int main(int argc, char**argv) +{ + if(B_NAME_NOT_FOUND == find_port(log_port_name)){ + bool b_screen = (argc > 1); + port_id pid = create_port(1000, log_port_name); + while(true){ + int32 code; + char buffer[1024 + 1]; + size_t sz = read_port_etc(pid, &code, buffer, 1024, B_TIMEOUT, 1000 * 1000); + if(sz != B_TIMED_OUT){ + if(b_screen){ + buffer[sz] = 0; + printf(buffer); + } else { + FILE *f = fopen(private_log_path, "a"); + fwrite(buffer, sz, 1, f); + fclose(f); + } + } + } + } + return 0; +} + +#else /* BUILD_LOG_DAEMON */ + +/** is activity logging on or off? */ +#if DEBUG +bool b_log = true; +#else +bool b_log = false; +#endif +/** logging in private file */ +bool b_log_file = false; +/** appending logs to previous log sessions */ +bool b_log_append = false; +/** log SCSI commands */ +bool b_log_scsi_cmd = false; +/** log USB bulk callback function activity */ +bool b_log_bulk_cb = false; + +bool b_log_protocol = false; +//bool b_log_CSW = false; +//bool b_log_CDB = false; +bool b_log_data_processing = false; +bool b_log_sense_data = false; +/** log time at wich logging event occured */ +static bool b_log_time = false; +/** log thread id from wich logging performed */ +static bool b_log_thid = false; +/** log thread name from wich logging performed */ +static bool b_log_thname = false; +/** semaphore id used to synchronizing logging requests */ +//static sem_id loglock; +/** log result of READ_CAPACITY command */ +bool b_log_capacity = false; + +/** + \fn: load_log_settings + \param sh: driver_settings handle + called from main driver settings loading procedure to load log-related + parameters +*/ +void +load_log_settings(void *sh) +{ + if(sh){ +#if !DEBUG + b_log = get_driver_boolean_parameter(sh, "debug_output", b_log, true); +#endif + b_log_file = get_driver_boolean_parameter(sh, "debug_output_in_file", + b_log_file, true); + b_log_append = ! get_driver_boolean_parameter(sh, "debug_output_file_rewrite", + !b_log_append, true); + b_log_time = get_driver_boolean_parameter(sh, "debug_trace_time", + b_log_time, false); + b_log_thid = get_driver_boolean_parameter(sh, "debug_trace_threadid", + b_log_thid, false); + b_log_thname = get_driver_boolean_parameter(sh, "debug_trace_thread_name", + b_log_thname, false); + b_log_scsi_cmd = get_driver_boolean_parameter(sh, "debug_trace_commands", + b_log_scsi_cmd, false); + b_log_bulk_cb = get_driver_boolean_parameter(sh, "debug_trace_bulk_callback", + b_log_bulk_cb, false); + b_log_protocol = get_driver_boolean_parameter(sh, "debug_trace_protocol", + b_log_protocol, false); + b_log_data_processing = + get_driver_boolean_parameter(sh, "debug_trace_data_io", + b_log_data_processing, false); + b_log_sense_data = + get_driver_boolean_parameter(sh, "debug_trace_sense_data", + b_log_sense_data, false); + b_log_capacity = get_driver_boolean_parameter(sh, "debug_trace_capacity", + b_log_capacity, false); + if(!b_log_file){ /* some information is already in system log entries */ + b_log_thid = false; + b_log_thname = false; + } + } +} +/** + \fn: create_log + called to [re]create private log file +*/ +void +create_log() +{ + int flags = O_WRONLY | O_CREAT | ((!b_log_append) ? O_TRUNC : 0); + if(b_log_file){ + close(open(private_log_path, flags, 0666)); + } +} + +/** + \fn: usb_scsi_trace + \param b_force: if true - output message ignoring current logging state + \param fmt: format string used in message formatting + \param ...: variable argument used in message formatting + formats and traces messages to current debug output target. +*/ +void +usb_scsi_trace(bool b_force, const char *fmt, ...) +{ + if(b_force || b_log){ + va_list arg_list; + static char *prefix = "\33[35m"MODULE_NAME":\33[0m"; + static char buf[1024]; + char *buf_ptr = buf; + port_id pid = find_port(log_port_name); + bool b_no_port = (pid == B_NAME_NOT_FOUND); + if(!b_log_file || b_no_port){ /* it's not a good idea to add prefix in private file */ + strcpy(buf, prefix); + buf_ptr += strlen(prefix); + } + if(b_log_time){ /* add time of logging this string */ + bigtime_t time = system_time(); + uint32 msec = time / 1000; + uint32 sec = msec / 1000; + sprintf(buf_ptr, "%02ld.%02ld.%03ld:", sec / 60, sec % 60, msec % 1000); + buf_ptr += strlen(buf_ptr); + } + if(b_log_thid){ /* add id of the calling thread */ + thread_id tid = find_thread(0); + thread_info tinfo = {0}; + if(b_log_thname){ /* add name of the calling thread */ + get_thread_info(tid, &tinfo); + } + sprintf(buf_ptr, "['%s':%lx]:", tinfo.name, tid); + buf_ptr += strlen(buf_ptr); + } + va_start(arg_list, fmt); + vsprintf(buf_ptr, fmt, arg_list); + va_end(arg_list); + if(b_log_file && !b_no_port){ /* write in private log file */ + if(B_OK != write_port_etc(pid, 0, buf, strlen(buf), B_TIMEOUT, 0)) + dprintf(buf); + } else /* write in system log*/ + dprintf(buf); + } +} +/** + \fn: trace_CCB_HEADER + \param ccbh: struct to be traced + traces CCB_HEADER struct to current debug output target +*/ +void +usb_scsi_trace_CCB_HEADER(const CCB_HEADER *ccbh) +{ + TRACE("CCB_HEADER:%08x\n" + " phys_addr:%ld\n" + " cam_ccb_len:%d\n" + " cam_func_code:%02x\n" + " cam_status:%02x\n" + " cam_hrsvd0:%02x\n" + " cam_path_id:%02x\n" + " cam_target_id:%02x\n" + " cam_target_lun:%02x\n" + " cam_flags:%08x\n", + ccbh, + ccbh->phys_addr, + ccbh->cam_ccb_len, + ccbh->cam_func_code, + ccbh->cam_status, + ccbh->cam_hrsvd0, + ccbh->cam_path_id, + ccbh->cam_target_id, + ccbh->cam_target_lun, + ccbh->cam_flags); +} +/** + \fn: trace_CCB_SCSIIO + \param ccbio: struct to be traced + traces CCB_SCSIIO struct to current debug output target +*/ +void +usb_scsi_trace_CCB_SCSIIO(const CCB_SCSIIO *ccbio) +{ + TRACE("CCB_SCSIIO:%08x\n", ccbio); + usb_scsi_trace_CCB_HEADER(&ccbio->cam_ch); + TRACE(" cam_pdrv_ptr:%08x\n" + " cam_next_ccb:%08x\n" + " cam_req_map:%08x\n" + " (*cam_cbfcnp):%08x\n" + " cam_data_ptr:%08x\n" + " cam_dxfer_len:%ld\n" + " cam_sense_ptr:%08x\n" + " cam_sense_len:%d\n" + " cam_cdb_len:%d\n" + " cam_sglist_cnt:%d\n" + " cam_sort:%d\n" + " cam_scsi_status:%02x\n" + " cam_sense_resid:%d\n" + " cam_resid:%d\n" + " cam_timeout:%d\n" + " cam_msg_ptr:%08x\n" + " cam_msgb_len:%d\n" + " cam_vu_flags:%04x\n" + " cam_tag_action:%d\n", + ccbio->cam_pdrv_ptr, + ccbio->cam_next_ccb, + ccbio->cam_req_map, + ccbio->cam_cbfcnp, + ccbio->cam_data_ptr, + ccbio->cam_dxfer_len, + ccbio->cam_sense_ptr, + ccbio->cam_sense_len, + ccbio->cam_cdb_len, + ccbio->cam_sglist_cnt, + ccbio->cam_sort, + ccbio->cam_scsi_status, + ccbio->cam_sense_resid, + ccbio->cam_resid, + ccbio->cam_timeout, + ccbio->cam_msg_ptr, + ccbio->cam_msgb_len, + ccbio->cam_vu_flags, + ccbio->cam_tag_action); + + usb_scsi_trace_bytes("CDB_UN:\n", ccbio->cam_cdb_io.cam_cdb_bytes, IOCDBLEN); +} +/** + \fn: usb_scsi_command_trace + \param b_hlight: highlight command and prefix it with spec. charachter + \param cmd: array of bytes to be traced. typically pointer SCSI command buffer + \param cmdlen: size of buffer in cmd parameter + traces SCSI commands into debug output target.can highlight and prefix the + text with special charachter and color for two different types + of commands. +*/ +void +usb_scsi_trace_command(bool b_hlight, const uint8 *cmd, size_t cmdlen) +{ + size_t len = min(cmdlen, 12); /* command length watchdog */ + char hl_mask[] = "\33[%sCMD:\33[0m"; + char prefix[sizeof(hl_mask) + 6]; + if(b_log_file){ /* compose CMD prefix */ + sprintf(prefix, "%sCMD:", b_hlight ? "=>":""); + } else { + sprintf(prefix, hl_mask, b_hlight ? "33m=>":"32m"); + } + usb_scsi_trace_bytes(prefix, cmd, len); /* append command bytes to log */ +} +/** + \fn:usb_scsi_bytes_trace + \param bytes:array of bytes to be traced. + \param bytes_len: size of buffer in bytes parameter + traces buffer bytes one by one into debug output target. +*/ +void +usb_scsi_trace_bytes(const char *prefix, const uint8 *bytes, size_t bytes_len) +{ + size_t len = min(bytes_len, 0x100); /* length watchdog */ + char truncTail[] = "\n"; + char *pbuf = (char *)malloc(len * 3 + sizeof(truncTail) + strlen(prefix) + 1); + if(pbuf){ + size_t i = 0; + char *p = pbuf; + strcpy(p, prefix); + p += strlen(prefix); + for(;i < len; i++){ + sprintf(p, " %02x", bytes[i]); + p += strlen(p); + } + /* user should be informed about truncation too*/ + strcpy(p, (len < bytes_len) ? truncTail : "\n"); + TRACE(pbuf); + free(pbuf); + } else { + TRACE_ALWAYS("usb_scsi_trace_bytes:error allocate " + "memory for tracing %d bytes\n", len); + } +} + +void usb_scsi_trace_sgb(const char *prefix, sg_buffer *sgb) +{ + char sgbHead[] = "SGB:"; + size_t i = 0; + size_t len = strlen(prefix) + strlen(sgbHead) + sgb->count * 9; + char *sgbPrefix = (char*)malloc(len); + if(0 != sgbPrefix){ + sg_buffer sgb_own; + size_t sgb_len = 0; + char *p = sgbPrefix; + strcpy(p, prefix); + p += strlen(p); + strcpy(p, sgbHead); + p += strlen(p); + i = 0; + for(; i < sgb->count; i++){ + sprintf(p, "%lX,", sgb->piov[i].iov_len); + sgb_len += sgb->piov[i].iov_len; + p += strlen(p); + } + if(B_OK == realloc_sg_buffer(&sgb_own, sgb_len)){ + sg_memcpy(&sgb_own, 0, sgb, 0, sgb_len); + /* assume non-fragmented memory */ + usb_scsi_trace_bytes(sgbPrefix, sgb_own.piov->iov_base, sgb_own.piov->iov_len); + free_sg_buffer(&sgb_own); + } else { + TRACE_ALWAYS("usb_scsi_trace_sgb:error allocate sgb for %d bytes\n", sgb_len); + } + } else { + TRACE_ALWAYS("usb_scsi_trace_sgb:error allocate memory for %d bytes\n", len); + } +} + +void usb_scsi_trace_SG(iovec *sg, int count) +{ + char sg_mask[] = "SG:{%s}\n"; + char truncTail[] = ""; + size_t trunc_count = min(count, 0x20); /* length watchdog */ + size_t len = sizeof(sg_mask) + sizeof(truncTail) + trunc_count * 16; + char *pbuf = (char *)malloc(len + 1); + if(pbuf){ + int i = 0; + char *p = pbuf; + for(; i < trunc_count; i++){ + sprintf(p, (!i) ? "%d" : ", %d", sg[i].iov_len); + p += strlen(p); + } + /* user should be informed about truncation too*/ + if(trunc_count < count) + strcpy(p, truncTail); + + TRACE(sg_mask, pbuf); + free(pbuf); + } else { + TRACE_ALWAYS("usb_scsi_trace_SG:error allocate " + "memory for tracing %d SG entries\n", trunc_count); + } +} + +#endif /* BUILD_LOG_DAEMON */ diff --git a/src/add-ons/kernel/busses/scsi/usb/tracing.h b/src/add-ons/kernel/busses/scsi/usb/tracing.h new file mode 100644 index 0000000000..5a1ab6c17d --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/tracing.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/** tracing support definitions */ + +#ifndef _USB_SCSI_TRACING_H_ + #define _USB_SCSI_TRACING_H_ + +#ifndef _SG_BUFFER_H_ + #include "sg_buffer.h" +#endif /*_SG_BUFFER_H_*/ + +void load_log_settings(void *sh); +void create_log(); +void usb_scsi_trace(bool b_force, const char *fmt, ...); + +/* non-switchable tracng functions */ +void usb_scsi_trace_bytes(const char *prefix, const uint8 *bytes, size_t bytes_len); +void usb_scsi_trace_sgb(const char *prefix, sg_buffer *sgb); +void usb_scsi_trace_CCB_HEADER(const CCB_HEADER *ccb); +void usb_scsi_trace_CCB_SCSIIO(const CCB_SCSIIO *ccbio); + +/* ---------------------- Generic tracing --------------------------------------- */ +/** + \define:TRACE_ALWAYS + trace always - used mainly for error messages +*/ +#define TRACE_ALWAYS(x...) \ + usb_scsi_trace(true, x) +/** + \define:TRACE + trace only if logging is activated +*/ +#define TRACE(x...) \ + usb_scsi_trace(false, x) + +/* ---------------------- SCSI commands tracing -------------------------------- */ +extern bool b_log_scsi_cmd; +void usb_scsi_trace_command(bool b_hlight, const uint8 *cmd, size_t cmdlen); +/** + \define:TRACE_SCSI_COMMAND + trace SCSI command +*/ +#define TRACE_SCSI_COMMAND(cmd, cmdlen)\ + { if(b_log_scsi_cmd) usb_scsi_trace_command(false, cmd, cmdlen); } +/** + \define:TRACE_SCSI_COMMAND_HLIGHT + trace SCSI command and prefixes it with special sign. Used for tracing + commands internally converted by this module. +*/ +#define TRACE_SCSI_COMMAND_HLIGHT(cmd, cmdlen)\ + { if(b_log_scsi_cmd) usb_scsi_trace_command(true, cmd, cmdlen); } + +/* ---------------------- USB callback tracing -------------------------------- */ +/** + \define:TRACE_BULK_CALLBACK + trace the bulk_callback procedures data and status flow. +*/ +extern bool b_log_bulk_cb; +#define TRACE_BULK_CALLBACK(stat, len)\ + { if(b_log_bulk_cb) TRACE("B_CB:status:%08x;length:%d\n", stat, len); } + +/* --------------- USB mass storage commands tracing --------------------------- */ +extern bool b_log_protocol; +/* --------------------------- data i/o tracing -------------------------------- */ +extern bool b_log_data_processing; +void usb_scsi_trace_SG(iovec *sg, int count); +/** + \define:TRACE_DATA_IO + trace the information about amount processed data and status of process. +*/ +#define TRACE_DATA_IO(x...)\ + { if(b_log_data_processing) usb_scsi_trace(false, x); } +#define TRACE_DATA_IO_SG(sg, cnt)\ + { if(b_log_data_processing) usb_scsi_trace_SG(sg, cnt); } + +extern bool b_log_sense_data; +/** + \define:TRACE_SENSE_DATA + trace the information REQUEST SENSE data. +*/ +#define TRACE_SENSE_DATA(data, len)\ + { if(b_log_sense_data) usb_scsi_trace_bytes("SENSE:", data, len); } +#define TRACE_MODE_SENSE_DATA(prefix, data, len)\ + { if(b_log_sense_data) usb_scsi_trace_bytes(prefix, data, len); } +#define TRACE_MODE_SENSE_SGB(prefix, data)\ + { if(b_log_sense_data) usb_scsi_trace_sgb(prefix, data); } + +extern bool b_log_capacity; +#define TRACE_CAPACITY(prefix, data)\ + { if(b_log_capacity) usb_scsi_trace_sgb(prefix, data); } + +#endif /*_USB_SCSI_TRACING_H_*/ diff --git a/src/add-ons/kernel/busses/scsi/usb/transform_procs.c b/src/add-ons/kernel/busses/scsi/usb/transform_procs.c new file mode 100644 index 0000000000..f0b8721469 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/transform_procs.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/** SCSI commands transformations support */ + +#include "usb_scsi.h" + +#include "device_info.h" +#include "transform_procs.h" +#include "tracing.h" +#include "scsi_commands.h" +//#include "proto_common.h" +#include "settings.h" + +#define UFI_COMMAND_LEN 12 +#define ATAPI_COMMAND_LEN 12 + +/** + \fn:transform_6_to_10 + \param cmd: SCSI command buffer to be transformed + \param len: length of buffer, pointed by cmd parameter + \param rcmd: a place for buffer pointer with transformed command + \param rlen: a place for length of transformed command + \return: true if transformation was performed + transforms a 6-byte command to 10-byte one if required.Transformed command is + returned in rcmd parameter. In case if no transformation was performed the return + buffer is untouched. +*/ +static bool transform_6_to_10(uint8 *cmd, + uint8 len, + uint8 **rcmd, + uint8 *rlen) +{ + bool transformed = true; + scsi_cmd_generic_6 *from = (scsi_cmd_generic_6 *)cmd; + memset(*rcmd, 0, *rlen); + switch (from->opcode){ + case READ_6: + case WRITE_6:{ + scsi_cmd_rw_10 *to = (scsi_cmd_rw_10 *)(*rcmd); + to->opcode = (from->opcode == READ_6) ? READ_10 : WRITE_10; + memcpy(to->addr + 1, from->addr, 3); + to->byte2 = from->addr[0]; + to->byte2 &= ~CMD_GEN_6_ADDR; + to->addr[1] &= CMD_GEN_6_ADDR; + to->len[1] = from->len; + to->ctrl = from->ctrl; + if(0 == from->len){ /* special case! in 6-byte R/W commands */ + to->len[0] = 1; /* the length 0x00 assume transfering 0x100 blocks! */ + } + }break; + case MODE_SENSE_6: + case MODE_SELECT_6:{ + scsi_cmd_generic_10 *to = (scsi_cmd_generic_10 *)(*rcmd); + if(from->opcode == MODE_SENSE_6){ + to->opcode = MODE_SENSE_10; + ((scsi_cmd_mode_sense_10 *)to)->byte3 = + ((scsi_cmd_mode_sense_6 *)from)->byte3; + }else + to->opcode = MODE_SELECT_10; + to->byte2 = from->addr[0]; + to->len[1] = from->len + 4; /*TODO: hardcoded length*/ + to->ctrl = from->ctrl; + }break; + default:{ /* no transformation needed */ + transformed = false; + }break; + } + return transformed; +} +/** + \fn:transform_cmd_6_to_10 + \param udi: usb_device_info object for wich transformation is requested + \param cmd: SCSI command buffer to be transformed + \param len: length of buffer, pointed by cmd parameter + \param rcmd: a place for buffer pointer with transformed command + \param rlen: a place for length of transformed command + \return: true if transformation was performed + transforms a 6-byte command to 10-byte depending on information provided with + udi object. +*/ +static bool transform_cmd_6_to_10(usb_device_info *udi, + uint8 *cmd, + uint8 len, + uint8 **rcmd, + uint8 *rlen) +{ + bool transformed = true; + scsi_cmd_generic_6 *from = (scsi_cmd_generic_6 *)cmd; + switch (from->opcode){ + case READ_6: + case WRITE_6:{ +// if(!(HAS_FEATURES(udi->descr.properties, PROP_FORCE_TO_6))){ + if(!HAS_FIXES(udi->properties, FIX_FORCE_RW_TO_6)){ + if((transformed = transform_6_to_10(cmd, len, rcmd, rlen)) == true) + *rlen = 10; + }else + transformed = false; + }break; + case MODE_SENSE_6: + case MODE_SELECT_6:{ +// if(HAS_FEATURES(udi->descr.properties, PROP_USE_MODESENSE_10)){ + if(HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)){ + if((transformed = transform_6_to_10(cmd, len, rcmd, rlen)) == true) + *rlen = 10; + }else + transformed = false; + } + } + return transformed; +} +/** + \fn:transform_cmd_test_unit_ready + \param udi: usb_device_info object for wich transformation is requested + \param cmd: SCSI command buffer to be transformed + \param len: length of buffer, pointed by cmd parameter + \param rcmd: a place for buffer pointer with transformed command + \param rlen: a place for length of transformed command + \return: true if transformation was performed + transforms a TEST_UNIT_COMAND SCSI command to START_STOP_UNIT one depending + on properties provided with udi object. +*/ +static bool transform_cmd_test_unit_ready(usb_device_info *udi, + uint8 *cmd, + uint8 len, + uint8 **rcmd, + uint8 *rlen) +{ + bool transformed = false; + if(HAS_FIXES(udi->properties, FIX_TRANS_TEST_UNIT)){ + scsi_cmd_start_stop_unit *command = (scsi_cmd_start_stop_unit *)(*rcmd); + memset(*rcmd, 0, *rlen); + command->opcode = START_STOP_UNIT; + command->start_loej = CMD_SSU_START; + *rlen = 6; + transformed = true; + } + return transformed; +} +/** + \fn:scsi_transform + \param udi: usb_device_info object for wich transformation is requested + \param cmd: SCSI command buffer to be transformed + \param len: length of buffer, pointed by cmd parameter + \param rcmd: a place for buffer pointer with transformed command + \param rlen: a place for length of transformed command + \return: B_OK if transformation was successfull, B_ERROR otherwise + this is the "transformation procedure" for transparent SCSI (0x06) USB subclass.It + performs all SCSI commands transformations required by this protocol. Additionally + it tries to make some workarounds for "brocken" USB devices. If no transformation + was performed resulting command buffer points to original one. +*/ +status_t +scsi_transform(usb_device_info *udi, + uint8 *cmd, + uint8 len, + uint8 **rcmd, + uint8 *rlen) +{ + status_t status = B_OK; + bool transformed = false; + scsi_cmd_generic *command = (scsi_cmd_generic *)cmd; + TRACE_SCSI_COMMAND(cmd, len); + switch(command->opcode){ + case READ_6: + case WRITE_6: + case MODE_SENSE_6: + case MODE_SELECT_6: + transformed = transform_cmd_6_to_10(udi, cmd, len, rcmd, rlen); + break; + case TEST_UNIT_READY: + transformed = transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen); + break; + default: break; + } + if(!transformed){ /* transformation was not required */ + *rcmd = cmd; + *rlen = len; + }else + TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen); + return status; +} +/** + \fn:rbc_transform + \param udi: usb_device_info object for wich transformation is requested + \param cmd: SCSI command buffer to be transformed + \param len: length of buffer, pointed by cmd parameter + \param rcmd: a place for buffer pointer with transformed command + \param rlen: a place for length of transformed command + \return: B_OK if transformation was successfull, B_ERROR otherwise + this is the "transformation procedure" for RBC USB subclass (0x01).It + performs all SCSI commands transformations required by this protocol. Additionally + it tries to make some workarounds for "brocken" USB devices. If no transformation + was performed resulting command buffer points to original one. +*/ +status_t rbc_transform(usb_device_info *udi, + uint8 *cmd, + uint8 len, + uint8 **rcmd, + uint8 *rlen) +{ + status_t status = B_OK; + bool transformed = false; + scsi_cmd_generic *command = (scsi_cmd_generic *)cmd; + TRACE_SCSI_COMMAND(cmd, len); + switch(command->opcode){ + case TEST_UNIT_READY: + transformed = transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen); + break; + case READ_6: + case WRITE_6: /* there are no such command in list of allowed - transform*/ + transformed = transform_cmd_6_to_10(udi, cmd, len, rcmd, rlen); + break; + case FORMAT_UNIT: /* TODO: all following ones are not checked against specs !!!*/ + case INQUIRY: /*TODO: check !!! */ + case MODE_SELECT_6: /*TODO: check !!! */ + case MODE_SENSE_6: /*TODO: check !!! */ + case PERSISTENT_RESERVE_IN: /*TODO: check !!! */ + case PERSISTENT_RESERVE_OUT: /*TODO: check !!! */ + case PREVENT_ALLOW_MEDIA_REMOVAL: /*TODO: check !!! */ + case READ_10: /*TODO: check !!! */ + case READ_CAPACITY: /*TODO: check !!! */ + case RELEASE_6: /*TODO: check !!! */ + case REQUEST_SENSE: /*TODO: check !!! */ + case RESERVE_6: /*TODO: check !!! */ + case START_STOP_UNIT: /*TODO: check !!! */ + case SYNCHRONIZE_CACHE: /*TODO: check !!! */ + case VERIFY: /*TODO: check !!! */ + case WRITE_10: /*TODO: check !!! */ + case WRITE_BUFFER:/*TODO Check correctnes of such translation!*/ + *rcmd = cmd; /* No need to copy */ + *rlen = len; /*TODO: check !!! */ + default: + TRACE_ALWAYS("An unsupported RBC command: %08x\n", command->opcode); + status = B_ERROR; + break; + } + if(transformed) + TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen); + return status; +} +/** + \fn:ufi_transform + \param udi: usb_device_info object for wich transformation is requested + \param cmd: SCSI command buffer to be transformed + \param len: length of buffer, pointed by cmd parameter + \param rcmd: a place for buffer pointer with transformed command + \param rlen: a place for length of transformed command + \return: B_OK if transformation was successfull, B_ERROR otherwise + this is the "transformation procedure" for UFI USB subclass (0x04).It + performs all SCSI commands transformations required by this protocol. Additionally + it tries to make some workarounds for "brocken" USB devices. If no transformation + was performed resulting command buffer points to original one. +*/ +status_t ufi_transform(usb_device_info *udi, + uint8 *cmd, + uint8 len, + uint8 **rcmd, + uint8 *rlen) +{ + status_t status = B_OK; + TRACE_SCSI_COMMAND(cmd, len); + memset(*rcmd, 0, UFI_COMMAND_LEN); + if(!transform_6_to_10(cmd, len, rcmd, rlen)){ /* was not transformed ?*/ + scsi_cmd_generic *command = (scsi_cmd_generic *)cmd; + switch(command->opcode){ + case TEST_UNIT_READY: + if(transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen)){ + break; /* if TEST UNIT READY was transformed*/ + } + case FORMAT_UNIT: /* TODO: mismatch */ + case INQUIRY: + case START_STOP_UNIT: + case MODE_SELECT_10: + case MODE_SENSE_10: + case PREVENT_ALLOW_MEDIA_REMOVAL: + case READ_10: + case READ_12: + case READ_CAPACITY: + case READ_FORMAT_CAPACITY: /* TODO: not in the SCSI-2 specs */ + case REQUEST_SENSE: + case REZERO_UNIT: + case SEEK_10: + case SEND_DIAGNOSTICS: /* TODO: parameter list len mismatch */ + case VERIFY: + case WRITE_10: + case WRITE_12: /* TODO: EBP. mismatch */ + case WRITE_AND_VERIFY: + memcpy(*rcmd, cmd, len); /*TODO what about control? ignored in UFI?*/ + break; + default: + TRACE_ALWAYS("An unsupported UFI command: %08x\n", command->opcode); + status = B_ERROR; + break; + } + } + *rlen = UFI_COMMAND_LEN; /* override any value set in transform funcs !!!*/ + if(status == B_OK) + TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen); + return status; +} +/** + \fn:atapi_transform + \param udi: usb_device_info object for wich transformation is requested + \param cmd: SCSI command buffer to be transformed + \param len: length of buffer, pointed by cmd parameter + \param rcmd: a place for buffer pointer with transformed command + \param rlen: a place for length of transformed command + \return: B_OK if transformation was successfull, B_ERROR otherwise + this is the "transformation procedure" for SFF8020I and SFF8070I + USB subclassses (0x02 and 0x05). It performs all SCSI commands transformations + required by this protocol. Additionally it tries to make some workarounds for + "broken" USB devices. If no transformation was performed resulting command + buffer points to original one. +*/ +status_t atapi_transform(usb_device_info *udi, + uint8 *cmd, + uint8 len, + uint8 **rcmd, + uint8 *rlen) +{ + status_t status = B_OK; + TRACE_SCSI_COMMAND(cmd, len); + memset(*rcmd, 0, ATAPI_COMMAND_LEN); + if(!transform_6_to_10(cmd, len, rcmd, rlen)){ /* was not transformed ?*/ + scsi_cmd_generic *command = (scsi_cmd_generic *)cmd; + switch(command->opcode){ + case TEST_UNIT_READY: + if(transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen)){ + break; /* if TEST UNIT READY was transformed*/ + } + case FORMAT_UNIT: + case INQUIRY: + case MODE_SELECT_10: + case MODE_SENSE_10: + case PREVENT_ALLOW_MEDIA_REMOVAL: + case READ_10: + case READ_12: /* mismatch in byte 1 */ + case READ_CAPACITY: /* mismatch. no transf len defined... */ + case READ_FORMAT_CAPACITY: /* TODO: check!!! */ + case REQUEST_SENSE: + case SEEK_10: + case START_STOP_UNIT: + case VERIFY: /* mismatch DPO */ + case WRITE_10: /* mismatch in byte 1 */ + case WRITE_12: /* mismatch in byte 1 */ + case WRITE_AND_VERIFY: /* mismatch byte 1 */ + case PAUSE_RESUME: + case PLAY_AUDIO: + case PLAY_AUDIO_MSF: + case REWIND: + case PLAY_AUDIO_TRACK: + /* are in FreeBSD driver but no in 8070/8020 specs ... + //case REZERO_UNIT: + //case SEND_DIAGNOSTIC: + //case POSITION_TO_ELEMENT: */ + case GET_CONFIGURATION: + case SYNCHRONIZE_CACHE: + case READ_BUFFER: + case READ_SUBCHANNEL: + case READ_TOC: /* some mismatch */ + case READ_HEADER: + case READ_DISK_INFO: + case READ_TRACK_INFO: + case SEND_OPC: + case READ_MASTER_CUE: + case CLOSE_TR_SESSION: + case READ_BUFFER_CAP: + case SEND_CUE_SHEET: + case BLANK: + case EXCHANGE_MEDIUM: + case READ_DVD_STRUCTURE: + case SET_CD_SPEED: + case DVD_REPORT_KEY: + case DVD_SEND_KEY: +// case 0xe5: /* READ_TRACK_INFO_PHILIPS *//* TODO: check!!! */ + memcpy(*rcmd, cmd, len); /* TODO: check!!! */ + break; + default: + TRACE_ALWAYS("An unsupported (?) ATAPI command: %08x\n", command->opcode); + status = B_ERROR; + break; + } + } + *rlen = ATAPI_COMMAND_LEN; + if(status == B_OK) + TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen); + return status; +} +/** + \fn:qic157_transform + \param udi: usb_device_info object for wich transformation is requested + \param cmd: SCSI command buffer to be transformed + \param len: length of buffer, pointed by cmd parameter + \param rcmd: a place for buffer pointer with transformed command + \param rlen: a place for length of transformed command + \return: B_OK if transformation was successfull, B_ERROR otherwise + this is the "transformation procedure" for QIC157 USB subclass (0x03).It + performs all SCSI commands transformations required by this protocol. Additionally + it tries to make some workarounds for "brocken" USB devices. If no transformation + was performed resulting command buffer points to original one. +*/ +status_t qic157_transform(usb_device_info *udi, + uint8 *cmd, + uint8 len, + uint8 **rcmd, + uint8 *rlen) +{ + status_t status = B_OK; + TRACE_SCSI_COMMAND(cmd, len); + *rlen = ATAPI_COMMAND_LEN; + memset(*rcmd, 0, *rlen); + if(!transform_6_to_10(cmd, len, rcmd, rlen)){ // was not transformed ? + scsi_cmd_generic *command = (scsi_cmd_generic *)cmd; + switch(command->opcode){ + case TEST_UNIT_READY: + if(transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen)){ + break; // if TEST UNIT READY was transformed + } + case ERASE: /*TODO: check !!! */ + case INQUIRY: /*TODO: check !!! */ + case LOAD_UNLOAD: /*TODO: check !!! */ + case LOCATE: /*TODO: check !!! */ + case LOG_SELECT: /*TODO: check !!! */ + case LOG_SENSE: /*TODO: check !!! */ + case MODE_SELECT_6: /*TODO: check !!! */ + case MODE_SENSE_6: /*TODO: check !!! */ + case READ_6: /*TODO: check !!! */ + case READ_POSITION: /*TODO: check !!! */ + case REQUEST_SENSE: /*TODO: check !!! */ + case REWIND: /*TODO: check !!! */ + case SPACE: /*TODO: check !!! */ + case WRITE_6: /*TODO: check !!! */ + case WRITE_FILEMARK: /*TODO: check !!! */ + *rcmd = cmd; /*TODO: check !!! */ + *rlen = len; + break; + default: + TRACE_ALWAYS("An unsupported QIC-157 command: %08x\n", command->opcode); + status = B_ERROR; + break; + } + } + if(status == B_OK) + TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen); + return status; +} + + +transform_module_info scsi_transform_m = { + {0, 0, 0}, /* this is not a real kernel module - just interface */ + scsi_transform, +}; + +transform_module_info rbc_transform_m = { + {0, 0, 0}, /* this is not a real kernel module - just interface */ + rbc_transform, +}; + +transform_module_info ufi_transform_m = { + {0, 0, 0}, /* this is not a real kernel module - just interface */ + ufi_transform, +}; + +transform_module_info atapi_transform_m = { + {0, 0, 0}, /* this is not a real kernel module - just interface */ + atapi_transform, +}; + +transform_module_info qic157_transform_m = { + {0, 0, 0}, /* this is not a real kernel module - just interface */ + qic157_transform, +}; diff --git a/src/add-ons/kernel/busses/scsi/usb/transform_procs.h b/src/add-ons/kernel/busses/scsi/usb/transform_procs.h new file mode 100644 index 0000000000..2d62bfe824 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/transform_procs.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/** decalration of SCSI commands transformation procedures */ + +#ifndef _TRANSFORM_PROCS_H_ + #define _TRANSFORM_PROCS_H_ + +#ifndef _PROTO_MODULE_H_ +#include "proto_module.h" +#endif /* _PROTO_MODULE_H_ */ +/* transforms SCSI commands */ +extern transform_module_info scsi_transform_m; +/* transforms RBC commands */ +extern transform_module_info rbc_transform_m; +/* transforms UFI commands */ +extern transform_module_info ufi_transform_m; +/* transforms ATAPI commands */ +extern transform_module_info atapi_transform_m; +/* transforms QIC-157 commands */ +extern transform_module_info qic157_transform_m; +#endif /*_TRANSFORM_PROCS_H_*/ diff --git a/src/add-ons/kernel/busses/scsi/usb/uninstall.sh b/src/add-ons/kernel/busses/scsi/usb/uninstall.sh new file mode 100755 index 0000000000..e1c15c0e86 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/uninstall.sh @@ -0,0 +1,32 @@ +#!/bin/sh +########################################################## +## +## USB Storage Module uninstallation script +## +## This file is a part of BeOS USB SCSI interface module project. +## Copyright (c) 2003-2004 by Siarzhuk Zharski +## All rights reserved. +## +## $Source: /cvsroot/sis4be/usb_scsi/uninstall.sh,v $ +## $Author: zharik $ +## $Revision: 1.3 $ +## $Date: 2004/06/06 09:19:47 $ +## +########################################################## + +DRIVER_TITLE="USB Storage Module" +DRIVER_NAME=usb_scsi +DRIVER_TARGET_NAME=usb + +answer=`alert "Do you really want to uninstall the $DRIVER_TITLE ?" "No" "Yes"` +if [ $answer == "No" ]; then + exit +fi + +rm ~/config/add-ons/kernel/busses/scsi/$DRIVER_TARGET_NAME +#rm ~/config/settings/kernel/drivers/$DRIVER_NAME + +answer=`alert "The $DRIVER_TITLE has been removed from your system.You need to reboot your system to finish uninstalletion" "Reboot" "OK"` +if [ $answer == "Reboot" ]; then + shutdown -r +fi diff --git a/src/add-ons/kernel/busses/scsi/usb/usb_defs.h b/src/add-ons/kernel/busses/scsi/usb/usb_defs.h new file mode 100644 index 0000000000..54db903b11 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/usb_defs.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/** definitions that should be in system headers but ... */ + +#ifndef _USB_DEFS_H_ + #define _USB_DEFS_H_ + +#define USB_EP_ATTR_CONTROL 0x00 +#define USB_EP_ATTR_ISOCHRONOUS 0x01 +#define USB_EP_ATTR_BULK 0x02 +#define USB_EP_ATTR_INTERRUPT 0x03 +#define USB_EP_ATTR_MASK 0x03 + +#define USB_EP_ADDR_DIR_IN 0x80 +#define USB_EP_ADDR_DIR_OUT 0x00 + +/*USB device class/subclass/protocl definitions*/ +#define USB_DEV_CLASS_MASS 0x08 + +#define USB_DEV_SUBCLASS_RBC 0x01 +#define USB_DEV_SUBCLASS_SFF8020I 0x02 +#define USB_DEV_SUBCLASS_QIC157 0x03 +#define USB_DEV_SUBCLASS_UFI 0x04 +#define USB_DEV_SUBCLASS_SFF8070I 0x05 +#define USB_DEV_SUBCLASS_SCSI 0x06 + +#define USB_DEV_PROTOCOL_CBI 0x00 +#define USB_DEV_PROTOCOL_CB 0x01 +#define USB_DEV_PROTOCOL_BULK 0x50 + +#define B_DEV_STALLED 0x8000a015 /* some "forgotten" error */ + +#endif /*_USB_DEFS_H_*/ diff --git a/src/add-ons/kernel/busses/scsi/usb/usb_scsi.c b/src/add-ons/kernel/busses/scsi/usb/usb_scsi.c new file mode 100644 index 0000000000..2115731106 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/usb_scsi.c @@ -0,0 +1,964 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +/** Main part of USB SIM implementation */ + +#include "usb_scsi.h" + +#include +#include +#include +#include +#include +#include "device_info.h" +#include "settings.h" +#include "transform_procs.h" +#include "tracing.h" +#include "scsi_commands.h" +#include "proto_common.h" +#include "proto_bulk.h" +#include "proto_cbi.h" +#include "usb_defs.h" +#include "fake_device.h" +#include "sg_buffer.h" + +status_t device_added(const usb_device device, + void **cookie); + +status_t device_removed(void *cookie); + +static long sim_action(CCB_HEADER *ccbh); +static long sim_init(); + +#define SIM_VERSION 1 +#define HBA_VERSION 1 + +//#define ROUNDUP(size, seg) (((size) + (seg) - 1) & ~((seg) - 1)) + +#define INQ_VENDOR_LEN 0x08 +#define INQ_PRODUCT_LEN 0x10 +#define INQ_REVISION_LEN 0x04 + +#define TRANS_TIMEOUT 7500000 + +static long path_id = -1; +static int32 load_count = 0; + +static char sim_vendor_name[] = "S.Zharski"; /* who wrote this driver */ +static char hba_vendor_name[] = "USB"; /* who made the hardware */ +static char controller_family[] = "USB SCSI"; /* what family of products */ + +struct usb_support_descriptor supported_devices[] = { + {0, 0, 0, 0, 0} +}; + +#define SIZEOF(array) (sizeof(array)/sizeof(array[0])) //????? + +usb_device_info *usb_devices[MAX_DEVICES_COUNT]; +/* main devices table locking semaphore */ +sem_id usb_serial_lock = -1; + +usb_module_info *usb; +static cam_for_sim_module_info *cam; + +struct usb_notify_hooks notify_hooks = { + device_added, + device_removed +}; +/** + \fn:match_device + \param device:??? + \param uii:??? + \param pproperties:??? + \return:B_BAD_TYPE , B_ENTRY_NOT_FOUND, B_OK + + ?? +*/ +status_t get_interface_properties(usb_interface_info *uii, + uint32 *pproperties) +{ + status_t status = B_BAD_TYPE; + if(uii->descr->interface_class == USB_DEV_CLASS_MASS){ + status = B_OK; + switch(uii->descr->interface_subclass){ + case USB_DEV_SUBCLASS_RBC: *pproperties |= CMDSET_RBC; break; + case USB_DEV_SUBCLASS_UFI: *pproperties |= CMDSET_UFI; break; + case USB_DEV_SUBCLASS_SFF8020I: + case USB_DEV_SUBCLASS_SFF8070I: *pproperties |= CMDSET_ATAPI; break; + case USB_DEV_SUBCLASS_SCSI: *pproperties |= CMDSET_SCSI; break; + case USB_DEV_SUBCLASS_QIC157: *pproperties |= CMDSET_QIC157; break; + default: + TRACE_ALWAYS("get_interface_properties:unknown USB subclass:%02x\n", + uii->descr->interface_subclass); + /*status = B_ENTRY_NOT_FOUND;*/ /*B_BAD_TYPE assumed*/ + break; + } + switch(uii->descr->interface_protocol){ + case USB_DEV_PROTOCOL_CBI: *pproperties |= PROTO_CBI; break; + case USB_DEV_PROTOCOL_CB: *pproperties |= PROTO_CB; break; + case USB_DEV_PROTOCOL_BULK: *pproperties |= PROTO_BULK_ONLY; break; + default: + TRACE_ALWAYS("get_interface_properties:unknown USB protocol:%02x\n", + uii->descr->interface_protocol); + /*status = B_ENTRY_NOT_FOUND;*/ /*B_BAD_TYPE assumed*/ + break; + } + if(status == B_OK){ + TRACE("get_interface_properties: standard properties:%08x\n", *pproperties); + } + } + return status; +} +/** + \fn: + +*/ +status_t load_vendor_module(char **path, const char *path_mask, + const char *prop, module_info **mi) +{ + status_t status = B_NO_MEMORY; + int path_len = strlen(path_mask) + strlen(prop); + *path = malloc(path_len); + if(*path){ + sprintf(*path, path_mask, prop); + status = get_module(*path, mi); + if(status != B_OK) + TRACE_ALWAYS("load_vendor_module:get_module(%s) failed:%08x\n", *path, status); + } else { + TRACE_ALWAYS("load_vendor_module:couldn't allocate %d bytes\n", path_len); + } + return status; +} +/** + \fn: + +*/ +status_t setup_transport_modules(usb_device_info *udi, + usb_device_settings *uds) +{ + status_t status = B_OK; + switch(PROTO(udi->properties)){ + case PROTO_BULK_ONLY: + udi->protocol_m = &bulk_only_protocol_m; + break; + case PROTO_CB: + case PROTO_CBI: + udi->protocol_m = &cbi_protocol_m; + break; + case PROTO_VENDOR:{ + status = load_vendor_module(&udi->protocol_m_path, + PROTOCOL_MODULE_MASK, + uds->vendor_protocol, + (module_info**)&udi->protocol_m); + }break; + default: + TRACE_ALWAYS("setup_transport_modules: " + "transport %02x is not supported\n", PROTO(udi->properties)); + status = B_ENTRY_NOT_FOUND; + } + if(status == B_OK){ + switch(CMDSET(udi->properties)){ + case CMDSET_SCSI: + udi->transform_m = &scsi_transform_m; + break; + case CMDSET_UFI: + udi->transform_m = &ufi_transform_m; + udi->properties |= FIX_FORCE_MS_TO_10; /* always use 10-byte request */ + break; + case CMDSET_ATAPI: + udi->transform_m = &atapi_transform_m; + udi->properties |= FIX_FORCE_MS_TO_10; /* always use 10-byte request */ + break; + case CMDSET_RBC: + udi->transform_m = &rbc_transform_m; + break; + case CMDSET_QIC157: + udi->transform_m = &qic157_transform_m; + udi->properties |= FIX_FORCE_MS_TO_10; /* always use 10-byte request */ + break; + case CMDSET_VENDOR:{ + status = load_vendor_module(&udi->transform_m_path, + TRANSFORM_MODULE_MASK, + uds->vendor_commandset, + (module_info**)&udi->transform_m); + }break; + default: + TRACE_ALWAYS("setup_transport_modules: " + "protocol %02x is not supported\n", CMDSET(udi->properties)); + status = B_ENTRY_NOT_FOUND; + } + } + return status; +} + +static void +release_transport_modules(usb_device_info *udi) +{ + if(PROTO(udi->properties) == PROTO_VENDOR && 0 != udi->protocol_m_path){ + put_module(udi->protocol_m_path); + udi->protocol_m = 0; + free(udi->protocol_m_path); + } + if(CMDSET(udi->properties) == CMDSET_VENDOR && 0 != udi->transform_m_path){ + put_module(udi->transform_m_path); + udi->transform_m = 0; + free(udi->transform_m_path); + } +} + +/** + \fn: +*/ +status_t setup_endpoints(usb_interface_info *uii, + usb_device_info *udi) +{ + status_t status = B_OK; + int16 idx = 0; + enum{ epIn = 0, epOut, epIntr, epCount }; + size_t epts[epCount] = { -1, -1, -1 }; + char *epnames[epCount] = {"input", "output", "interrupt"}; + size_t ep = 0; + for(; ep < uii->endpoint_count; ep++){ + usb_endpoint_descriptor *ed = uii->endpoint[ep].descr; + TRACE("try endpoint:%d %x %x %x\n", ep, (int32)ed->attributes, (int32)ed->endpoint_address, uii->endpoint[ep].handle); + if((ed->attributes & USB_EP_ATTR_MASK) == USB_EP_ATTR_BULK){ + if((ed->endpoint_address & USB_EP_ADDR_DIR_IN) == USB_EP_ADDR_DIR_IN){ + epts[epIn] = ep; + }else{ + epts[epOut] = ep; + } + }else{ + if((ed->attributes & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTERRUPT) + epts[epIntr] = ep; + } + } + switch(PROTO(udi->properties)){ + case PROTO_CB: + case PROTO_BULK_ONLY: + if(epts[epIntr] == -1) + epts[epIntr] = 0; /* not required for this transports - set it to default*/ + break; + case PROTO_CBI: + default: + } + for(idx = 0; idx < epCount; idx++){ + if(epts[idx] == -1 && PROTO(udi->properties) != PROTO_VENDOR){ + TRACE_ALWAYS("setup_endpoints: required %s endpoint not found. " + "ignore this interface\n", epnames[idx]); + // DEBUG!!!!!!!!!! + status = B_ERROR; + } + } + if(status == B_OK){ + udi->pipe_in = uii->endpoint[epts[epIn]].handle; + udi->pipe_out = uii->endpoint[epts[epOut]].handle; + udi->pipe_intr = uii->endpoint[epts[epIntr]].handle; + //TRACE("setup_endpoints: input:%d output:%d " + // "interrupt:%d\n", epts[epIn], epts[epOut], epts[epIntr]); + TRACE("endpoint:%x %x %x\n", udi->pipe_in, udi->pipe_out, udi->pipe_intr); + } + return status; +} +/** + \fn:create_device_info + \param device:??? + \param ppudi:??? + \return:??? + + ??? +*/ +status_t allocate_resources(usb_device_info *udi) +{ + char name[32]; + status_t status = B_NO_MEMORY; + uint16 dev = 0; + acquire_sem(usb_serial_lock); + for(; dev < MAX_DEVICES_COUNT; dev++){ + if(!usb_devices[dev]) + break; + } + if(dev < MAX_DEVICES_COUNT){ + usb_devices[dev] = udi; + udi->lock_sem = + udi->trans_sem = -1; + sprintf(name, "usb_scsi lock_sem:%d", dev); + if((udi->lock_sem = create_sem(0, name)) >= 0){ + sprintf(name, "usb_scsi trans_sem:%d", dev); + if((udi->trans_sem = create_sem(0, name))>=0){ + udi->dev_num = dev; + release_sem(udi->lock_sem); + status = B_OK; + }else + status = udi->trans_sem; + } else + status = udi->lock_sem; + + if(status != B_OK){ + TRACE_ALWAYS("allocate_resources:error:%s", strerror(status)); + if(udi->lock_sem >= 0) + delete_sem(udi->lock_sem); + if(udi->trans_sem >= 0) + delete_sem(udi->trans_sem); + usb_devices[dev] = NULL; + free(udi); + } + }else{ + TRACE_ALWAYS("allocate_resources:reserved devices space exhausted." + "Unplug unnesesary devices or reconfigure this driver.\n"); + } + release_sem(usb_serial_lock); + return status; +} +/** + \fn: + +*/ +void release_resources(usb_device_info *udi) +{ + release_transport_modules(udi); + udi->usb_m = 0; + (*usb->cancel_queued_transfers)(udi->pipe_in); + (*usb->cancel_queued_transfers)(udi->pipe_out); + delete_sem(udi->lock_sem); + delete_sem(udi->trans_sem); + acquire_sem(usb_serial_lock); + usb_devices[udi->dev_num] = NULL; + release_sem(usb_serial_lock); +} +/** + \fn:device_added + \param device:?? + \param cookie:?? + \return:?? + + ?? +*/ +status_t device_added(const usb_device device, + void **cookie){ + status_t status = B_NO_MEMORY; + const usb_configuration_info *uci = NULL; + uint16 cfg = 0; + bool b_found = false; + bool b_has_extra_settings = false; + const usb_device_descriptor *udd = (*usb->get_device_descriptor)(device); + usb_device_info *udi = (usb_device_info *)malloc(sizeof(usb_device_info)); + TRACE("device_added: probing canidate: " + "%04x/%04x %02d/%02d/%02d\n", udd->vendor_id, udd->product_id, + udd->device_class, udd->device_subclass, udd->device_protocol); + if(udi){ + status = B_NO_INIT; + while(!b_found && (uci = (*usb->get_nth_configuration)(device, cfg++))){ + uint16 itf = 0; + for(; itf < uci->interface_count && !b_found; itf++){ + usb_interface_list *ifl = &uci->interface[itf]; + uint16 alt = 0; + for(; alt < ifl->alt_count; alt++){ + usb_interface_info *uii = &ifl->alt[alt]; + usb_device_settings ud_settings; + memset(udi, 0, sizeof(usb_device_info)); + memset(&ud_settings, 0, sizeof(usb_device_settings)); + udi->device = device; + udi->interface = itf; + b_has_extra_settings = lookup_device_settings(udd, &ud_settings); + switch(get_interface_properties(uii, &udi->properties)){ + case B_BAD_TYPE: /* non-standard USB class*/ + if(!b_has_extra_settings){ + continue; /* skip to next interface */ + } /* no break - fall through */ + case B_OK: + if(b_has_extra_settings){ + if(PROTO(ud_settings.properties) != PROTO_NONE){ + udi->properties &= ~PROTO_MASK; + udi->properties |= PROTO(ud_settings.properties); + } + if(CMDSET(ud_settings.properties) != CMDSET_NONE){ + udi->properties &= ~CMDSET_MASK; + udi->properties |= CMDSET(ud_settings.properties); + } + udi->properties |= ud_settings.properties & FIX_MASK; + TRACE("device_added: properties merged:%08x\n", udi->properties); + } + if( B_OK == setup_transport_modules(udi, &ud_settings)){ + break; + } /* else - no break - fall through */ + default: + continue; /* skip to next interface */ + } + if(alt != 0){ /*TODO: are we need this ???*/ + if((status = (*usb->set_alt_interface)(device, uii)) != B_OK){ + TRACE_ALWAYS("device_added:setting alt interface failed:%s", + strerror(status)); + goto Failed;/* Break - is it right?*/ + } + } + if((*usb->get_configuration)(device) != uci){ + if((status = (*usb->set_configuration)(device, uci)) != B_OK){ + TRACE_ALWAYS("device_added:setting configuration failed:%08x uci: %08x\n", + (*usb->get_configuration)(device), uci); + TRACE_ALWAYS("device_added:setting configuration failed:%s\n", + strerror(status)); + + goto Failed;/* Break - is it right?*/ + } + } + if(B_OK != setup_endpoints(uii, udi)){ + continue; /* skip to next interface */ + } + if((status = allocate_resources(udi)) == B_OK){ + udi->b_trace = b_log_protocol; + udi->trace = usb_scsi_trace; + udi->trace_bytes = usb_scsi_trace_bytes; + udi->trans_timeout = TRANS_TIMEOUT; + udi->usb_m = usb; + udi->not_ready_luns = 0xff; /*assume all LUNs initially not ready */ + if((status = (*udi->protocol_m->init)(udi)) == B_OK){ + TRACE("device_added[%d]: SUCCESS! Enjoy using!\n", udi->dev_num); + *cookie = udi; + b_found = true; /* we have found something useful - time to go out! */ + break; /* ... now break alternatives iteration.*/ + } else { + release_resources(udi); + } + } + /* go to next iteration - check all configurations for possible devices */ + }/* for(...) iterate interface alternates*/ + }/* for(...) iterate interfaces*/ + }/* while(...) iterate configurations */ + if(status == B_OK){ + (*cam->minfo.rescan)(); + } else { + free(udi); + } + } /* if(udi){ */ + if(status != B_OK){ + TRACE("device_added: probing failed (%s) for: %04x/%04x\n", + strerror(status), udd->vendor_id, udd->product_id); + } +Failed: + return status; +} +/** + \fn:device_removed + \param cookie:??? + \return:??? + + ??? +*/ +status_t device_removed(void *cookie) +{ + status_t status = B_OK; + usb_device_info *udi = (usb_device_info *)cookie; + acquire_sem(udi->lock_sem); /* wait for possible I/O operation complete */ + release_resources(udi); + /* no corresponding call of release_sem(udi->lock_sem); + - semaphore was deleted in release_resources, any waiting thread + was failed with BAD_SEM_ID. + */ + TRACE_ALWAYS("device_removed[%d]:All The Best !!!\n", udi->dev_num); + free(udi); + (*cam->minfo.rescan)(); + return status; +} +/** + \fn:sim_init + \return: ??? + + called on SIM init +*/ +static long sim_init(void) +{ + status_t status = B_OK; + TRACE("sim_init\n"); + return status; +} + +/** +*/ +static bool +pre_check_scsi_io_request(usb_device_info *udi, + CCB_SCSIIO *ccbio, + status_t *ret_status) +{ + int target_id = ccbio->cam_ch.cam_target_id; + uint8 target_lun = ccbio->cam_ch.cam_target_lun; + *ret_status = B_OK; + /* handle reserved device and luns entries */ + if(b_reservation_on && udi == NULL && + target_id < reserved_devices && + target_lun < reserved_luns) + { + *ret_status = fake_scsi_io(ccbio); + return false; + } + /* no device for this target | LUN */ + if(udi == NULL || target_lun > udi->max_lun){ + ccbio->cam_ch.cam_status = CAM_DEV_NOT_THERE; + *ret_status = B_DEV_BAD_DRIVE_NUM; + return false; + } + /* check command length */ + if(ccbio->cam_cdb_len != 6 && + ccbio->cam_cdb_len != 10 && + ccbio->cam_cdb_len != 12) + { + TRACE("Bad SCSI command length:%d.Ignore\n", ccbio->cam_cdb_len); + ccbio->cam_ch.cam_status = CAM_REQ_INVALID; + *ret_status = B_BAD_VALUE; + return false; + } + /* Clean up auto sense buffer. + To avoid misunderstanding in not ready luns logic detection.*/ + if(NULL == ccbio->cam_sense_ptr){ + memset(&udi->autosense_data, 0, sizeof(udi->autosense_data)); + } else { + memset(ccbio->cam_sense_ptr, 0, ccbio->cam_sense_len); + } + return true; +} +/** +*/ +static bool +pre_handle_features(usb_device_info *udi, + CCB_SCSIIO *ccbio, + scsi_cmd_generic *command, + sg_buffer *sgb, + status_t *ret_status) +{ + uint8 target_lun = ccbio->cam_ch.cam_target_lun; + *ret_status = B_OK; + udi->trans_timeout = TRANS_TIMEOUT; + switch(command->opcode){ + case MODE_SELECT_6: + case MODE_SENSE_6:{ + bool b_select = (MODE_SELECT_6 == command->opcode); + const char*cmd_name = b_select ? "MODE_SELECT" : "MODE_SENSE"; + if(udi->not_ready_luns & (1 << target_lun)){ + TRACE("pre_handle_features:%s_6 bypassed for LUN:%d\n", cmd_name, target_lun); + goto set_REQ_INVALID_and_return; + } + if(HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)){ + if( B_OK != realloc_sg_buffer(sgb, ccbio->cam_dxfer_len + 4)){ /* TODO: 4 - hardcoded? */ + TRACE_ALWAYS("pre_handle_features:error allocating %d bytes for %s_10\n", + ccbio->cam_dxfer_len + 4, cmd_name); + goto set_REQ_INVALID_and_return; + } + if(b_select){ + sg_buffer sgb_sense_6; + /*TODO: implemenet and try refragment_sg_buffer - to check handling of real scatter/gather!!*/ + if(B_OK != init_sg_buffer(&sgb_sense_6, ccbio)){ + /* In case of error TRACE-ing was already performed in sg_ functions */ + goto set_REQ_INVALID_and_return; + } + TRACE_MODE_SENSE_SGB("MODE SELECT 6:", &sgb_sense_6); + if(B_OK != sg_memcpy(sgb, 1, &sgb_sense_6, 0, 3) || + B_OK != sg_memcpy(sgb, 7, &sgb_sense_6, 3, 1) || + B_OK != sg_memcpy(sgb, 8, &sgb_sense_6, 4, ccbio->cam_dxfer_len - sizeof(scsi_mode_param_header_6))) + { + /* In case of error TRACE-ing was already performed in sg_ functions */ + goto set_REQ_INVALID_and_return; + } + TRACE_MODE_SENSE_SGB("MODE SELECT 10:", sgb); + } + } /*else { + if(b_select){ / * trace data if configured in settings * / + TRACE_MODE_SENSE_DATA("MODE_SELECT:", ccbio->cam_data_ptr, ccbio->cam_dxfer_len); + } + }*/ + }break; + case INQUIRY: /* fake INQUIRY request */ + if(HAS_FIXES(udi->properties, FIX_NO_INQUIRY)){ + fake_inquiry_request(udi, ccbio); + goto set_REQ_CMP_and_return; + } break; + case TEST_UNIT_READY: /* fake INQUIRY request */ + if(HAS_FIXES(udi->properties, FIX_NO_TEST_UNIT)){ + goto set_REQ_CMP_and_return; + } break; + case PREVENT_ALLOW_MEDIA_REMOVAL: /* fake PREVENT_ALLOW_MEDIA_REMOVAL request */ + if(HAS_FIXES(udi->properties, FIX_NO_PREVENT_MEDIA)){ + goto set_REQ_CMP_and_return; + } break; + case FORMAT_UNIT: + udi->trans_timeout = B_INFINITE_TIMEOUT; + break; + default: break; + } + return true; + +set_REQ_CMP_and_return: + ccbio->cam_ch.cam_status = CAM_REQ_CMP; + return false;//*ret_status = B_OK; + +set_REQ_INVALID_and_return: + ccbio->cam_ch.cam_status = CAM_REQ_INVALID; + *ret_status = B_BAD_VALUE; + return false; +} +/** +*/ +static bool +post_handle_features(usb_device_info *udi, + CCB_SCSIIO *ccbio, + scsi_cmd_generic *command, + sg_buffer *sgb, + status_t *ret_status) +{ + bool b_cmd_ok = (ccbio->cam_ch.cam_status == CAM_REQ_CMP); + uint8 target_lun = ccbio->cam_ch.cam_target_lun; + switch(command->opcode){ + case READ_6: + case WRITE_6: +#if 0 +/* Disabled - single problem can switch to 6-bytes mode. If device doesn't + support 6-bytes command all goes totally wrong. That's bad. */ + if(!b_cmd_ok && !HAS_FEATURES(udi->descr.properties, PROP_FORCE_RW_TO_6)){ + TRACE("post_handle_features:READ(10)/WRITE(10) failed - retry 6-byte one\n"); + udi->descr.properties |= PROP_FORCE_RW_TO_6; + ccbio->cam_scsi_status = SCSI_STATUS_OK; /* clear the scsi_status. */ + ccbio->cam_ch.cam_status = CAM_REQ_INPROG; /* set status in progress again. */ + b_retry = true; /* inform caller about retry */ + } +#endif + break; + case MODE_SENSE_6: + if(!b_cmd_ok && !HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)){ + TRACE("post_handle_features:MODE SENSE(6) failed - retry 10-byte one\n"); + udi->properties |= FIX_FORCE_MS_TO_10; + ccbio->cam_scsi_status = SCSI_STATUS_OK; /* clear the scsi_status. */ + ccbio->cam_ch.cam_status = CAM_REQ_INPROG; /* set status in progress again. */ + return true; /* inform caller about retry */ + } /* no break, - fallthrough! */ + case MODE_SELECT_6:{ + if(MODE_SENSE_6 == command->opcode){ + sg_buffer sgb_sense_6; + if(B_OK != init_sg_buffer(&sgb_sense_6, ccbio)){ + TRACE_ALWAYS("post_hanlde_features: initialize sgb failed\n"); + goto set_REQ_INVALID_and_return; + } + /* convert sense information from 10-byte request result to 6-byte one */ + if(HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)){ + uchar mode_data_len_msb = 0, block_descr_len_msb = 0; + if( B_OK != sg_access_byte(sgb, 0, &mode_data_len_msb, false) || + B_OK != sg_access_byte(sgb, 6, &block_descr_len_msb, false) || + 0 != mode_data_len_msb || 0 != block_descr_len_msb) + { + /* In case of error TRACE-ing was already performed in sg_ functions */ + TRACE_ALWAYS("MODE_SENSE 10->6 conversion overflow: %d, %d\n", + mode_data_len_msb, block_descr_len_msb); + goto set_REQ_INVALID_and_return; + } + TRACE_MODE_SENSE_SGB("MODE SENSE 10:", sgb); + if( B_OK != sg_memcpy(&sgb_sense_6, 0, sgb, 1, 3) || + B_OK != sg_memcpy(&sgb_sense_6, 3, sgb, 7, 1) || + B_OK != sg_memcpy(&sgb_sense_6, 4, sgb, 8, ccbio->cam_dxfer_len - sizeof(scsi_mode_param_header_6))) + { + /* In case of error TRACE-ing was already performed in sg_ functions */ + TRACE_ALWAYS("MODE_SENSE 10->6 conversion failed\n"); + goto set_REQ_INVALID_and_return; + } + } + /* set write-protected flag if required by user */ + if(HAS_FIXES(udi->properties, FIX_FORCE_READ_ONLY)){ + status_t status = B_OK; + uchar device_spec_params = 0; + if(B_OK == (status = sg_access_byte(sgb, 2, &device_spec_params, false))){ + device_spec_params |= 0x80; + status = sg_access_byte(sgb, 2, &device_spec_params, true); + } + if(B_OK != status){ + TRACE_ALWAYS("MODE_SENSE set READ-ONLY mode failed. Writing ALLOWED!\n"); + /*goto set_req_invalid_and_return;*/ /* not urgent. do not fail processing... */ + } + } + TRACE_MODE_SENSE_SGB("MODE SENSE 6:", &sgb_sense_6); + } + if(HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)){ + free_sg_buffer(sgb); + } + } break; + case TEST_UNIT_READY: { /* set the not ready luns flag */ + scsi_sense_data *sense_data = (ccbio->cam_sense_ptr == NULL) ? + &udi->autosense_data : (scsi_sense_data *)ccbio->cam_sense_ptr; + if((sense_data->flags & SSD_KEY) == SSD_KEY_NOT_READY){ + udi->not_ready_luns |= (1 << target_lun); + } else { + udi->not_ready_luns &= ~(1 << target_lun); + } + usb_scsi_trace_bytes("NOT_READY_LUNS:", &udi->not_ready_luns, 1); + } break; + case READ_CAPACITY:{ + /*uint8 *bts = sgb->piov->iov_base; + uint32 capacity = (bts[0]<<24) + (bts[1]<<16) + (bts[2]<<8) + (bts[3]); + TRACE_ALWAYS("CAPAC:%d\n", capacity); + //bts[3] -= 3;*/ + TRACE_CAPACITY("READ_CAPACITY:", sgb); + } break; + default: break; + } + return false; /* do not retry - all is OK */ //b_retry; + +set_REQ_INVALID_and_return: + ccbio->cam_ch.cam_status = CAM_REQ_INVALID; + *ret_status = B_BAD_VALUE; + return false; /* do not retry - fatal error */ +} +/** + \fn:xpt_scsi_io + \param ccbio: ???? + \return: ??? + + xpt_scsi_io - handle XPT_SCSI_IO sim action +*/ +status_t xpt_scsi_io(CCB_SCSIIO *ccbio) +{ + status_t status = B_OK; + usb_device_info *udi = usb_devices[ccbio->cam_ch.cam_target_id/*target_id*/]; + uint8 *cmd; + sg_buffer sgb; + + /* clear the scsi_status. It can come from system with some garbage value ...*/ + ccbio->cam_scsi_status = SCSI_STATUS_OK; + /* check the request for correct parameters, valid targets, luns etc ... */ + if(false == pre_check_scsi_io_request(udi, ccbio, &status)){ + return status; + } + +#if 0 /* activate if you need detailed logging of CCB_SCSI request*/ + usb_scsi_trace_CCB_SCSIIO(ccbio); +#endif + + + /* acquire semaphore - avoid re-enters */ +/* if((status = acquire_sem_etc(udi->lock_sem, 1, + B_RELATIVE_TIMEOUT, + udi->trans_timeout)) != B_OK) */ +// TRACE_ALWAYS("sem before acq:%08x\n",udi->lock_sem); + if((status = acquire_sem(udi->lock_sem)) != B_OK){ + /* disabled - CAM_BUSY flag is not recognized by BeOS ... :-( + if(status == B_WOULD_BLOCK){ + TRACE("locked sema bypass OK\n"); + ccbio->cam_ch.cam_status = CAM_BUSY; + return B_OK; + }*/ + TRACE("xpt_scsi_io:acquire_sem_etc() failed:%08x\n", status); + ccbio->cam_ch.cam_status = CAM_DEV_NOT_THERE; + return B_DEV_BAD_DRIVE_NUM; + } + /* set the command data pointer */ + if(ccbio->cam_ch.cam_flags & CAM_CDB_POINTER){ + cmd = ccbio->cam_cdb_io.cam_cdb_ptr; + }else{ + cmd = ccbio->cam_cdb_io.cam_cdb_bytes; + } + /* NOTE: using stack copy of sg_buffer sgb. It can be modified/freed in + *_handle_features() functions! Twice reallocation is also not awaited! + Note this on refactoring!!! */ + /*TODO returns!*/ + init_sg_buffer(&sgb, ccbio); + do{ /* <-- will be repeated if 6-byte RW/MS commands failed */ + uint8 *rcmd; + uint8 rcmdlen; + uint32 transfer_len = 0; + EDirection dir = eDirNone; + /* handle various features for this device */ + if(!pre_handle_features(udi, ccbio, (scsi_cmd_generic *)cmd, &sgb, &status)){ + release_sem(udi->lock_sem); + return status; + } + /* transform command as required by protocol */ + rcmd = udi->scsi_command_buf; + rcmdlen = sizeof(udi->scsi_command_buf); + if((status = (*udi->transform_m->transform)(udi, cmd, ccbio->cam_cdb_len & 0x1f, + &rcmd, &rcmdlen)) != B_OK) + { + TRACE_ALWAYS("xpt_scsi_io: transform failed: %08x\n", status); + ccbio->cam_ch.cam_status = CAM_REQ_INVALID; + release_sem(udi->lock_sem); + return B_BAD_VALUE; + } + /* set correct direction flag */ + switch(CAM_DIR_MASK & ccbio->cam_ch.cam_flags){ + case CAM_DIR_IN: dir = eDirIn; break; + case CAM_DIR_OUT: dir = eDirOut; break; + default: dir = eDirNone; break; + } + + TRACE_DATA_IO_SG(sgb.piov, sgb.count); + + /*TODO: return!*/ + sg_buffer_len(&sgb, &transfer_len); + /* transfer command to device. SCSI status will be handled in callback */ + (*udi->protocol_m->transfer)(udi, rcmd, rcmdlen, sgb.piov, sgb.count, + transfer_len/*ccbio->cam_dxfer_len*/, + dir, ccbio, transfer_callback); + /* perform some post-tranfer features handling + and automatic 6-10 bytes command support detection */ + } while(post_handle_features(udi, ccbio, (scsi_cmd_generic *)cmd, &sgb, &status)); + release_sem(udi->lock_sem); + return status; +} +/** + \fn:xpt_path_inquiry + \param ccbp: + \return: + + xpt_path_inquiry - handle XPT_PATH_INQ sim action +*/ +status_t xpt_path_inquiry(CCB_PATHINQ *ccbp) +{ + status_t status = B_OK; + ccbp->cam_version_num = SIM_VERSION; + ccbp->cam_target_sprt = 0; + ccbp->cam_hba_eng_cnt = 0; + memset (ccbp->cam_vuhba_flags, 0, VUHBA); + ccbp->cam_sim_priv = SIM_PRIV; + ccbp->cam_async_flags = 0; + ccbp->cam_initiator_id = CONTROLLER_SCSI_ID; + ccbp->cam_hba_inquiry = CONTROLLER_SCSI_BUS; /* Narrow SCSI bus */ + ccbp->cam_hba_misc = PIM_NOINQUIRY; + ccbp->cam_osd_usage = 0; + /* There should be special handling of path_id == 0xff + but looks like it's not used by BeOS now */ + /*ccbp->cam_hpath_id = path_id;*/ + strncpy(ccbp->cam_sim_vid, sim_vendor_name, SIM_ID); + strncpy(ccbp->cam_hba_vid, hba_vendor_name, HBA_ID); + ccbp->cam_ch.cam_status = CAM_REQ_CMP; + return status; +} +/** + \fn:xpt_extended_path_inquiry + \param ccbep: ??? + \return:??? + + xpt_extended_path_inquiry - handle XPT_EXTENDED_PATH_INQ sim action +*/ +status_t xpt_extended_path_inquiry(CCB_EXTENDED_PATHINQ *ccbep) +{ + status_t status = B_OK; + xpt_path_inquiry((CCB_PATHINQ *)ccbep); + sprintf(ccbep->cam_sim_version, "%d.0", SIM_VERSION); + sprintf(ccbep->cam_hba_version, "%d.0", HBA_VERSION); + strncpy(ccbep->cam_controller_family, controller_family, FAM_ID); + strncpy(ccbep->cam_controller_type, "USB-SCSI", TYPE_ID); + return status; +} +/** + \fn:sim_action + \param ccbh: ???? + \return: ???? + + This fucntion performs SCSI interface module actions - + calls corresponding xpt_* - functions. +*/ +static long sim_action(CCB_HEADER *ccbh) +{ + status_t status = B_ERROR; + if(path_id != ccbh->cam_path_id){ + TRACE_ALWAYS("sim_action:path_id mismatch of func:%d:our:%d,requested:%d\n", + ccbh->cam_func_code, path_id, ccbh->cam_path_id); + ccbh->cam_status = CAM_PATH_INVALID; + } else { + ccbh->cam_status = CAM_REQ_INPROG; + switch(ccbh->cam_func_code){ + case XPT_SCSI_IO: + status = xpt_scsi_io((CCB_SCSIIO *)ccbh); + break; + case XPT_PATH_INQ: + status = xpt_path_inquiry((CCB_PATHINQ *)ccbh); + break; + case XPT_EXTENDED_PATH_INQ: + status = xpt_extended_path_inquiry((CCB_EXTENDED_PATHINQ *)ccbh); + break; + default: + TRACE_ALWAYS("sim_action: unsupported function: %x\n", ccbh->cam_func_code); + ccbh->cam_status = CAM_REQ_INVALID; + break; + } + } + return status; +} +/** + \fn:std_ops + \param op: operation to be performed on this module + \param ...: possible additional arguments + \return: B_OK on success, error status on failure + + This function deals with standard module operations. Currently, the only + two things that entails are initialization and uninitialization. + - get the SCSI Bus Manager Module and USB Manager Module + - put them when we're finished +*/ +static status_t std_ops(int32 op, ...) +{ + int i; + status_t status = B_ERROR; + CAM_SIM_ENTRY entry; + switch(op) { + case B_MODULE_INIT: + if(0 == atomic_add(&load_count, 1)){ + thread_info tinfo = {0}; + load_module_settings(); + get_thread_info(find_thread(0), &tinfo); + if(!b_ignore_sysinit2 || (0 != strcmp(tinfo.name, "sysinit2"))){ + create_log(); + if(get_module(B_USB_MODULE_NAME, (module_info **)&usb) == B_OK){ + if(get_module(B_CAM_FOR_SIM_MODULE_NAME, (module_info **)&cam) == B_OK){ + for(i = 0; i < MAX_DEVICES_COUNT; i++) + usb_devices[i] = NULL; + + if((*usb->register_driver)(MODULE_NAME, supported_devices, SIZEOF(supported_devices), "usb_dsk") == B_OK){ + if((*usb->install_notify)(MODULE_NAME, ¬ify_hooks) == B_OK){ + entry.sim_init = sim_init; + entry.sim_action = sim_action; + path_id =(*cam->xpt_bus_register)(&entry); + usb_serial_lock = create_sem(1, MODULE_NAME"_devices_table_lock"); + status = B_OK; + break; + } + } + put_module(B_CAM_FOR_SIM_MODULE_NAME); + } + put_module(B_USB_MODULE_NAME); + } + } else { + TRACE_ALWAYS("std_ops INIT call was ignored for thread:%s\n", tinfo.name); + } + } else { + atomic_add(&load_count, -1); + } + break; + case B_MODULE_UNINIT: + if(1 == atomic_add(&load_count, -1)){ + (*usb->uninstall_notify)(MODULE_NAME); + status = B_OK; + if(path_id != -1){ + (*cam->xpt_bus_deregister)(path_id); + path_id = -1; + } + delete_sem(usb_serial_lock); + put_module(B_USB_MODULE_NAME); + put_module(B_CAM_FOR_SIM_MODULE_NAME); + } else { + atomic_add(&load_count, 1); + } + break; + } + return status; +} + +/** + Declare our module_info so we can be loaded as a kernel module +*/ +static sim_module_info sim_usb_module = { + { "busses/scsi/usb/v1", 0, &std_ops } +}; +/** + Export module_info-s list +*/ +_EXPORT module_info *modules[] = { + (module_info *) &sim_usb_module, + NULL +}; diff --git a/src/add-ons/kernel/busses/scsi/usb/usb_scsi.devices b/src/add-ons/kernel/busses/scsi/usb/usb_scsi.devices new file mode 100644 index 0000000000..fbc4e19da7 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/usb_scsi.devices @@ -0,0 +1,76 @@ +########################################################## +## +## USB Storage Module non-standard devices definitions +## +## This file is a part of BeOS USB SCSI interface module project. +## Copyright (c) 2003-2005 by Siarzhuk Zharski +## All rights reserved. +## +########################################################## +## +## To use the those devices definitions, listed below copy +## it to your settings file. For more details look in ReadMe.html +## + +########################################################## +# +# Sony DSC series of digital cameras. +# +# ( reported by CKJ ) +# +# Those devices report subclass (command set) as 0xff +# but work with transparent SCSI command set +# +vendor 0x054c { + device 0x0010 { + commandset SCSI + protocol CB + } +} +########################################################## +# +# Sony cameras. +# +# (reported by RudolfC) +# +# Sony DV handycam DCR-TRV22E USB mass storage interface +# Those devices report subclass (command set) as 0xff +# but work with transparent SCSI command set +# +vendor 0x054c { + device 0x002e { + commandset SCSI + protocol CB + } +} + + +########################################################## +# +# Siemens mp3 Player. +# +# Supports standard protocol but doesn't like 6-byte mode_sense/mode_select +# requests. Doesn't perform standard reset procedures - if device hang - switch +# it off and plug it again. +# +vendor 0x0483 { + device 0x1307 { + protocol BULK + commandset SCSI + use_mode_sense_10 + } +} + +########################################################## +# +# FREECOM USB-ATAPI bridge. +# +# Supports FREECOM USB Cable connected CD/DVD drives/burners +# +# +vendor 0x07ab { + device 0xfc01 { + protocol freecom + commandset ATAPI + } +} diff --git a/src/add-ons/kernel/busses/scsi/usb/usb_scsi.h b/src/add-ons/kernel/busses/scsi/usb/usb_scsi.h new file mode 100644 index 0000000000..67925e9722 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/usb_scsi.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2003-2005 by Siarzhuk Zharski + * Distributed under the terms of the BSD License. + * + */ + +#ifndef _USB_SCSI_H_ + #define _USB_SCSI_H_ + +#ifndef _OS_H + #include +#endif //_OS_H + +#ifndef _USB_V3_H + #include "USB_v3.h" +#endif /* _USB_V3_H */ + +#ifndef _CAM_H + #include +#endif /*_CAM_H*/ + +#define MODULE_NAME "usb_scsi" + +#define CONTROLLER_SCSI_BUS 0x00 /* Narrow SCSI bus. Use PI_* to alter this*/ +#define MAX_DEVICES_COUNT 0x07 /* simulate Narrow SCSI bus - 8 devices*/ +#define CONTROLLER_SCSI_ID 0x07 /* "controller" SCSI ID */ +#define MAX_LUNS_COUNT 0x08 + +/* transport protocol definitions - are not bitmasks */ +#define PROTO_NONE 0x00000000 +#define PROTO_BULK_ONLY 0x00000001 +#define PROTO_CB 0x00000002 +#define PROTO_CBI 0x00000003 + +#define PROTO_VENDOR 0x0000000e +#define PROTO_MASK 0x0000000f + +#define PROTO(__value) ((__value) & PROTO_MASK) + +/* command set definitions - are not bitmasks */ +#define CMDSET_NONE 0x00000000 +#define CMDSET_SCSI 0x00000010 +#define CMDSET_UFI 0x00000020 +#define CMDSET_ATAPI 0x00000030 +#define CMDSET_RBC 0x00000040 +#define CMDSET_QIC157 0x00000050 + +#define CMDSET_VENDOR 0x000000e0 +#define CMDSET_MASK 0x000000f0 + +#define CMDSET(__value)((__value) & CMDSET_MASK) + +#define HAS_SET(__mask, __flag) \ + (((__mask) & __flag) == (__flag)) + +/* fixes - bitmasked */ +#define FIX_NO_GETMAXLUN 0x00000100 +#define FIX_FORCE_RW_TO_6 0x00000200 +#define FIX_NO_TEST_UNIT 0x00000400 +#define FIX_NO_INQUIRY 0x00000800 +#define FIX_TRANS_TEST_UNIT 0x00001000 +#define FIX_NO_PREVENT_MEDIA 0x00002000 +#define FIX_FORCE_MS_TO_10 0x00004000 +#define FIX_FORCE_READ_ONLY 0x00008000 + +#define FIX_NONE 0x00000000 +#define FIX_MASK 0x000fff00 + +#define HAS_FIXES(__value, __fix) \ + HAS_SET((__value), (__fix)) + +#endif /*_USB_SCSI_H_*/ diff --git a/src/add-ons/kernel/busses/scsi/usb/usb_scsi.settings.sample b/src/add-ons/kernel/busses/scsi/usb/usb_scsi.settings.sample new file mode 100644 index 0000000000..51c00f91c2 --- /dev/null +++ b/src/add-ons/kernel/busses/scsi/usb/usb_scsi.settings.sample @@ -0,0 +1,30 @@ +########################################################## +## +## USB Storage Module settings file +## +## This file is a part of BeOS USB SCSI interface module project. +## Copyright (c) 2003-2005 by Siarzhuk Zharski +## All rights reserved. +## +########################################################## +## This file typically placed in following directory: +## /boot/home/config/settings/kernel/drivers/ +########################################################## +## +## More details on using this settings file and +## detailed parameters reference are in the ReadMe.html +## + +#reserve_devices 2 # count of device entries reserved by this SIM. default is 2 +#reserve_luns 4 # count of LUNs available for every reserved device entry. default is 4 + +#ignore_sysinit2 true # workaround for some R5 + USB patches boot problem + +#debug_output true # activates debug output +#debug_output_in_file true # use /var/log/usb_scsi.log instead of syslog +#debug_output_file_rewrite true # truncate log file on system reboot + +#debug_trace_protocol true # dump USB MS protocol information +#debug_trace_sense_data true # dump additional USB MS protocol information +#debug_trace_capacity true # dump READ CAPACITY SCSI command results + diff --git a/src/add-ons/kernel/drivers/Jamfile b/src/add-ons/kernel/drivers/Jamfile index bc1706673d..a0fbf56faf 100644 --- a/src/add-ons/kernel/drivers/Jamfile +++ b/src/add-ons/kernel/drivers/Jamfile @@ -10,6 +10,8 @@ SubInclude HAIKU_TOP src add-ons kernel drivers graphics ; SubInclude HAIKU_TOP src add-ons kernel drivers midi ; SubInclude HAIKU_TOP src add-ons kernel drivers misc ; SubInclude HAIKU_TOP src add-ons kernel drivers network ; +SubInclude HAIKU_TOP src add-ons kernel drivers ports ; SubInclude HAIKU_TOP src add-ons kernel drivers power ; SubInclude HAIKU_TOP src add-ons kernel drivers random ; SubInclude HAIKU_TOP src add-ons kernel drivers tty ; +SubInclude HAIKU_TOP src add-ons kernel drivers video ; diff --git a/src/add-ons/kernel/drivers/audio/Jamfile b/src/add-ons/kernel/drivers/audio/Jamfile index cf2c7658b8..1f4ac62a2e 100644 --- a/src/add-ons/kernel/drivers/audio/Jamfile +++ b/src/add-ons/kernel/drivers/audio/Jamfile @@ -3,5 +3,6 @@ SubDir HAIKU_TOP src add-ons kernel drivers audio ; SubInclude HAIKU_TOP src add-ons kernel drivers audio ac97 ; SubInclude HAIKU_TOP src add-ons kernel drivers audio echo ; SubInclude HAIKU_TOP src add-ons kernel drivers audio emuxki ; -SubInclude HAIKU_TOP src add-ons kernel drivers audio usb_audio ; SubInclude HAIKU_TOP src add-ons kernel drivers audio module_driver ; +SubInclude HAIKU_TOP src add-ons kernel drivers audio sis7018 ; +SubInclude HAIKU_TOP src add-ons kernel drivers audio usb_audio ; diff --git a/src/add-ons/kernel/drivers/audio/sis7018/Jamfile b/src/add-ons/kernel/drivers/audio/sis7018/Jamfile new file mode 100644 index 0000000000..837caf6bfc --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/Jamfile @@ -0,0 +1,25 @@ +SubDir HAIKU_TOP src add-ons kernel drivers audio sis7018 ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders audio ; + +KernelAddon sis7018 : kernel drivers bin : + ac97.c + midi.c + pcm.c + sis7018.c + sis7018hw.c +; + +AddResources sis7018 : vsis7018.rdef ; + +Package haiku-sis7018-cvs + : + sis7018 + : + boot home config add-ons kernel drivers bin ; + +PackageDriverSymLink haiku-sis7018-cvs : audio sis7018 ; +Package haiku-sis7018-cvs : sis7018.settings.sample + : boot home config settings kernel drivers sample ; diff --git a/src/add-ons/kernel/drivers/audio/sis7018/ReadMe b/src/add-ons/kernel/drivers/audio/sis7018/ReadMe new file mode 100644 index 0000000000..a0a5b5bdbe --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/ReadMe @@ -0,0 +1,84 @@ +BeOS sound driver for SiS 7018 PCI Audio Accelerator + +This driver is designed to supports following chipsets: +SiS 7018 (vendor:1039 card:7018) +Trident 4D Wave DX (vendor:1023 card:2000) +Trident 4D Wave NX (vendor:1023 card:2001) - not tested +Acer Lab's M5451 (vendor:10b9 card:5451) + +What's new: +----------------------------------------------------------------------------------------------- +version 0.1.0-dev-8 +* The AC'97 codec id checking restored. +- to be continued! + +version 0.1.0-dev-7 + * Added use_io_registers to settings file. Just for testers. + * The AC'97 codec id checking bypassed - for testing purposes only + +version 0.1.0-dev-6 + * Fixed problem with "Real-time Audio". Currently works in this mode too. + +version 0.1.0-dev-5 + * Fixed AC'97 codec handling - 6bit master gain codecs schould be supported correctly + + For testing purposes added Trident DX with vendorID : 0x03 - such card found + by one tester. + +version 0.1.0-dev-4 ++ Finished some codec manipulations - mio volumes, mio mutes etc. + +version 0.1.0-dev-3 +* Fixed "last thrashed" sample problem ++ makefile and install script are fixed. + +version 0.1.0-dev-2 +* changed AC'97 initialization ++ Added settings file ++ Added possibility to write into private log file ++ More complicated AC'97 tracing possible ... + +version 0.1.0-dev-1 +* changed AC'97 initialization + +version 0.1.0-dev-0 + initial build. +----------------------------------------------------------------------------------------------- + +!!! WANTED !!! +Wanted testers with Trident NX sound hardware. Current driver is not tested on such hardware. It'll be good to asure that it work with that cards too! + +Installation +Run install.sh + +Uninstallation +Run uninstall.sh + +Problems solving +If this driver crash your system - reboot and press "Space" during load. In boot menu select "Disable user add-ons" and continue boot. Uninstall driver and reboot again into normal mode. Write me a e-mail about this problem. + +Professional testing: +If you found a problem with this driver and want to help me in development of this software make the following things (Assume that driver is already installed): + +1) Open the file /boot/home/config/settings/kernel/drivers/sis7018 and set following parameters: + +debug_output true +debug_output_in_file true + +if you have a problems with mixer - it's not work, or settings is not saved on reboot - activate this one too: + +debug_trace_ac97 true + +2) Reboot your system and try to play something. + +3) After that get the file /boot/home/sis7018.log and send it to me. + +4) It'll be good on your first bug report to me send also hardware configuration of your system. To get it go into Terminal and run following commands + +listdev + +Get all that it say to you and send me too, please ... + +Thank you !!! + +Siarzuk Zharski +http://www.zharik.host.sk/ diff --git a/src/add-ons/kernel/drivers/audio/sis7018/ac97.c b/src/add-ons/kernel/drivers/audio/sis7018/ac97.c new file mode 100644 index 0000000000..8d806b870c --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/ac97.c @@ -0,0 +1,605 @@ +/* + * This file is a part of SiS 7018 BeOS driver project. + * Copyright (c) 2002-2003 by Siarzuk Zharski + * Portional Copyright (c) 1999 Cameron Grant + * + * This file may be used under the terms of the BSD License + * See the file "License" for details. + */ +#include "sis7018.h" +#include "sis7018hw.h" +#include "t4dwave.h" +#include "ac97.h" +//#include "pcm.h" + +#define TR_TIMEOUT_CDC 0xffff + +//typedef bool (*ac97init_proc)(sis7018_dev *dev, bool bOn); +/* init functions*/ +status_t ac97init_CS4299(sis7018_dev *dev, bool bOn); +status_t ac97init_default(sis7018_dev *dev, bool bOn); + +static struct ac97_codecid +{ + uint32 id; + int noext; + char *name; + status_t (*ac97init)(sis7018_dev *dev, bool bOn); +} ac97codecid[] = { + { 0x41445303, 0, "Analog Devices AD1819", NULL }, + { 0x41445340, 0, "Analog Devices AD1881", NULL }, + { 0x41445348, 0, "Analog Devices AD1881A", NULL }, + { 0x41445360, 0, "Analog Devices AD1885", NULL }, + { 0x414b4d00, 1, "Asahi Kasei AK4540", NULL }, + { 0x414b4d01, 1, "Asahi Kasei AK4542", NULL }, + { 0x414b4d02, 1, "Asahi Kasei AK4543", NULL }, + { 0x414c4710, 0, "Avance Logic ALC200/200P", NULL }, + { 0x43525900, 0, "Cirrus Logic CS4297", NULL }, + { 0x43525903, 0, "Cirrus Logic CS4297", NULL }, + { 0x43525913, 0, "Cirrus Logic CS4297A", NULL }, + { 0x43525914, 0, "Cirrus Logic CS4297B", NULL }, + { 0x43525923, 0, "Cirrus Logic CS4294C", NULL }, + { 0x4352592b, 0, "Cirrus Logic CS4298C", NULL }, + { 0x43525931, 0, "Cirrus Logic CS4299A", ac97init_CS4299 }, + { 0x43525933, 0, "Cirrus Logic CS4299C", ac97init_CS4299 }, + { 0x43525934, 0, "Cirrus Logic CS4299D", ac97init_CS4299 }, + { 0x43525941, 0, "Cirrus Logic CS4201A", NULL }, + { 0x43525951, 0, "Cirrus Logic CS4205A", NULL }, + { 0x43525961, 0, "Cirrus Logic CS4291A", NULL }, + { 0x45838308, 0, "ESS Technology ES1921", NULL }, + { 0x49434511, 0, "ICEnsemble ICE1232", NULL }, + { 0x4e534331, 0, "National Semiconductor LM4549", NULL }, + { 0x83847600, 0, "SigmaTel STAC9700/9783/9784", NULL }, + { 0x83847604, 0, "SigmaTel STAC9701/9703/9704/9705", NULL }, + { 0x83847605, 0, "SigmaTel STAC9704", NULL }, + { 0x83847608, 0, "SigmaTel STAC9708/9711", NULL }, + { 0x83847609, 0, "SigmaTel STAC9721/9723", NULL }, + { 0x83847644, 0, "SigmaTel STAC9744", NULL }, + { 0x83847656, 0, "SigmaTel STAC9756/9757", NULL }, + { 0x53494c22, 0, "Silicon Laboratory Si3036", NULL }, + { 0x53494c23, 0, "Silicon Laboratory Si3038", NULL }, + { 0x54524103, 0, "TriTech TR?????", NULL }, + { 0x54524106, 0, "TriTech TR28026", NULL }, + { 0x54524108, 0, "TriTech TR28028", NULL }, + { 0x54524123, 0, "TriTech TR28602", NULL }, + { 0x574d4c00, 0, "Wolfson WM9701A", NULL }, + { 0x574d4c03, 0, "Wolfson WM9703/9704", NULL }, + { 0x574d4c04, 0, "Wolfson WM9704 (quad)", NULL }, + { 0, 0, NULL } +}; + +static char *ac97enhancement[] = { + "no 3D Stereo Enhancement", + "Analog Devices Phat Stereo", + "Creative Stereo Enhancement", + "National Semi 3D Stereo Enhancement", + "Yamaha Ymersion", + "BBE 3D Stereo Enhancement", + "Crystal Semi 3D Stereo Enhancement", + "Qsound QXpander", + "Spatializer 3D Stereo Enhancement", + "SRS 3D Stereo Enhancement", + "Platform Tech 3D Stereo Enhancement", + "AKM 3D Audio", + "Aureal Stereo Enhancement", + "Aztech 3D Enhancement", + "Binaura 3D Audio Enhancement", + "ESS Technology Stereo Enhancement", + "Harman International VMAx", + "Nvidea 3D Stereo Enhancement", + "Philips Incredible Sound", + "Texas Instruments 3D Stereo Enhancement", + "VLSI Technology 3D Stereo Enhancement", + "TriTech 3D Stereo Enhancement", + "Realtek 3D Stereo Enhancement", + "Samsung 3D Stereo Enhancement", + "Wolfson Microelectronics 3D Enhancement", + "Delta Integration 3D Enhancement", + "SigmaTel 3D Enhancement", + "KS Waves", + "Rockwell 3D Stereo Enhancement", + "Reserved 29", + "Reserved 30", + "Reserved 31" +}; + +static char *ac97feature[] = { + "mic channel", + "reserved", + "tone", + "simulated stereo", + "headphone", + "bass boost", + "18 bit DAC", + "20 bit DAC", + "18 bit ADC", + "20 bit ADC" +}; + +static char *ac97extfeature[] = { + "variable rate PCM", + "double rate PCM", + "reserved 1", + "variable rate mic", + "reserved 2", + "reserved 3", + "center DAC", + "surround DAC", + "LFE DAC", + "AMAP", + "reserved 4", + "reserved 5", + "reserved 6", + "reserved 7", +}; + +int ac97read(sis7018_dev *dev, int regno) +{ + cpu_status cp; + int i, j, reg, rw; + if(b_trace_ac97) + TRACE(" ac97read: regno=%x\n", regno); + + switch (dev->type->ids.chip_id){ + case SPA_PCI_ID: + reg=SPA_REG_CODECRD; + rw=SPA_CDC_RWSTAT; + break; + case ALI_PCI_ID: + if(dev->info.revision > 0x01) + reg=TDX_REG_CODECWR; + else + reg=TDX_REG_CODECRD; + rw=TDX_CDC_RWSTAT; + break; + case TDX_PCI_ID: + case xDX_PCI_ID: + reg=TDX_REG_CODECRD; + rw=TDX_CDC_RWSTAT; + break; + case TNX_PCI_ID: + reg=(regno & 0x100)? TNX_REG_CODEC2RD : TNX_REG_CODEC1RD; + rw=TNX_CDC_RWSTAT; + break; + default: + TRACE("ac97read defaulted !!!\n"); + return ENODEV; + } + + cp = disable_interrupts(); + acquire_spinlock(&dev->hardware); + + regno &= 0x7f; + + if(dev->type->ids.chip_id == ALI_PCI_ID){ + j = rw; + for (i=TR_TIMEOUT_CDC; (i > 0) && (j & rw); i--){ + j = hw_read(dev, reg, 4); + } + if(i > 0){ + uint32 c1 = hw_read(dev, 0xc8, 4); + uint32 c2 = hw_read(dev, 0xc8, 4); + for(i=TR_TIMEOUT_CDC; (i > 0) && (c1 == c2); i--){ + c2 = hw_read(dev, 0xc8, 4); + } + } + } + if(dev->type->ids.chip_id != ALI_PCI_ID || i > 0){ + hw_write(dev, reg, regno | rw, 4); + j=rw; + for (i=TR_TIMEOUT_CDC; (i > 0) && (j & rw); i--){ + j=hw_read(dev, reg, 4); + } + } + + release_spinlock(&dev->hardware); + restore_interrupts(cp); + + if (i == 0) + TRACE_ALWAYS("ac97 codec timeout during read of register %x\n", regno); + if(b_trace_ac97) + TRACE(" ac97read: regno=%x ret = %x\n", regno, j); + return (j >> TR_CDC_DATA) & 0xffff; +} + +status_t ac97write(sis7018_dev *dev, int regno, uint32 data) +{ + cpu_status cp; + int i, j, reg, rw; + + if(b_trace_ac97) + TRACE("\nac97write: regno=%x, data=%lx\n", regno, data); + + switch (dev->type->ids.chip_id){ + case SPA_PCI_ID: + reg=SPA_REG_CODECWR; + rw=SPA_CDC_RWSTAT; + break; + case ALI_PCI_ID: + case TDX_PCI_ID: + case xDX_PCI_ID: + reg=TDX_REG_CODECWR; + rw=TDX_CDC_RWSTAT; + break; + case TNX_PCI_ID: + reg=TNX_REG_CODECWR; + rw=TNX_CDC_RWSTAT | ((regno & 0x100)? TNX_CDC_SEC : 0); + break; + default: + TRACE("ac97write defaulted !!!"); + return ENODEV; + } + + regno &= 0x7f; + if(b_trace_ac97) + TRACE("ac97write: reg %x was %x\n", regno, ac97read(dev, regno)); + + cp = disable_interrupts(); + acquire_spinlock(&dev->hardware); + j=rw; + + if(dev->type->ids.chip_id == ALI_PCI_ID){ + for(i = TR_TIMEOUT_CDC; (i > 0) && (j & rw); i--){ + j = hw_read(dev, reg, 4); + } + if(i > 0) { + uint32 c1 = hw_read(dev, 0xc8, 4); + uint32 c2 = hw_read(dev, 0xc8, 4); + for (i = TR_TIMEOUT_CDC; (i > 0) && (c1 == c2); i--) + c2 = hw_read(dev, 0xc8, 4); + } + } + if(dev->type->ids.chip_id != ALI_PCI_ID || i > 0){ + for(i=TR_TIMEOUT_CDC; (i>0) && (j & rw); i--){ + j=hw_read(dev, reg, 4); + } + if(dev->type->ids.chip_id == ALI_PCI_ID && dev->info.revision > 0x01) + rw |= 0x0100; + hw_write(dev, reg, (data << TR_CDC_DATA) | regno | rw, 4); + } + + release_spinlock(&dev->hardware); + restore_interrupts(cp); + + if(b_trace_ac97) + TRACE("ac97write: wrote %x, now %x\n", data, ac97read(dev, regno)); + if (i==0) + TRACE_ALWAYS("ac97 codec timeout writing %x, data %lx\n", regno, data); + if(b_trace_ac97) + TRACE("ac97write: ret = %x\n\n", i); + return (i > 0)? B_OK : B_TIMED_OUT; +} + +status_t ac97init(sis7018_dev *card) +{ +// cpu_status cp; + status_t err=B_OK; + int i, /*j,*/ caps, se, noext, extcaps, extid, extstat, reg=0; + int32 id; +/* old manner + err |= ac97write(card, AC97_REG_POWER, 0); + err |= ac97write(card, AC97_REG_RESET, 0); + + err |= ac97write(card, AC97_MIX_PCM, 0x707); + err |= ac97write(card, AC97_MIX_BEEP, 0x06); + err |= ac97write(card, AC97_MIX_MIC, 0x8000); + err |= ac97write(card, AC97_MIX_PHONE, 0x707); + err |= ac97write(card, AC97_MIX_PHONES, 0x707); +*/ + + //BSD init manner + err |= ac97write(card, AC97_REG_POWER, 0x0000); + err |= ac97write(card, AC97_REG_RESET, 0); + snooze(100000); + //snooze(50000); + err |= ac97write(card, AC97_REG_POWER, 0x0000); + err |= ac97write(card, AC97_REG_GEN, 0x0000); + +/* Marcus's init manner*/ +// err |= ac97write(card, AC97_REG_RESET, 0); +// snooze(50000); // 50 ms + + if (err != B_OK){ + TRACE("ac97 codec resetting failed: %lx\n", err); + return ENODEV; + } + +// cp = disable_interrupts(); +// acquire_spinlock(&card->hardware); + + i = ac97read(card, AC97_REG_RESET); + caps = i & 0x03ff; + se = (i & 0x7c00) >> 10; + + id = (ac97read(card, AC97_REG_ID1) << 16) | ac97read(card, AC97_REG_ID2); +// codec->rev = id & 0x000000ff; + +// release_spinlock(&card->hardware); +// restore_interrupts(cp); +#if 1 + if (id == 0 || id == 0xffffffff){ + TRACE("ac97 codec invalid or not present (id == %lx)\n", id); + return ENODEV; + } +#endif + noext = 0; + for (i = 0; ac97codecid[i].id; i++){ + if (ac97codecid[i].id == id){ + status_t err = B_OK; + noext = ac97codecid[i].noext; + if (ac97codecid[i].name) + TRACE("\nac97 codec id 0x%08lx (%s)\n", id, ac97codecid[i].name); + if(ac97codecid[i].ac97init) + err |= (*ac97codecid[i].ac97init)(card, true); + else + err |= ac97init_default(card, true); + if(err != B_OK) + TRACE("ac97 codec initializatin error\n"); + } + } + + TRACE("ac97 codec features:\n"); + + for (i = 0; i < 10; i++) + if (caps & (1 << i)) + TRACE("> %s\n", ac97feature[i]); + TRACE("> %s\n", ac97enhancement[se]); + TRACE("\n"); + + extcaps = 0; + extid = 0; + extstat = 0; + if (!noext){ + i = ac97read(card, AC97_REGEXT_ID); + if (i != 0xffff){ + extcaps = i & 0x3fff; + extid = (i & 0xc000) >> 14; + extstat = ac97read(card, AC97_REGEXT_STAT) & AC97_EXTCAPS; + } + } + + if (extcaps != 0 || extid){ + TRACE("\nac97 %s codec %s:\n", extid? "secondary" : "primary", + extcaps? "extended features":""); + for (i = 0; i < 14; i++) + if (extcaps & (1 << i)) + TRACE("> %s\n", ac97extfeature[i]); + TRACE("\n"); + } + + if ((ac97read(card, AC97_REG_POWER) & 2) == 0) + TRACE("ac97 codec reports dac not ready\n"); + +// some addition + + reg = ac97read(card, AC97_MIX_MASTER); + err |= ac97write(card, AC97_MIX_MASTER, 0x3f3f); + if(0x3f3f == ac97read(card, AC97_MIX_MASTER)){ + TRACE("AC97 master gain is wide!\n"); + card->ac97.wide_main_gain = true; + } + err |= ac97write(card, AC97_MIX_MASTER, reg); + +// BSD manner + err |= ac97write(card, AC97_MIX_PCM, 0x707); +// err |= ac97write(card, AC97_MIX_BEEP, 0x06); +// err |= ac97write(card, AC97_MIX_MIC, 0x8000); +// err |= ac97write(card, AC97_MIX_PHONE, 0x707); +// err |= ac97write(card, AC97_MIX_PHONES, 0x707); + +/*Marcus's manner*/ + // err |= ac97write(card, AC97_MIX_MASTER, 0x00); + // err |= ac97write(card, AC97_MIX_PCM, 0x404); + + return err; +} + +status_t ac97get_params(sis7018_dev *dev, sound_setup *sound) +{ + uint16 reg = 0; + int main_gain_multiplier = dev->ac97.wide_main_gain ? 1 : 2; + + sound->sample_rate = kHz_48_0; + sound->dither_enable = false; + sound->output_boost = 0; + sound->highpass_enable = 0; + + reg=ac97read(dev, AC97_MIX_MONO); + sound->mono_gain = (char)reg; + sound->mono_mute = (char)(reg & AC97_MUTE) ? 1 : 0; + + reg=ac97read(dev, AC97_REG_RECSEL); + switch (reg&0x07){ + case 4: sound->right.adc_source = line; break; + case 3: sound->right.adc_source = aux1; break; + case 0: sound->right.adc_source = mic; break; + default: sound->right.adc_source = loopback; break; + } + + switch ((reg >> 8) & 0x07){ + case 4: sound->left.adc_source = line; break; + case 3: sound->left.adc_source = aux1; break; + case 0: sound->left.adc_source = mic; break; + default: sound->left.adc_source = loopback; break; + } + + reg = ac97read(dev, AC97_MIX_MIC); + sound->loop_attn = (reg & 0x1f)*2; + sound->loop_enable = (reg & AC97_MUTE) ? 0 : 1; + sound->left.mic_gain_enable = + sound->right.mic_gain_enable = (reg >> 6) & 0x01; + + reg = ac97read(dev, AC97_MIX_RGAIN); + sound->left.adc_gain = (reg >> 0x8) & 0xf; + sound->right.adc_gain = reg & 0xf; + + reg = ac97read(dev, AC97_MIX_CD); + sound->left.aux1_mix_gain = ((reg >> 8) & 0x1f); + sound->right.aux1_mix_gain = (reg & 0x1f); + sound->left.aux1_mix_mute = + sound->right.aux1_mix_mute = (reg & AC97_MUTE) ? 1 : 0; + + reg = ac97read(dev, AC97_MIX_AUX); + sound->left.aux2_mix_gain = ((reg >> 8) & 0x1f); + sound->right.aux2_mix_gain = (reg & 0x1f); + sound->left.aux2_mix_mute = + sound->right.aux2_mix_mute = (reg & AC97_MUTE) ? 1 : 0; + + + reg = ac97read(dev, AC97_MIX_LINE); + sound->left.line_mix_gain = ((reg >> 8) & 0x1f); + sound->right.line_mix_gain = (reg & 0x1f); + sound->left.line_mix_mute = + sound->right.line_mix_mute = (reg & AC97_MUTE) ? 1 : 0; + + reg = ac97read(dev, AC97_MIX_MASTER); + sound->left.dac_attn = ((reg >> 8) & 0x1f) * main_gain_multiplier; + sound->right.dac_attn = (reg & 0x1f) * main_gain_multiplier; + sound->left.dac_mute = + sound->right.dac_mute = (reg & AC97_MUTE) ? 1 : 0; + + return B_OK; +} + +status_t ac97set_params(sis7018_dev *dev, sound_setup * sound) +{ + status_t err = B_OK; + uint16 reg = 0; + int main_gain_divider = dev->ac97.wide_main_gain ? 1 : 2; + +#if 0 //DEBUG + TRACE("\nsound setup (left/right)\n"); + TRACE("adc_source %x/%x\n", sound->left.adc_source, sound->right.adc_source); + TRACE("adc_gain %x/%x\n", sound->left.adc_gain, sound->right.adc_gain); + TRACE("mic_gain_enable %x/%x\n", sound->left.mic_gain_enable, sound->right.mic_gain_enable); + TRACE("aux1_mix_gain %x/%x\n", sound->left.aux1_mix_gain, sound->right.aux1_mix_gain); + TRACE("aux1_mix_mute %x/%x\n", sound->left.aux1_mix_mute, sound->right.aux1_mix_mute); + TRACE("aux2_mix_gain %x/%x\n", sound->left.aux2_mix_gain, sound->right.aux2_mix_gain); + TRACE("aux2_mix_mute %x/%x\n", sound->left.aux2_mix_mute, sound->right.aux2_mix_mute); + TRACE("line_mix_gain %x/%x\n", sound->left.line_mix_gain, sound->right.line_mix_gain); + TRACE("line_mix_mute %x/%x\n", sound->left.line_mix_mute, sound->right.line_mix_mute); + TRACE("dac_attn %x/%x\n", sound->left.dac_attn, sound->right.dac_attn); + TRACE("dac_mute %x/%x\n", sound->left.dac_mute, sound->right.dac_mute); + TRACE("sound setup\n"); + TRACE("sample_rate %x\n", sound->sample_rate); + TRACE("playback_format %x\n", sound->playback_format); + TRACE("capture_format %x\n", sound->capture_format); + TRACE("dither_enable %x\n", sound->dither_enable); + TRACE("loop_attn %x\n", sound->loop_attn); + TRACE("loop_enable %x\n", sound->loop_enable); + TRACE("output_boost %x\n", sound->output_boost); + TRACE("highpass_enable %x\n", sound->highpass_enable); + TRACE("mono_gain %x\n", sound->mono_gain); + TRACE("mono_mute %x\n", sound->mono_mute); +#endif +//TRACE("sample-rate:%d\n", sound->sample_rate); + sound->sample_rate = kHz_48_0; + sound->dither_enable = false; + sound->output_boost = 0; + sound->highpass_enable = 0; + + reg = sound->mono_gain | ((sound->mono_mute) ? AC97_MUTE : 0); + err |= ac97write(dev, AC97_MIX_MONO, reg); + + reg = sound->loop_attn / 2; + reg |= ((sound->left.mic_gain_enable || sound->right.mic_gain_enable) ? 0x01 : 0x00) << 6; + reg |= (sound->loop_enable) ? 0 : AC97_MUTE; + err |= ac97write(dev, AC97_MIX_MIC, reg); + + reg = 0; + switch(sound->left.adc_source){ + case line: reg = 4; break; + case aux1: reg = 3; break; + case mic: reg = 0; break; + default: reg = 0; break; + } + + reg <<= 8; + switch(sound->right.adc_source){ + case line: reg |= 4; break; + case aux1: reg |= 3; break; + case mic: reg |= 0; break; + default: reg |= 0; break; + } + + err |= ac97write(dev, AC97_REG_RECSEL, reg); + + reg = (sound->left.adc_gain) << 8; + reg |= sound->right.adc_gain; + err |= ac97write(dev, AC97_MIX_RGAIN, reg); + + reg = (sound->left.aux1_mix_gain) << 0x08; + reg |= sound->right.aux1_mix_gain; + reg |= (sound->left.aux1_mix_mute || sound->right.aux1_mix_mute) ? AC97_MUTE : 0 ; + err |= ac97write(dev, AC97_MIX_CD, reg); + + reg = (sound->left.aux2_mix_gain) << 0x08; + reg |= sound->right.aux2_mix_gain; + reg |= (sound->left.aux2_mix_mute || sound->right.aux2_mix_mute) ? AC97_MUTE : 0 ; + err |= ac97write(dev, AC97_MIX_AUX, reg); + + reg = (sound->left.line_mix_gain) << 0x08; + reg |= sound->right.line_mix_gain; + reg |= (sound->left.line_mix_mute || sound->right.line_mix_mute) ? AC97_MUTE : 0 ; + err |= ac97write(dev, AC97_MIX_LINE, reg); + + reg = ((sound->left.dac_attn) / main_gain_divider) << 0x08; + reg |= (sound->right.dac_attn) / main_gain_divider; + reg |= (sound->left.dac_mute || sound->right.dac_mute) ? AC97_MUTE : 0 ; + err |= ac97write(dev, AC97_MIX_MASTER, reg); + + return err; +} + +status_t ac97init_default(sis7018_dev *dev, bool bOn) +{ + status_t err = B_OK; + //TRACE("powerdown register was = %#04x\n",ich_codec_read(AC97_POWERDOWN))); +// if (bOn) +// ac97write(dev, AC97_REG_POWER, ac97read(dev, AC97_REG_POWER) & ~0x8000); /* switch on (low active) */ +// else +// ac97write(dev, AC97_REG_POWER, ac97read(dev, AC97_REG_POWER) | 0x8000); /* switch off */ + //LOG(("powerdown register is = %#04x\n",ich_codec_read(AC97_POWERDOWN))); + return err; +} + +status_t ac97init_CS4299(sis7018_dev *dev, bool bOn) +{ + status_t err = B_OK; + TRACE("Use CS4299 init\n"); + // if (bOn) +// err |= ac97write(dev, 0x68, 0x8004); +// else +// err |= ac97write(dev, 0x68, 0); + return err; +} + +#if DEBUG +static struct +{ + int16 reg; + char name[DEVNAME]; +} ac97_regs[]= +{ + {AC97_REG_RESET, "Reset"}, {AC97_MIX_MASTER, "Master Volume"}, + {AC97_MIX_PHONES, "AUX Out volume"}, {AC97_MIX_MONO, "Mono Volume"}, + {AC97_MIX_TONE, "Master Tone"}, {AC97_MIX_BEEP, "PC Beep"}, + {AC97_MIX_PHONE, "Phone volume"}, {AC97_MIX_MIC, "Mio Volume"}, + {AC97_MIX_LINE, "Line In Volume"}, {AC97_MIX_CD, "CD Volume"}, + {AC97_MIX_VIDEO, "Video Volume"}, {AC97_MIX_AUX, "AUX In Volume"}, + {AC97_MIX_PCM, "PCM Out Volume"}, {AC97_REG_RECSEL, "Record Select"}, + {AC97_MIX_RGAIN, "Record Gain"}, {AC97_MIX_MGAIN, "Record Gain Mio"}, + {AC97_REG_GEN, "General Purpose"}, {AC97_REG_3D, "3D Control"}, + {0x24, "Audio Int & Paging"}, {AC97_REG_POWER, "Powerdown Ctrl/Stat"}, + {AC97_REG_ID1, "Vendor ID1"}, {AC97_REG_ID2, "VendorID 2"}, +}; + +void ac97dump(int card_id) +{ + int i; + for(i=0; i < sizeof(ac97_regs)/sizeof(ac97_regs[0]); i++) + kprintf("%s : %x\n", ac97_regs[i].name, ac97read(&cards[card_id], ac97_regs[i].reg)); +} + +#endif //DEBUG + diff --git a/src/add-ons/kernel/drivers/audio/sis7018/ac97.h b/src/add-ons/kernel/drivers/audio/sis7018/ac97.h new file mode 100644 index 0000000000..efad1729a2 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/ac97.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1999 Cameron Grant + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/sound/pcm/ac97.h,v 1.3.2.5 2001/08/01 03:41:03 cg Exp $ + */ + +/* + * This file is a part of SiS 7018 BeOS driver project. + * Copyright permissions see above. + * + * Portion copyright (c) 2002-2003 by Siarzuk Zharski + * + * $Source: /cvsroot/sis4be/sis7018/ac97.h,v $ + * $Author: zharik $ + * $Revision: 1.4 $ + * $Date: 2003/04/08 19:18:37 $ + */ + +#define AC97_MUTE 0x8000 + +#define AC97_REG_RESET 0x00 +#define AC97_MIX_MASTER 0x02 +#define AC97_MIX_PHONES 0x04 +#define AC97_MIX_MONO 0x06 +#define AC97_MIX_TONE 0x08 +#define AC97_MIX_BEEP 0x0a +#define AC97_MIX_PHONE 0x0c +#define AC97_MIX_MIC 0x0e +#define AC97_MIX_LINE 0x10 +#define AC97_MIX_CD 0x12 +#define AC97_MIX_VIDEO 0x14 +#define AC97_MIX_AUX 0x16 +#define AC97_MIX_PCM 0x18 +#define AC97_REG_RECSEL 0x1a +#define AC97_MIX_RGAIN 0x1c +#define AC97_MIX_MGAIN 0x1e +#define AC97_REG_GEN 0x20 +#define AC97_REG_3D 0x22 +#define AC97_REG_POWER 0x26 +#define AC97_REGEXT_ID 0x28 +#define AC97_EXTCAP_VRA (1 << 0) +#define AC97_EXTCAP_DRA (1 << 1) +#define AC97_EXTCAP_VRM (1 << 3) +#define AC97_EXTCAPS (AC97_EXTCAP_VRA | AC97_EXTCAP_DRA | AC97_EXTCAP_VRM) +#define AC97_REGEXT_STAT 0x2a +#define AC97_REGEXT_FDACRATE 0x2c +#define AC97_REGEXT_SDACRATE 0x2e +#define AC97_REGEXT_LDACRATE 0x30 +#define AC97_REGEXT_LADCRATE 0x32 +#define AC97_REGEXT_MADCRATE 0x34 +#define AC97_MIXEXT_CLFE 0x36 +#define AC97_MIXEXT_SURROUND 0x38 +#define AC97_REG_ID1 0x7c +#define AC97_REG_ID2 0x7e + +/* Added by S.Zharski*/ + +status_t ac97init(sis7018_dev *dev); + +int ac97read(sis7018_dev *dev, int regno); +status_t ac97write(sis7018_dev *dev, int regno, uint32 data); + +status_t ac97get_params(sis7018_dev *dev, sound_setup *sound); +status_t ac97set_params(sis7018_dev *dev, sound_setup *sound); + +void ac97dump(int card_id); + +/* +Siarzhuk Zharski: Following not needed in BeOS build. =-) +*/ +/*#define AC97_F_EAPD_INV 0x00000001 + +#define AC97_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, sizeof(struct kobj)) +#define AC97_CREATE(dev, devinfo, cls) ac97_create(dev, devinfo, &cls ## _class) + +struct ac97_info; + +#include "ac97_if.h" + +extern kobj_class_t ac97_getmixerclass(void); + +struct ac97_info *ac97_create(device_t dev, void *devinfo, kobj_class_t cls); +void ac97_destroy(struct ac97_info *codec); +void ac97_setflags(struct ac97_info *codec, u_int32_t val); +u_int32_t ac97_getflags(struct ac97_info *codec); +int ac97_setrate(struct ac97_info *codec, int which, int rate); +int ac97_setextmode(struct ac97_info *codec, u_int16_t mode); +u_int16_t ac97_getextmode(struct ac97_info *codec); +u_int16_t ac97_getextcaps(struct ac97_info *codec); +*/ diff --git a/src/add-ons/kernel/drivers/audio/sis7018/install.sh b/src/add-ons/kernel/drivers/audio/sis7018/install.sh new file mode 100644 index 0000000000..901616bdb7 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/install.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +answer=`alert "Do you really want to install the SiS 7018 driver?" "No" "Yes"` +if [ $answer == "No" ]; then + exit +fi + +/boot/beos/bin/install -d ~/config/add-ons/kernel/drivers/bin/ +/boot/beos/bin/install -d ~/config/settings/kernel/drivers/ +/boot/beos/bin/install -d ~/config/add-ons/kernel/drivers/dev/audio/old/ +/boot/beos/bin/install `dirname $0`/sis7018 ~/config/add-ons/kernel/drivers/bin/ +/boot/beos/bin/cp `dirname $0`/sis7018.settings.sample ~/config/settings/kernel/drivers/sis7018 + +mimeset ~/config/add-ons/kernel/drivers/bin/sis7018 +mimeset ~/config/settings/kernel/drivers/sis7018 + +ln -sf ../../../bin/sis7018 ~/config/add-ons/kernel/drivers/dev/audio/old/sis7018 + +alert "The SiS 7018 driver is installed in your system. + +Go to Preferences->Media and restart media services to activate driver." diff --git a/src/add-ons/kernel/drivers/audio/sis7018/midi.c b/src/add-ons/kernel/drivers/audio/sis7018/midi.c new file mode 100644 index 0000000000..1e3a79d042 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/midi.c @@ -0,0 +1,176 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +/* + * This file is a part of SiS 7018 BeOS driver project. + * Copyright permissions see above. + * + * Portion copyright (c) 2002-2003 by Siarzuk Zharski + */ + +//#include +//#include +//#include + +#include "sis7018.h" +#include "sis7018hw.h" +#include "midi_driver.h" +#include "midi.h" + +generic_mpu401_module *mpu401; + +//extern void dump_card(sonic_vibes_dev * card); + +#if !defined(_KERNEL_EXPORT_H) +#include +#endif /* _KERNEL_EXPORT_H */ + +//#define MIDI_ACTIVE_SENSE 0xfe +//#define SNOOZE_GRANULARITY 500 + +//extern generic_mpu401_module * mpu401; + +void midi_interrupt_op(int32 op, void * data) +{ + midi_dev * port = (midi_dev *)data; + TRACE("port = %p\n", port); + if (op == B_MPU_401_ENABLE_CARD_INT) + { + cpu_status cp; + TRACE("B_MPU_401_ENABLE_CARD_INT\n"); + cp = disable_interrupts(); + acquire_spinlock(&port->card->hardware); + hw_increment_interrupt_handler(port->card); + //set_direct(port->card, 0x01, 0x00, 0x80); + //set_indirect(port->card, 0x2A, 0x04, 0xff); + release_spinlock(&port->card->hardware); + restore_interrupts(cp); + } + else if (op == B_MPU_401_DISABLE_CARD_INT) + { + /* turn off MPU interrupts */ + cpu_status cp; + TRACE("B_MPU_401_DISABLE_CARD_INT\n"); + cp = disable_interrupts(); + acquire_spinlock(&port->card->hardware); + //set_direct(port->card, 0x01, 0x80, 0x80); + /* remove interrupt handler if necessary */ + hw_decrement_interrupt_handler(port->card); + release_spinlock(&port->card->hardware); + restore_interrupts(cp); + } + TRACE("midi_interrupt_op() done\n"); +} + +static status_t midi_open(const char *name, uint32 flags, void **cookie); +static status_t midi_close(void *cookie); +static status_t midi_free(void *cookie); +static status_t midi_control(void *cookie, uint32 op, void *data, size_t len); +static status_t midi_read(void *cookie, off_t pos, void *data, size_t *len); +static status_t midi_write(void *cookie, off_t pos, const void *data, size_t *len); + + +device_hooks midi_hooks = { + &midi_open, + &midi_close, + &midi_free, + &midi_control, + &midi_read, + &midi_write, + NULL, /* select */ + NULL, /* deselect */ + NULL, /* readv */ + NULL /* writev */ +}; + +static status_t midi_open(const char * name, uint32 flags, void ** cookie) +{ + int ix; + int ret; + + TRACE("midi_open()\n"); + + *cookie = NULL; + for (ix=0; ix= num_cards) + { + TRACE("bad device\n"); + return ENODEV; + } + + TRACE("mpu401: %p open(): %p driver: %p\n", mpu401, mpu401->open_hook, cards[ix].midi.driver); + ret = (*mpu401->open_hook)(cards[ix].midi.driver, flags, cookie); + if (ret >= B_OK) + { + cards[ix].midi.cookie = *cookie; + atomic_add(&cards[ix].midi.count, 1); + } + TRACE("mpu401: open returns %x / %p\n", ret, *cookie); + return ret; +} + +static status_t midi_close(void * cookie) +{ + TRACE("midi_close()\n"); + return (*mpu401->close_hook)(cookie); +} + +static status_t midi_free(void * cookie) +{ + int ix; + status_t f; + TRACE("midi_free()\n"); + f = (*mpu401->free_hook)(cookie); + for (ix=0; ixcontrol_hook)(cookie, iop, data, len); +} + +static status_t midi_read( void * cookie, off_t pos, void * ptr, size_t * nread) +{ + TRACE("midi_read\n"); + return (*mpu401->read_hook)(cookie, pos, ptr, nread); +} + +static status_t midi_write(void * cookie, off_t pos, const void * ptr, size_t * nwritten) +{ + TRACE("midi_write\n"); + return (*mpu401->write_hook)(cookie, pos, ptr, nwritten); +} + +bool midi_interrupt( sis7018_dev * dev) +{ + if (!dev->midi.driver) + { +// kprintf("aiigh\n"); + return false; + } + kprintf("midi_interrupt\n"); + return (*mpu401->interrupt_hook)(dev->midi.driver); +} + diff --git a/src/add-ons/kernel/drivers/audio/sis7018/midi.h b/src/add-ons/kernel/drivers/audio/sis7018/midi.h new file mode 100644 index 0000000000..6ee6616bdd --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/midi.h @@ -0,0 +1,19 @@ +/* + * This file is a part of SiS 7018 BeOS driver project. + * Copyright (c) 2002-2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * See the file "License" for details. + */ + +#ifndef _MIDI_H_ + #define _MIDI_H_ + +#ifndef _DRIVERS_H + #include +#endif //_DRIVERS_H + +extern device_hooks midi_hooks; +void midi_interrupt_op(int32 op, void * data); +extern generic_mpu401_module *mpu401; +#endif //_MIDI_H_ diff --git a/src/add-ons/kernel/drivers/audio/sis7018/midi_driver.h b/src/add-ons/kernel/drivers/audio/sis7018/midi_driver.h new file mode 100644 index 0000000000..2d0eff4355 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/midi_driver.h @@ -0,0 +1,117 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +/* + * This file is a part of SiS 7018 BeOS driver project. + * Copyright permissions see above. + * + * Portion copyright (c) 2002-2003 by Siarzuk Zharski + */ + +#ifndef _MIDI_DRIVER_H +#define _MIDI_DRIVER_H + +#include +#include + +/* ----- + ioctl codes +----- */ + +/* the old opcodes are deprecated, and may or may not work + in newer drivers */ +enum { + B_MIDI_GET_READ_TIMEOUT = B_MIDI_DRIVER_BASE, + B_MIDI_SET_READ_TIMEOUT, + B_MIDI_TIMED_READ, + B_MIDI_TIMED_WRITE, + B_MIDI_WRITE_SYNC, + B_MIDI_WRITE_CLEAR, + B_MIDI_GET_READ_TIMEOUT_OLD = B_DEVICE_OP_CODES_END + 1, + B_MIDI_SET_READ_TIMEOUT_OLD +}; + +/* the default timeout when you open a midi driver */ +#define B_MIDI_DEFAULT_TIMEOUT 1000000000000000LL + +/* Usage: + To read, set "data" to a pointer to your buffer, and "size" to the + maximum size of this buffer. On return, "when" will contain the time + at which the data was received (first byte) and "size" will contain + the actual amount of data read. + Call ioctl(fd, B_MIDI_TIMED_READ, &midi_timed_data, sizeof(midi_timed_data)); + To write, set "when" to when you want the first byte to go out the + wire, set "data" to point to your data, and set "size" to the size + of your data. + Call ioctl(fd, B_MIDI_TIMED_WRITE, &midi_timed_data, sizeof(midi_timed_data)); +*/ +typedef struct { + bigtime_t when; + size_t size; + unsigned char * data; +} midi_timed_data; + + +/* The MIDI parser returns the number of bytes that a message contains, given the */ +/* initial byte. For some messages, this is not known until the second byte is seen. */ +/* For such messages, a state > 0 is returned as well as some count > 0. When state */ +/* is > 0, you should call (*parse) for the next byte as well, which might modify */ +/* the returned message size. Message size will always be returned with the current */ +/* byte being counted as byte 1. A return of 0 means that the byte initiates a new */ +/* message. SysX is handled by returning max_size until the end or next initial message */ +/* is seen. So your loop looks something like: */ +/* + uint32 state = 0; // Only set this to 0 the first time you call the parser. + // preserve the 'state' between invocations of your read() hook. + int todo = 0; + unsigned char * end = in_buf+buf_size + unsigned char * out_buf = in_buf; + while (true) { + uchar byte = read_midi(); + if (!todo || state) { + todo = (*parser->parse)(&state, byte, end-out_buf); + } + if (todo < 1) { + unput_midi(byte); + } else { + *(out_buf++) = byte; + todo--; + } + if (todo < 1 || out_buf >= end) { + received_midi_message(in_buf, out_buf-in_buf); + todo = 0; + } + } + */ + +#define B_MIDI_PARSER_MODULE_NAME "media/midiparser/v1" + +typedef struct _midi_parser_module_info { + module_info minfo; + int (*parse)(uint32 * state, uchar byte, size_t max_size); + int _reserved_; +} midi_parser_module_info; + +#define B_MPU_401_MODULE_NAME "generic/mpu401/v1" + +enum { + B_MPU_401_ENABLE_CARD_INT = 1, + B_MPU_401_DISABLE_CARD_INT +}; +typedef struct _generic_mpu401_module { + module_info minfo; + status_t (*create_device)(int port, void ** out_storage, uint32 workarounds, void (*interrupt_op)(int32 op, void * card), void * card); + status_t (*delete_device)(void * storage); + status_t (*open_hook)(void * storage, uint32 flags, void ** out_cookie); + status_t (*close_hook)(void * cookie); + status_t (*free_hook)(void * cookie); + status_t (*control_hook)(void * cookie, uint32 op, void * data, size_t len); + status_t (*read_hook)(void * cookie, off_t pos, void * data, size_t * len); + status_t (*write_hook)(void * cookie, off_t pos, const void * data, size_t * len); + bool (*interrupt_hook)(void * cookie); + int _reserved_; +} generic_mpu401_module; + +#endif diff --git a/src/add-ons/kernel/drivers/audio/sis7018/pcm.c b/src/add-ons/kernel/drivers/audio/sis7018/pcm.c new file mode 100644 index 0000000000..b9378b87e2 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/pcm.c @@ -0,0 +1,479 @@ +/* + * This file is a part of SiS 7018 BeOS driver project. + * Copyright (c) 2002-2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * See the file "License" for details. + */ +#include "pcm.h" +#include "sis7018.h" +#include "sis7018hw.h" // ioctl definitions +#include "sound.h" +#include "ac97.h" +#include "R3MediaDefs.h" // sound_buffer definition +#include "t4dwave.h" + +#if DEBUG +int32 int_cnt; +int32 put_cnt; +bigtime_t the_time; +#endif + +/* pcm_open - handle open() calls */ +static status_t pcm_open (const char *name, uint32 flags, void** cookie) +{ + int ix; + pcm_dev *port = NULL; + + TRACE("pcm_open(%s, %lx)\n", name, flags); + + *cookie = NULL; + for (ix=0; ixinit_sem); + + if (atomic_add(&port->open_count, 1) == 0) + { + TRACE("pcm_open: first open\n"); + port->card = &cards[ix]; + + port->open_mode = (flags & O_RWMASK); + if (port->open_mode != O_RDONLY) + ;// TODO start playback "dma" + + if (port->open_mode != O_WRONLY) + ;//TODO start record "dma" + + port->old_cap_sem = -1; + port->old_play_sem = -1; + + hw_pchannel_init(port); + hw_increment_interrupt_handler(port->card); + } + else + { + if ((flags & O_RWMASK) == O_RDWR) + { + if (port->open_mode == O_RDONLY) + ; //TODO start playback "dma" + else + if (port->open_mode == O_WRONLY) + ; //TODO start record "dma" + port->open_mode = O_RDWR; + } + TRACE("pcm_open: next opens\n"); + } + + hw_start(port); + + release_sem(port->init_sem); + + return B_OK; +} + +/* pcm_read - handle read() calls */ +static status_t pcm_read (void* cookie, off_t position, void *buf, size_t* num_bytes) +{ + pcm_dev * port = (pcm_dev *)cookie; + + if (port->open_mode == O_WRONLY) + return EPERM; + +// TRACE("pcm_read(%p, %d, %p, %d)\n", cookie, position, buf, *num_bytes); + *num_bytes = 0; /* tell caller nothing was read */ + return B_IO_ERROR; +} + +extern int intrs; + +static status_t pcm_write(void * cookie, off_t pos, const void * data, size_t * nwritten) +{ + pcm_dev * port = (pcm_dev *)cookie; + sis7018_ch *ch = &((pcm_dev *)cookie)->play_channel; + status_t err; + cpu_status cp; + int written = 0; + int to_write = *nwritten; /* in play bytes, not input bytes! */ + int block; + int bytes_xferred; + + if (port->open_mode == O_RDONLY) + return EPERM; + + *nwritten = 0; + + if ((err = acquire_sem_etc(ch->wr_entry, 1, B_CAN_INTERRUPT, 0)) < B_OK) + { + TRACE("wr_entry acquisition failed\n"); + return err; + } + atomic_add(&ch->write_waiting, 1); + + while (to_write > 0) + { + /* wait to write */ + if ((err = acquire_sem_etc(ch->write_sem, 1, B_CAN_INTERRUPT, 0)) < B_OK) + { + TRACE("write_sem acquisition failed\n"); + release_sem(ch->wr_entry); + return err; + } + +#if DEBUG + put_cnt++; + { + bigtime_t delta = system_time() - the_time; + if (delta < 1) { + TRACE("delta %Ld (low!) #%ld\n", delta, put_cnt); + } + else if (delta > 2000) { + TRACE("delta %Ld (high!) #%ld\n", delta, put_cnt); + } + } + if (put_cnt != int_cnt) { + static int last; + if (last != int_cnt-put_cnt) + TRACE("%ld mismatch\n", int_cnt-put_cnt); + last = int_cnt-put_cnt; + } +#endif /* DEBUG */ + + // KTRACE(); + cp = disable_interrupts(); + acquire_spinlock(&ch->wr_lock); + + block = ch->wr_size-ch->was_written; + if (block > to_write) + { + /* must let next guy in */ + if (atomic_add(&ch->write_waiting, -1) > 0) + release_sem_etc(ch->write_sem, 1, B_DO_NOT_RESCHEDULE); + else + atomic_add(&ch->write_waiting, 1); /* undo damage */ + + block = to_write; + } + else + if (block < to_write) + atomic_add(&ch->write_waiting, 1); /* we will loop back */ + + /* switch (port->config.format) + {*/ + // case 0x24: /* floats */ + /* copy_float_to_short((short *)(port->wr_cur+port->was_written), (const float *)data, + block, !B_HOST_IS_LENDIAN == !port->config.big_endian); + bytes_xferred = block * 2; + break; */ + // case 0x02: /* shorts */ + // if (!B_HOST_IS_LENDIAN == !port->config.big_endian) { + /* we need to swap */ + /* swap_copy((short *)(port->wr_cur+port->was_written), (const short *)data, block); + bytes_xferred = block; + break; + } + */ /* else fall through to default case */ + // case 0x11: /* bytes */ + // default: +// my_copy((short *)(ch->wr_cur+ch->was_written), (const short *)data, block); + memcpy((void *)(ch->wr_cur+ch->was_written), data, block); + bytes_xferred = block; + /* break; + }*/ + ch->was_written += block; + ch->wr_silence = 0; + + release_spinlock(&ch->wr_lock); + restore_interrupts(cp); + +#if DEBUG + if(ch->wr_cur == ch->wr_cur_prv) + { + int tt = (system_time() - ch->time_prv)/1000; + TRACE("%d ms block - %x, to_write: %x ,size: %x,was_written: %x\n", tt, block, to_write, ch->wr_size, ch->was_written); + ch->time_prv = system_time(); + } + + ch->wr_cur_prv = ch->wr_cur; +#endif + + data = ((char *)data)+bytes_xferred; + written += bytes_xferred; + to_write -= block; + } + + *nwritten = written; + release_sem(ch->wr_entry); + + return B_OK; +} + +bool playback_interrupt(sis7018_ch * ch, bool bHalf) +{ + bool ret = false; +// pcm_dev * port = &dev->pcm; +// sis7018_ch *ch = &dev->pcm.play_channel; + volatile uchar * ptr; +// uint32 addr; + uint32 offs; + bigtime_t st = system_time(); +// int32 ww; +// sis7018_ch ch2 = *ch; + +#if 0 +ddprintf(("sonic_vibes: dma_a 0x%x+0x%x\n", PCI_IO_RD_32((int)port->dma_c), PCI_IO_RD_32((int)port->dma_c+4))); +#endif +// KTRACE(); /* */ + acquire_spinlock(&ch->wr_lock); + + if (ch->write_sem < 0) + { + dprintf("spurious play interrupt!\n"); + release_spinlock(&ch->wr_lock); + return false; + } + /* copy possible silence into playback buffer */ + + if (ch->was_written > 0 && ch->was_written < ch->wr_size) + // { +/* if (port->config.format == 0x11) + { + memset((void *)(port->wr_cur+port->was_written), 0x80, port->wr_size-port->was_written); + } + else {*/ + memset((void *)(ch->wr_cur+ch->was_written), 0, ch->wr_size-ch->was_written); + // } +// } + + /* because the system may be lacking and not hand us the */ + /* interrupt in time, we check which half is currently being */ + /* played, and set the pointer to the other half */ + +// addr = PCI_IO_RD_32((uint32)port->dma_a); +// if ((offs = addr-(uint32)port->card->low_phys) < port->wr_size) +// hw_rdch(&ch2); + + // select channel ... + offs = hw_read(ch->card, TR_REG_CIR, 4); + offs &= ~TR_CIR_MASK; + offs |= ch->index & 0x3f; + hw_write(ch->card, TR_REG_CIR, offs, 4); + + // read current cso + switch(ch->card->type->ids.chip_id) + { + case SPA_PCI_ID: + case ALI_PCI_ID: + case TDX_PCI_ID: + case xDX_PCI_ID: + offs=((hw_read(ch->card, TR_REG_CHNBASE, 4) & 0xffff0000) >> 16) * 4; + break; + case TNX_PCI_ID: + offs=(hw_read(ch->card, TR_REG_CHNBASE, 4) & 0x00ffffff) * 4; + break; + } + + if (offs < ch->wr_size) + ptr = ch->wr_2; + else + ptr = ch->wr_1; + + ch->wr_total += ch->mem_size/2; + /* compensate for interrupt latency */ + /* assuming 4 byte frames */ + ch->wr_time = st-(offs&(ch->mem_size/2-1))*250000LL/(int64)48000; + +/* if ((ww = atomic_add(&ch->wr_time_wait, -1)) > 0) + { + release_sem_etc(ch->wr_time_sem, 1, B_DO_NOT_RESCHEDULE); + ret = true; + } + else + { +*/// atomic_add(&ch->wr_time_wait, 1); /* re-set to 0 */ +// } + + if (ch->wr_cur == ptr) + { + ch->wr_skipped++; + dprintf("write skipped %ld\n", ch->wr_skipped); + } + + ch->wr_cur = ptr; + ch->was_written = 0; + + /* check for client there to write into buffer */ + + if (atomic_add(&ch->write_waiting, -1) > 0) + { +#if DEBUG + int_cnt++; + the_time = st; +#endif + release_sem_etc(ch->write_sem, 1, B_DO_NOT_RESCHEDULE); + ret = true; + } + else + { + atomic_add(&ch->write_waiting, 1); + /* if none there, fill with silence */ + if (ch->wr_silence < ch->mem_size) + { + /* if (port->config.format == 0x11) { + memset((void *)ptr, 0x80, port->wr_size); + } + else {*/ + memset((void *)ptr, 0, ch->wr_size); + //} + ch->wr_silence += ch->wr_size; + } + } + /* copying will be done in user thread */ + + release_spinlock(&ch->wr_lock); + return ret; +} + +/* pcm_control - handle ioctl calls */ +static status_t pcm_control (void* cookie, uint32 op, void* arg, size_t len) +{ + status_t err = B_BAD_VALUE; + pcm_dev * port = (pcm_dev *)cookie; +// TRACE("pcm_control(%p, %lx)\n", cookie, op); + switch (op) + { + case SOUND_GET_PARAMS: + // TRACE("SOUND_GET_PARAMS\n"); + err = ac97get_params(port->card, (sound_setup *)arg); + break; + case SOUND_SET_PARAMS: + // TRACE("SOUND_SET_PARAMS\n"); + err = ac97set_params(port->card, (sound_setup *)arg); + break; + case SOUND_SET_PLAYBACK_COMPLETION_SEM: + // TRACE("SOUND_SET_PLAYBACK_COMPLETION_SEM\n"); + port->old_play_sem = *(sem_id *)arg; + err = B_OK; + break; + case SOUND_SET_CAPTURE_COMPLETION_SEM: + // TRACE("SOUND_SET_CAPTURE_COMPLETION_SEM\n"); + port->old_cap_sem = *(sem_id *)arg; + err = B_OK; + break; + case SOUND_UNSAFE_WRITE: + { + sis7018_ch *ch = &((sis7018_dev *)cookie)->pcm.play_channel; + audio_buffer_header * buf = (audio_buffer_header *)arg; + size_t n = buf->reserved_1-sizeof(*buf); + //TRACE("%ld %ld %ld %ld\n", buf->reserved_1, buf->reserved_2, buf->sample_clock, buf->time ); + //TRACE("SOUND_UNSAFE_WRITE %d\n", n); + err = pcm_write(cookie, 0, buf+1, &n); + buf->time = ch->wr_time; + buf->sample_clock = ch->wr_total/4 * 1000 / 48; + err |= release_sem(port->old_play_sem); + // err = B_OK; + } + break; + case SOUND_UNSAFE_READ: + TRACE("SOUND_UNSAFE_READ\n"); + // ASSERT(0); + err = release_sem(port->old_cap_sem); + err = B_IO_ERROR; + break; + case SOUND_LOCK_FOR_DMA: + TRACE("SOUND_LOCK_FOR_DMA\n"); + err = B_OK; + break; + case SOUND_SET_PLAYBACK_PREFERRED_BUF_SIZE: + { + int32 new_size = (int32)arg; + TRACE("SOUND_SET_PLAYBACK_PREFERRED_BUF_SIZE: 0x%x\n", new_size); + hw_pchannel_setblocksize(port, new_size); + err = B_OK; + } + break; + case SOUND_SET_CAPTURE_PREFERRED_BUF_SIZE: + // TRACE("SOUND_SET_CAPTURE_PREFERRED_BUF_SIZE\n"); + // config.rec_buf_size = (int32)data; + // configure = true; + err = B_OK; + break; + case SOUND_GET_PLAYBACK_PREFERRED_BUF_SIZE: + TRACE("SOUND_GET_PLAYBACK_PREFERRED_BUF_SIZE\n"); + *(int32*)arg = port->play_channel.mem_size/2; + err = B_OK; + break; + case SOUND_GET_CAPTURE_PREFERRED_BUF_SIZE: + // TRACE("SOUND_GET_CAPTURE_PREFERRED_BUF_SIZE\n"); + // *(int32*)data = config.rec_buf_size; + err = B_OK; + break; + default: + TRACE("pcm_control : unknown code %ld\n", op); + err = B_BAD_VALUE; + break; + } + return err; +} + +/* pcm_close - handle close() calls */ +static status_t pcm_close (void* cookie) +{ + pcm_dev * port = (pcm_dev *)cookie; + TRACE("pcm_close(%p)\n", cookie); + + acquire_sem(port->init_sem); + + if (atomic_add(&port->open_count, -1) == 1) + { + TRACE("pcm_close: last close\n"); + hw_stop(port); + hw_pchannel_free(port); + } + else + { + TRACE("pcm_close: previous closes\n"); + } + + release_sem(port->init_sem); + return B_OK; +} + + +/* pcm_free - called after the last device is closed, and after all i/o is complete. */ +static status_t pcm_free (void* cookie) +{ + pcm_dev *port = (pcm_dev *)cookie; + TRACE("pcm_free(%p)\n", cookie); + + acquire_sem(port->init_sem); + + if (port->open_count == 0) + { + hw_decrement_interrupt_handler(port->card); + } + + release_sem(port->init_sem); + return B_OK; +} + +/* function pointers for the device hooks entry points */ +device_hooks pcm_hooks = +{ + pcm_open, /* -> open entry point */ + pcm_close, /* -> close entry point */ + pcm_free, /* -> free cookie */ + pcm_control, /* -> control entry point */ + pcm_read, /* -> read entry point */ + pcm_write /* -> write entry point */ +}; diff --git a/src/add-ons/kernel/drivers/audio/sis7018/pcm.h b/src/add-ons/kernel/drivers/audio/sis7018/pcm.h new file mode 100644 index 0000000000..6e034e71e8 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/pcm.h @@ -0,0 +1,43 @@ +/* + * This file is a part of SiS 7018 BeOS driver project. + * Copyright (c) 2002-2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * See the file "License" for details. + */ +#ifndef _PCM_H_ + #define _PCM_H_ + +#ifndef _DRIVERS_H + #include +#endif //_DRIVERS_H + +#ifndef _SIS7018_H_ + #include "sis7018.h" +#endif //_SIS7018_H_ + +extern device_hooks pcm_hooks; + +bool playback_interrupt(sis7018_ch *ch, bool bHalf); + +/* secret handshake ioctl()s */ +/*#define SV_SECRET_HANDSHAKE 10100 +typedef struct { + bigtime_t wr_time; + bigtime_t rd_time; + uint32 wr_skipped; + uint32 rd_skipped; + uint64 wr_total; + uint64 rd_total; + uint32 _reserved_[6]; +} sv_handshake; +#define SV_RD_TIME_WAIT 10101 +#define SV_WR_TIME_WAIT 10102 +typedef struct { + bigtime_t time; + bigtime_t bytes; + uint32 skipped; + uint32 _reserved_[3]; +} sv_timing; +*/ +#endif //_PCM_H_ diff --git a/src/add-ons/kernel/drivers/audio/sis7018/sis7018.c b/src/add-ons/kernel/drivers/audio/sis7018/sis7018.c new file mode 100644 index 0000000000..d0b80d32b2 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/sis7018.c @@ -0,0 +1,441 @@ +/* + * This file is a part of SiS 7018 BeOS driver project. + * Copyright (c) 2002-2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * See the file "License" for details. + */ +#include //sprintf +#include +#include //posix file i/o - create, write, close +#include +#include "sis7018.h" +#include "sis7018hw.h" +#include "ac97.h" + +#if DO_PCM +#include "pcm.h" +#endif + +#if DO_MIDI +#include "midi_driver.h" +#include "midi.h" +#endif + +#define NUM_CARDS 3 + +int32 num_cards; +sis7018_dev cards[NUM_CARDS]; +int num_names; +char * names[NUM_CARDS*7+1]; + +#if DEBUG +bool b_log = true; +#else +bool b_log = false; +#endif +bool b_log_file = false; +bool b_log_append = false; +bool b_trace_ac97 = false; +bool use_io_regs = false; + +static const char *private_log_path="/boot/home/sis7018.log"; +static sem_id loglock; + +static void reload_sis7018_setting() +{ + void *settingshandle; + settingshandle = load_driver_settings(CHIPNAME); +#if !DEBUG + b_log = get_driver_boolean_parameter(settingshandle, "debug_output", b_log, true); +#endif + b_log_file = get_driver_boolean_parameter(settingshandle, "debug_output_in_file", b_log_file, true); + b_log_append = ! get_driver_boolean_parameter(settingshandle, "debug_output_file_rewrite", !b_log_append, true); + b_trace_ac97 = get_driver_boolean_parameter(settingshandle, "debug_trace_ac97", b_trace_ac97, true); + use_io_regs = get_driver_boolean_parameter(settingshandle, "use_io_registers", use_io_regs, true); + unload_driver_settings(settingshandle); +} + +void create_log() +{ + int flags = O_WRONLY | O_CREAT | ((!b_log_append) ? O_TRUNC : 0); + if(!b_log_file) + return; + close(open(private_log_path, flags, 0666)); + loglock = create_sem(1,"sis7018 logfile"); +} + +void sis7018_trace(bool b_force, char *fmt, ...) +{ + if(!(b_force || b_log)) + return; + { + va_list arg_list; + static char *prefix = "\33[32m"CHIPNAME":\33[0m"; + static char buf[1024]; + char *buf_ptr = buf; + if(!b_log_file) + { + strcpy(buf, prefix); + buf_ptr += strlen(prefix); + } + + va_start(arg_list, fmt); + vsprintf(buf_ptr, fmt, arg_list); + va_end(arg_list); + + if(b_log_file) + { + int fd; + if(!b_trace_ac97) + acquire_sem(loglock); + fd = open(private_log_path, O_WRONLY | O_APPEND); + write(fd, buf, strlen(buf)); + close(fd); + if(!b_trace_ac97) + release_sem(loglock); + } + else + dprintf(buf); + } +} + +card_type card_types[]= +{ + {{TDX_PCI_ID}, "Trident DX"}, + {{xDX_PCI_ID}, "Trident XX"}, + {{TNX_PCI_ID}, "Trident NX"}, + {{ALI_PCI_ID}, "ALi 5451"}, + {{SPA_PCI_ID}, "SiS 7018"}, +}; + +#ifdef DEBUG +int _assert_(char *a, int b, char *c) +{ + char sz[1024]; + sprintf(sz, CHIPNAME":tripped assertion in %s/%d (%s)", a, b, c); + TRACE("tripped assertion in %s/%d (%s)\n", a, b, c); + kernel_debugger(sz); + return 0; +} +#endif + +static void make_device_names(sis7018_dev * card) +{ + char * name = card->name; + sprintf(name, "%s/%ld", card->type->chip_name, card-cards+1); + +#if DO_MIDI + sprintf(card->midi.name, "midi/%s", name); + names[num_names++] = card->midi.name; +#endif //DO_MIDI + +#if DO_PCM +// sprintf(card->pcm.name, "audio/raw/%s", name); +// names[num_names++] = card->pcm.name; + sprintf(card->pcm.oldname, "audio/old/%s", name); + names[num_names++] = card->pcm.oldname; +#endif //DO_PCM + + names[num_names] = NULL; +} + +static status_t setup_hardware( sis7018_dev * card) +{ + status_t err = B_OK; + int32 command_reg; + + TRACE("setup_hardware(%p)\n", card); + + if ((card->pcm.init_sem = create_sem(1, "sis7018 pcm init")) < B_OK) + goto bail; + +#if DO_MIDI //TODO: below? + if ((*mpu401->create_device)(card->info.u.h0.base_registers[3], &card->midi.driver, + 0, midi_interrupt_op, &card->midi) < B_OK) + goto bail3; + TRACE("midi %p\n", card->midi.driver); + card->midi.card = card; +#endif //DO_MIDI + + make_device_names(card); + + command_reg = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, + PCI_command, 2); +// TRACE("PCI command config was: %lx\n", command_reg); + command_reg |= PCI_command_io | PCI_command_memory | PCI_command_master; + (*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function, + PCI_command, 2, command_reg); +// TRACE("PCI command config set to: %lx\n", command_reg); + + if(use_io_regs) + { + card->io_base = card->info.u.h0.base_registers[0]; + TRACE("%s base at %x\n", card->name, card->io_base); + } + else // USE_IO_RANGE + { + TRACE("%s memory %lx length %lx\n", card->name, card->info.u.h0.base_registers[1], card->info.u.h0.base_register_sizes[1]); + card->regs_area = map_physical_memory("Regs sis7018", + (void *)card->info.u.h0.base_registers[1], + card->info.u.h0.base_register_sizes[1], + B_ANY_KERNEL_ADDRESS, + B_READ_AREA + B_WRITE_AREA, + &card->regs_mem_base); + + TRACE("%s registers memory base at 0x%p\n", card->name, card->regs_mem_base); + }// USE_IO_RANGE + + err = hw_initialize(card); + return err; + +#if DO_MIDI +bail3: +#endif //DO_MIDI + delete_sem(card->pcm.init_sem); +bail: + return err < B_OK ? err : B_ERROR; +} + +#if DEBUG +static int debug_sis7018(int argc, char * argv[]) +{ + int err = (argc < 2 || argc > 3); + int card_id = 0; + + if(!err) + { + if(argc == 3) + card_id = parse_expression(argv[2]); + + if(card_id < 0 || card_id > num_cards-1) + { + kprintf("ERROR: Wrong card_id: %d\n", card_id); + kprintf("\n"); + err = 1; + } + else + { + switch((char)*(argv[1])) + { + case 'd': hw_dump_device(card_id); break; + case 'i': hw_dump_pci_info(card_id); break; + case 'p': hw_dump_pcm_device(card_id); break; + case 'm': hw_dump_midi_device(card_id); break; + case 'c': hw_dump_play_channel(card_id); break; + case 'a': ac97dump(card_id); break; + default: + kprintf("ERROR: Wrong command: %s\n",argv[1]); + kprintf("\n"); + err=1; + break; + } + } + } + + if (err) + { + kprintf("Syntax: "CHIPNAME" < command > [card id]\n"); + kprintf(" - where commands is:\n"); + kprintf(" d - dump device info\n"); + kprintf(" i - dump pci_info\n"); + kprintf(" p - dump pcm info\n"); + kprintf(" m - dump midi info\n"); + kprintf(" c - dump playback channel info\n"); + kprintf(" a - dump AC'97 registers info\n"); + kprintf(" - and card id is zero-based id of card to be investigated\n"); + kprintf(" default card id is 0\n"); + kprintf(" current cards count is %ld\n", num_cards); + kprintf("\n"); + } + + return 0; +} +#endif /* DEBUG */ + +/************** SYSTEM CALLBACKS ************************************/ + +int32 api_version = B_CUR_DRIVER_API_VERSION; + +/* init_hardware - called once the first time the driver is loaded */ +status_t init_hardware (void) +{ + int ix = 0, jx = 0; + pci_info info; + status_t err = ENODEV; + + TRACE("init_hardware()\n"); + + if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci)) + return ENOSYS; + + while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) + { + for(jx = 0; jx < sizeof(card_types)/sizeof(card_types[0]); jx++) + if (info.vendor_id == card_types[jx].ids.ids.vendor_id + && info.device_id == card_types[jx].ids.ids.card_id) + { + err = B_OK; + } + ix++; + } + + put_module(B_PCI_MODULE_NAME); + return err; +} + +/* init_driver - optional function - called every time the drive is loaded. */ +status_t init_driver (void) +{ + int ix=0, jx=0; + pci_info info; + num_cards = 0; + + reload_sis7018_setting(); + create_log(); + + TRACE("\n>>> init_driver()\n"); + load_driver_symbols(CHIPNAME); + + if (get_module(B_PCI_MODULE_NAME, (module_info **) &pci)) + return ENOSYS; + +#if DO_MIDI + TRACE("MPU\n"); + if (get_module(B_MPU_401_MODULE_NAME, (module_info **) &mpu401)) + { + put_module(B_PCI_MODULE_NAME); + return ENOSYS; + } + TRACE("MPU: %p\n", mpu401); +#endif //DO_MIDI + + while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) + { + for(jx = 0; jx < sizeof(card_types)/sizeof(card_types[0]); jx++) + if (info.vendor_id == card_types[jx].ids.ids.vendor_id + && info.device_id == card_types[jx].ids.ids.card_id) + { + if (num_cards == NUM_CARDS) + { + TRACE_ALWAYS("Too many cards installed! Only %d will be used.\n", NUM_CARDS); + break; + } + + memset(&cards[num_cards], 0, sizeof(sis7018_dev)); + cards[num_cards].info = info; + cards[num_cards].type = &card_types[jx]; + if (setup_hardware(&cards[num_cards])) + { + TRACE_ALWAYS("Setup of %s driver for %ld-th card failed\n", CHIPNAME, num_cards+1); + } + else + num_cards++; + + TRACE_ALWAYS("%s found.\n", + card_types[jx].chip_name, + card_types[jx].ids.ids.vendor_id, + card_types[jx].ids.ids.card_id); + } + ix++; + } + + if (!num_cards) + { +#if DO_MIDI + put_module(B_MPU_401_MODULE_NAME); +#endif //DO_MIDI + put_module(B_PCI_MODULE_NAME); + TRACE("No suitable cards found\n"); + return ENODEV; + } + +#if DEBUG + add_debugger_command(CHIPNAME, debug_sis7018, CHIPNAME" driver info."); +#endif + return B_OK; +} + +static void teardown_card(sis7018_dev *card) +{ + /* remove created devices */ +#if DO_MIDI + (*mpu401->delete_device)(card->midi.driver); +#endif //DO_MIDI + + if(!use_io_regs) + delete_area(card->regs_area); + + delete_sem(card->pcm.init_sem); +} + +/* uninit_driver - optional function - called every time the driver is unloaded */ +void uninit_driver (void) +{ + int ix, cnt = num_cards; + num_cards = 0; + + TRACE("<<< uninit_driver()\n\n"); + +#if DEBUG + remove_debugger_command(CHIPNAME, debug_sis7018); +#endif + + for (ix=0; ix + * + * This file may be used under the terms of the BSD License + * See the file "License" for details. + */ +#ifndef _SIS7018_H_ + #define _SIS7018_H_ + +#include +#include +#include +#include + +#define CHIPNAME "sis7018" + +void sis7018_trace(bool b_force, char *fmt, ...); + +//#define TRACE_ALWAYS(x...) dprintf("\33[32m"CHIPNAME":\33[0m"x); +#define TRACE_ALWAYS(x...) sis7018_trace(true, x); +#define TRACE(x...) sis7018_trace(false, x); + +extern bool b_trace_ac97; + +#if DEBUG +//#define TRACE(x...) TRACE_ALWAYS(x) +int _assert_(char *,int,char *); +#define ASSERT(c) (!(c) ? _assert_(__FILE__, __LINE__, #c) : 0) +#else +//#define TRACE(x...) +#define ASSERT(c) +#endif + +#define DEVNAME 32 + +#define TDX_PCI_ID 0x20001023 // Trident 4D Wave/DX +#define xDX_PCI_ID 0x20000003 // Hypotese? +#define TNX_PCI_ID 0x20011023 // Trident 4D Wave/NX +#define ALI_PCI_ID 0x545110b9 // Acer Labs 5451 Audio +#define SPA_PCI_ID 0x70181039 // SiS PCI Audio + +typedef struct _card_type +{ + union _ids + { + uint32 chip_id; + struct { + uint16 vendor_id; + uint16 card_id; + } ids; + } ids; + char chip_name[DEVNAME]; +} card_type; + +#define DO_PCM 1 +#define DO_MIDI 0 + +//#define USE_IO_REGS 0 +extern bool use_io_regs; + +typedef struct _midi_dev { + struct _sis7018_dev *card; + void * driver; + void * cookie; + int32 count; + char name[64]; +} midi_dev; + +/* channel registers */ +typedef struct _sis7018_ch { + int32 cso, alpha, fms, fmc, ec; + int32 lba; + int32 eso, delta; + int32 rvol, cvol; + int32 gvsel, pan, vol, ctrl; + int32 active/*:1, was_active:1*/; + int index/*, bufhalf*/; + struct _sis7018_dev *card; + size_t mem_size; /* size of low memory */ + vuchar * mem_ptr; + vuchar * mem_phys; /* physical address */ + area_id areaid; /* area pointing to low memory */ + + vuchar * wr_1; + vuchar * wr_2; + vuchar * wr_cur; +#if DEBUG + vuchar * wr_cur_prv; + bigtime_t time_prv; + bool prevInt; +#endif + size_t wr_size; + + int32 wr_lock; + int wr_silence; + int32 write_waiting; + sem_id write_sem; + size_t was_written; + uint32 wr_skipped; + sem_id wr_entry; + bigtime_t wr_time; + uint64 wr_total; +// sem_id wr_time_sem; +// int32 wr_time_wait; +} sis7018_ch; + +typedef struct { + struct _sis7018_dev * card; + char name[DEVNAME]; + int32 open_count; + int32 open_mode; + sem_id init_sem; + + sem_id old_cap_sem; + sem_id old_play_sem; + + char oldname[DEVNAME]; + struct _sis7018_ch play_channel; +} pcm_dev; + +typedef struct _ac97_codec +{ + bool wide_main_gain; +} ac97_codec; + +typedef struct _sis7018_dev +{ + char name[DEVNAME]; /* used for resources */ + int32 hardware; /* spinlock */ +//#if(USE_IO_REGS) + int io_base; /* offset to port */ +//#else + void *regs_mem_base; +//#endif + int32 inth_count; +/* int dma_base; + size_t low_size;*/ /* size of low memory */ +/* vuchar * low_mem; + vuchar * low_phys;*/ /* physical address */ +// area_id map_low; /* area pointing to low memory */ +//#if(!USE_IO_REGS) + area_id regs_area; +//#endif + pci_info info; + midi_dev midi; +/* joy_dev joy;*/ + pcm_dev pcm; +/* mux_dev mux; + mixer_dev mixer;*/ + card_type *type; + ac97_codec ac97; +} sis7018_dev; + +extern int32 num_cards; +extern sis7018_dev cards[]; + +/*uint32 io_rd(sis7018_dev *dev, int offset, int size); +void io_wr(sis7018_dev *dev, int offset, uint32 value, int size); +int rd_cd(sis7018_dev *dev, int regno); +int wr_cd(sis7018_dev *dev, int regno, uint32 data); + +void increment_interrupt_handler(sis7018_dev * card); +void decrement_interrupt_handler(sis7018_dev * card); +*/ +#endif //_SIS7018_H_ diff --git a/src/add-ons/kernel/drivers/audio/sis7018/sis7018.rdef b/src/add-ons/kernel/drivers/audio/sis7018/sis7018.rdef new file mode 100644 index 0000000000..dda3560e09 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/sis7018.rdef @@ -0,0 +1,54 @@ + +resource(101, "BEOS:L:STD_ICON") #'ICON' array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFF3F7E3DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFF3F3F7E3E28FFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFF3F3F7E3E5F3E28FFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFF3F3F7E3E5F3E5F3E27FFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFF3F3F7E3E5F3E5F3E937E3DFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFF3F3F7E3E5F3E5F3E937E3E5FDFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFF3F3F7E3E5F3E5F3E937E3E5F3E9301FFFFFFFFFFFFFFFFFF" + $"FFFFFF3F3F3F3F3F3F7E3E5F3E5F3F3F3F3E937E3E5F403F3F3F3F3FFFFFFFFF" + $"FFFF3FFAFAFAFAFAFA3F7E3E5F1FFAFAFA3F3E5F3E3FFCFAFAFAFAFA1FFFFFFF" + $"FF3FFAFAFAFAFAFAFAFA3F7E3E3FFBFAFA3F257E3FFAFAFAFAFAFAFAFA3FFFFF" + $"3FFAFAFA3F3F3F3FFAFAFA3F7E1FFAFAFA1FDD3FFAFAFA3F3F3F3FFAFAFA3FFF" + $"3FFAFA3F252525253F3F3F3F24253F3F3F25253FFAFA3F252525253F3F3F3F25" + $"3FFAFA3F257E3E5FDD242525257E252525253E3FFCFA1F257F3E5EDD25242525" + $"3FFAFAFA3F3F7E3E5F3E5F3E93403F3F3F3F7E1FFAFAFA3F3F3E937E3E28FFFF" + $"253FFAFAFAFA3F3F7E3E5F3E5F3FFAFAFA3FDC263FFAFAFAFA3F3F7E3E5F3DFF" + $"FF253F3FFAFAFAFA3F3F7E3E5F3FFAFAFA3FDD7E253F3FFAFAFAFA3F3F3E5F3D" + $"FFFF25253F3FFAFAFAFA3F7E3E3FFBFAFA3F247F3E21253F3FFAFAFAFA3F01FF" + $"FFFFFF3F25253F3FFAFAFA3F7E1FFAFAFA3FDD7E3E5F3E21253F3FFAFAFA3FFF" + $"FFFFFFFF3F7E26253FFAFA3F253FFAFAFA3F243E5F3E5F3E93242540FAFA3F25" + $"3F3F3F3FFF3F7E3E3FFBFA3F253FFAFAFA3F241F3F3F3F3E5F3E5F3FFAFA3FDC" + $"3FFAFAFA3F3F3F3FFAFAFA3F253FFAFAFA3F253FFAFAFA3F3F3F3FFAFAFA3F25" + $"253FFAFAFAFAFAFAFAFA3F25253FFAFAFA3F25241FFAFAFAFAFAFAFAFA3F2525" + $"FF253FFAFAFAFAFA3F3F25257E1FFAFAFA3FDC7F253FFAFAFAFAFA3F3F2524FF" + $"FFFF253F3F3F3F3F2525257E3E3F3F3F3F3F227E3E221F3F3F3F3F252525FFFF" + $"FFFFFF252525252425FF3F3F7F2425252525243E5F3E222524252525FFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFF3F3F7E3E5F3E5F3E937E3DE0FFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFF3F3F7E3E5F3E5F3E27FFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFF3F3F7E3E5F3E28FFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFF3F3F7E3E28FFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F7E3DFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" +}; + +resource(101, "BEOS:M:STD_ICON") #'MICN' array { + $"FFFFFFFFFFFFFFB500FFFFFFFFFFFFFF" + $"FFFFFFFFFFFF19947F01FFFFFFFFFFFF" + $"FFFFFFFFFF19943E5F7F01FFFFFFFFFF" + $"FFFFFFFF18947E3E5F3E7E3DFFFFFFFF" + $"FF63FCFD687E6EFC687E74FCFDFC07FF" + $"63FAFDFCFA6867FAFCB4E5FBFDFBFB07" + $"FCFDDDDCAD12248DD487FA10DCB310D3" + $"17FAFC687E3E6CFDFED4FBFB42947F00" + $"29ADFCFAFD9468FAFDDDB418FBFB4229" + $"B807B410E5FD8DFAFC7E7F7EAE15FA10" + $"FEFC186DFBFCA7FAFD8EFD626E19FA11" + $"D4FBFAFAFCB487FAFC2468FAFAFB6226" + $"FFB5A78D278DB4A78EDC7E11ADCE27FF" + $"FFFFFFFFFF07417E7F3EDCFFFFFFFFFF" + $"FFFFFFFFFFFF07617E3BFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFD6DEFFFFFFFFFFFFFF" +}; diff --git a/src/add-ons/kernel/drivers/audio/sis7018/sis7018.settings.sample b/src/add-ons/kernel/drivers/audio/sis7018/sis7018.settings.sample new file mode 100644 index 0000000000..5e2c792449 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/sis7018.settings.sample @@ -0,0 +1,37 @@ +# +# The sample sis7018 driver settings file +# +# Rename it to sis7018 and put into +# /boot/home/config/settings/kernel/drivers/ +# After restarting Media Services the new settings will works. + +# Debug output - this is a possibility to view some kind of development related +# information - error and warning messages etc. + +# debug_output - activates debug output. The debug builds has debug output +# activated by default and this key has no effect on it. The release builds requires +# to activate this if you want to see debug messages in syslog or in private log file. +# +# debug_output true + +# debug_output_in_file - activates writing of debug messages into private log file. +# The name of this file is /boot/home/sis7018.log. If this key is set to true - no messages +# will be written into syslog. +# +# debug_output_in_file true + +# debug_output_file_rewrite - activates rewriting of private log file on +# calling driver_init() syscall. By default this set in false. +# +# debug_output_file_rewrite false + +# debug_trace_ac97 - activates more detailed logging of AC'97 operations. +# Do not use it with syslog output - you'll get only messages +# because BeOS's syslog daemon don't like a lot of messages in short time +# +# debug_trace_ac97 true + +# use_io_registers - switches driver from "memory" scheme to "io registers" +# scheme. This key is usefull for testers. Don't use it if you don't need it. +# +# use_io_registers true diff --git a/src/add-ons/kernel/drivers/audio/sis7018/sis7018hw.c b/src/add-ons/kernel/drivers/audio/sis7018/sis7018hw.c new file mode 100644 index 0000000000..220e96e00d --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/sis7018hw.c @@ -0,0 +1,563 @@ +/* + * This file is a part of SiS 7018 BeOS driver project. + * Copyright (c) 2002-2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * See the file "License" for details. + */ +#include //sprintf +#include + +#include "sis7018.h" +#include "sis7018hw.h" +#include "t4dwave.h" +#include "ac97.h" +#include "pcm.h" + +pci_module_info* pci; + +#define MIN_MEMORY_SIZE 0x2000 +#define PCHANNEL_ID 0x00 + +int intrs; + +uint32 hw_read(sis7018_dev *dev, int offset, int size) +{ + uint32 ret = 0xffffffff; + if(use_io_regs){ + switch(size){ + case 1: ret = (*pci->read_io_8)(dev->io_base + offset); break; + case 2: ret = (*pci->read_io_16)(dev->io_base + offset); break; + case 4: ret = (*pci->read_io_32)(dev->io_base + offset); break; + default: break; + } + } + else{ + switch(size){ + case 1: ret = *(int8 *)((char *)dev->regs_mem_base + offset); break; + case 2: ret = *(int16 *)((char *)dev->regs_mem_base + offset); break; + case 4: ret = *(int32 *)((char *)dev->regs_mem_base + offset); break; + default: break; + } + } + // TRACE("tr_rd off=%x ret=%lx\n", offset, ret); + return ret; +} + +void hw_write(sis7018_dev *dev, int offset, uint32 value, int size) +{ + //TRACE("tr_wr off=%x value = %lx\n", offset, value); + if(use_io_regs){ + switch(size){ + case 1: (*pci->write_io_8)(dev->io_base + offset, (uint8) value); break; + case 2: (*pci->write_io_16)(dev->io_base + offset, (uint16) value); break; + case 4: (*pci->write_io_32)(dev->io_base + offset, value); break; + default: break; + } + } + else{ + switch(size){ + case 1: *(int8 *)((char *)dev->regs_mem_base + offset) = (int8)value; break; + case 2: *(int16 *)((char *)dev->regs_mem_base + offset) = (int16)value; break; + case 4: *(int32 *)((char *)dev->regs_mem_base + offset) = (int32)value; break; + default: break; + } + } +} + +static void hw_clrint(sis7018_ch *ch) +{ + sis7018_dev *dev = ch->card; + int bank, chan; + + bank = (ch->index & 0x20) ? 1 : 0; + chan = ch->index & 0x1f; + hw_write(dev, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 1 << chan, 4); +} + +static void hw_enaint(sis7018_ch *ch, int enable) +{ + sis7018_dev *dev = ch->card; + int32 i, reg; + int bank, chan; + cpu_status cp; + + cp = disable_interrupts(); + acquire_spinlock(&dev->hardware); + + bank = (ch->index & 0x20) ? 1 : 0; + chan = ch->index & 0x1f; + reg = bank? TR_REG_INTENB : TR_REG_INTENA; + + i = hw_read(dev, reg, 4); + i &= ~(1 << chan); + i |= (enable? 1 : 0) << chan; + + hw_clrint(ch); + hw_write(dev, reg, i, 4); + + release_spinlock(&dev->hardware); + restore_interrupts(cp); +} + +static void hw_selch(sis7018_ch *ch) +{ + sis7018_dev *dev = ch->card; + int32 i; + + i = hw_read(dev, TR_REG_CIR, 4); + i &= ~TR_CIR_MASK; + i |= ch->index & 0x3f; + hw_write(dev, TR_REG_CIR, i, 4); +} + +static void hw_startch(sis7018_ch *ch) +{ + sis7018_dev *dev = ch->card; + int bank, chan; + + bank = (ch->index & 0x20) ? 1 : 0; + chan = ch->index & 0x1f; + hw_write(dev, bank? TR_REG_STARTB : TR_REG_STARTA, 1 << chan, 4); +} + +static void hw_stopch(sis7018_ch *ch) +{ + sis7018_dev *dev = ch->card; + int bank, chan; + + bank = (ch->index & 0x20) ? 1 : 0; + chan = ch->index & 0x1f; + hw_write(dev, bank? TR_REG_STOPB : TR_REG_STOPA, 1 << chan, 4); +} + +static void hw_wrch(sis7018_ch *ch) +{ + sis7018_dev *dev = ch->card; + int32 cr[TR_CHN_REGS], i; + cpu_status cp; + + ch->gvsel &= 0x00000001; + ch->fmc &= 0x00000003; + ch->fms &= 0x0000000f; + ch->ctrl &= 0x0000000f; + ch->pan &= 0x0000007f; + ch->rvol &= 0x0000007f; + ch->cvol &= 0x0000007f; + ch->vol &= 0x000000ff; + ch->ec &= 0x00000fff; + ch->alpha &= 0x00000fff; + ch->delta &= 0x0000ffff; + ch->lba &= 0x3fffffff; + + cr[1]=ch->lba; + cr[3]=(ch->fmc<<14) | (ch->rvol<<7) | (ch->cvol); + cr[4]=(ch->gvsel<<31) | (ch->pan<<24) | (ch->vol<<16) | (ch->ctrl<<12) | (ch->ec); + + switch (ch->card->type->ids.chip_id) + { + case SPA_PCI_ID: + case ALI_PCI_ID: + case TDX_PCI_ID: + case xDX_PCI_ID: + ch->cso &= 0x0000ffff; + ch->eso &= 0x0000ffff; + cr[0]=(ch->cso<<16) | (ch->alpha<<4) | (ch->fms); + cr[2]=(ch->eso<<16) | (ch->delta); + break; + case TNX_PCI_ID: + ch->cso &= 0x00ffffff; + ch->eso &= 0x00ffffff; + cr[0]=((ch->delta & 0xff)<<24) | (ch->cso); + cr[2]=((ch->delta>>8)<<24) | (ch->eso); + cr[3]|=(ch->alpha<<20) | (ch->fms<<16) | (ch->fmc<<14); + break; + } + cp = disable_interrupts(); + acquire_spinlock(&dev->hardware); + + hw_selch(ch); + for (i=0; ihardware); + restore_interrupts(cp); +} + +void hw_rdch(sis7018_ch *ch) +{ + sis7018_dev *dev = ch->card; + int32 cr[5], i; + cpu_status cp; + + cp = disable_interrupts(); + acquire_spinlock(&dev->hardware); + + hw_selch(ch); + for (i=0; i<5; i++) + cr[i]=hw_read(dev, TR_REG_CHNBASE+(i<<2), 4); + + release_spinlock(&dev->hardware); + restore_interrupts(cp); + + ch->lba= (cr[1] & 0x3fffffff); + ch->fmc= (cr[3] & 0x0000c000) >> 14; + ch->rvol= (cr[3] & 0x00003f80) >> 7; + ch->cvol= (cr[3] & 0x0000007f); + ch->gvsel= (cr[4] & 0x80000000) >> 31; + ch->pan= (cr[4] & 0x7f000000) >> 24; + ch->vol= (cr[4] & 0x00ff0000) >> 16; + ch->ctrl= (cr[4] & 0x0000f000) >> 12; + ch->ec= (cr[4] & 0x00000fff); + + switch(ch->card->type->ids.chip_id) + { + case SPA_PCI_ID: + case ALI_PCI_ID: + case TDX_PCI_ID: + case xDX_PCI_ID: + ch->cso= (cr[0] & 0xffff0000) >> 16; + ch->alpha= (cr[0] & 0x0000fff0) >> 4; + ch->fms= (cr[0] & 0x0000000f); + ch->eso= (cr[2] & 0xffff0000) >> 16; + ch->delta= (cr[2] & 0x0000ffff); + break; + case TNX_PCI_ID: + ch->cso= (cr[0] & 0x00ffffff); + ch->eso= (cr[2] & 0x00ffffff); + ch->delta= ((cr[2] & 0xff000000) >> 16) | ((cr[0] & 0xff000000) >> 24); + ch->alpha= (cr[3] & 0xfff00000) >> 20; + ch->fms= (cr[3] & 0x000f0000) >> 16; + break; + } +} + +status_t hw_pchannel_init(pcm_dev *dev) +{ + char name_buf[256]; + sis7018_ch *ch = &dev->play_channel; + ch->index = PCHANNEL_ID; + hw_pchannel_setblocksize(dev, 8192); + ch->ctrl = 0x0f; // 16-bit stereo signed + loop mode enabled + ch->delta = (48000 << 12 ) / 48000; + ch->card = dev->card; + ch->areaid=-1; + + ch->wr_lock = 0; + ch->write_waiting = 0; + sprintf(name_buf, "WS:%s", dev->name); + name_buf[B_OS_NAME_LENGTH-1] = 0; + ch->write_sem = create_sem(0, name_buf); + if (ch->write_sem < B_OK) + return ch->write_sem; + + set_sem_owner(ch->write_sem, B_SYSTEM_TEAM); + name_buf[0] = 'W'; name_buf[1] = 'E'; + ch->wr_entry = create_sem(1, name_buf); + if (ch->wr_entry < B_OK){ + delete_sem(ch->write_sem); + return ch->wr_entry; + } + set_sem_owner(ch->wr_entry, B_SYSTEM_TEAM); + ch->wr_time = 0; + return B_OK; +} + +void hw_pchannel_free(pcm_dev *dev) +{ + sis7018_ch *ch = &dev->play_channel; + if(ch->areaid >= 0){ + delete_area(ch->areaid); + ch->areaid = -1; + + delete_sem(ch->write_sem); + delete_sem(ch->wr_entry); + ch->write_sem = -1; + ch->wr_entry = -1; + } +} + +void hw_start(pcm_dev *dev) +{ + sis7018_ch *ch = &dev->play_channel; + + if(ch->active) + return; + + /* start out with a clean slate */ + TRACE("hw_start()\n"); +/* if (port->config.format == 0x11) + { + memset((void*)port->card->low_mem, 0x80, port->config.play_buf_size + + port->config.rec_buf_size); + } + else {*/ + + // TODO? + // memset((void *)port->card->low_mem, 0, port->config.play_buf_size + + // port->config.rec_buf_size); + //} + + ch->wr_cur = ch->wr_2; + ch->wr_silence = ch->mem_size; + ch->was_written = 0; + ch->wr_total = 0; + + ch->fmc = 3; + ch->fms = 0; + ch->ec = 0; + ch->alpha = 0; + ch->lba = (int32)ch->mem_phys; + ch->cso = 0; + ch->eso = ch->mem_size/(sizeof(int16)*2)-1; + ch->rvol = ch->cvol = 0x7f; + ch->gvsel = 0; + ch->pan = 0; + ch->vol = 0; + + hw_wrch(ch); + hw_enaint(ch, 1); + hw_startch(ch); + + ch->active = 1; +} + +void hw_stop(pcm_dev *dev) +{ + sis7018_ch *ch = &dev->play_channel; + if(!ch->active) + return; + + hw_stopch(ch); + ch->active = 0; +} + +static int32 hw_interrupt_handler(void * data) +{ + int32 active, mask, bufhalf, chnum, intsrc; + sis7018_dev *card = (sis7018_dev *)data; + sis7018_ch *ch; + int32 handled = B_UNHANDLED_INTERRUPT; + intrs++; + + acquire_spinlock(&card->hardware); + intsrc = hw_read(card, TR_REG_MISCINT, 4); + +#if DO_PCM + if (intsrc & TR_INT_ADDR){ + chnum = PCHANNEL_ID; + mask = 0x00000001 << PCHANNEL_ID; + active = hw_read(card, (chnum < 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, 4); + bufhalf = hw_read(card, (chnum < 32)? TR_REG_CSPF_A : TR_REG_CSPF_B, 4); + if (active & mask){ + ch = &card->pcm.play_channel; + if(playback_interrupt(ch, (bufhalf & mask))) + handled = B_INVOKE_SCHEDULER; + else + handled = B_HANDLED_INTERRUPT; + } + hw_write(card, (chnum <= 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, active, 4); + } +#endif +#if DO_MIDI + ssssssss + /*if (status & 0x80) { + if (midi_interrupt(card)) { + handled = B_INVOKE_SCHEDULER; + } else { + handled = B_HANDLED_INTERRUPT; + } + }*/ + handled = B_HANDLED_INTERRUPT; +#endif + + release_spinlock(&card->hardware); + return handled; +} + +void hw_increment_interrupt_handler(sis7018_dev * card) +{ + TRACE("hw_increment_interrupt_handler()\n"); + if (atomic_add(&card->inth_count, 1) == 0){ + TRACE("intline %d int %p\n", card->info.u.h0.interrupt_line, hw_interrupt_handler); + install_io_interrupt_handler(card->info.u.h0.interrupt_line, hw_interrupt_handler, card, 0); + } +} + +void hw_decrement_interrupt_handler(sis7018_dev * card) +{ + TRACE("hw_decrement_interrupt_handler()\n"); + if (atomic_add(&card->inth_count, -1) == 1){ + TRACE("remove_io_interrupt_handler()\n"); + remove_io_interrupt_handler(card->info.u.h0.interrupt_line, hw_interrupt_handler, card); + } +} + +status_t hw_initialize(sis7018_dev *card) +{ + status_t err = B_OK; + + cpu_status cp = disable_interrupts(); + acquire_spinlock(&card->hardware); + + switch (card->type->ids.chip_id){ + case SPA_PCI_ID: + hw_write(card, SPA_REG_GPIO, 0, 4); + hw_write(card, SPA_REG_CODECST, SPA_RST_OFF, 4); + break; + case TDX_PCI_ID: + case xDX_PCI_ID: + hw_write(card, TDX_REG_CODECST, TDX_CDC_ON, 4); + break; + case TNX_PCI_ID: + hw_write(card, TNX_REG_CODECST, TNX_CDC_ON, 4); + break; + } + + hw_write(card, TR_REG_CIR, TR_CIR_MIDENA | TR_CIR_ADDRENA, 4); + + release_spinlock(&card->hardware); + restore_interrupts(cp); + + err |= ac97init(card); + + return err; +} + +void hw_dump_device(int card_id) +{ + kprintf("interrupt handler called: %d\n", intrs); +} + +void hw_dump_pci_info(int card_id) +{ + kprintf("dump_pci_info is not yet implemented.\n"); +} + +void hw_dump_pcm_device(int card_id) +{ + kprintf("dump_pcm_device is not yet implemented.\n"); +} + +void hw_dump_midi_device(int card_id) +{ + kprintf("dump_midi_device is not yet implemented.\n"); +} + +static void hw_dump_channel(sis7018_ch *ch) +{ + kprintf("Pointer : %p\n", ch); + kprintf(" cso:%8lx, alpha:%8lx, fms:%8lx, fmc:%8lx, ec:%lx\n", + ch->cso, ch->alpha, ch->fms, ch->fmc, ch->ec); + kprintf(" lba:%8lx, eso:%8lx, delta:%8lx, rvol:%8lx, cvol:%lx\n", + ch->lba, ch->eso, ch->delta, ch->rvol, ch->cvol); + kprintf("gvsel:%8lx, pan:%8lx, vol:%8lx, ctrl:%8lx, active:%x\n", + ch->gvsel, ch->pan, ch->vol, ch->ctrl, (int)ch->active); + kprintf("index:%8x, card:0x%8p, mem_ptr:0x%8p, mem_size:%8lx, mem_phys:0x%8p\n", + ch->index, ch->card, ch->mem_ptr, ch->mem_size, ch->mem_phys); + kprintf("\n"); +} + +void hw_dump_play_channel(int card_id) +{ + sis7018_ch ch; + memcpy(&ch, &cards[card_id].pcm.play_channel, sizeof(sis7018_ch)); + kprintf("Dumping play channel information:\n"); + kprintf(" - cached:\n"); + hw_dump_channel(&ch); + kprintf(" - readed from hardware:\n"); + hw_rdch(&ch); + hw_dump_channel(&ch); +} + +static status_t hw_find_memory(sis7018_ch *ch, size_t blocksize) +{ + size_t low_size = (blocksize * 2+(B_PAGE_SIZE-1))&~(B_PAGE_SIZE-1); + physical_entry where; + size_t trysize; + area_id curarea; + void * addr; + char name[DEVNAME]; + + sprintf(name, "%s_area", ch->card->name); + if (low_size < MIN_MEMORY_SIZE) + low_size = MIN_MEMORY_SIZE; + trysize = low_size; + + curarea = find_area(name); + if (curarea != B_NAME_NOT_FOUND){ + TRACE("delete previously allocated area\n"); + delete_area(curarea); + curarea = -1; + } + + TRACE("allocating new area\n"); + + curarea = create_area(name, &addr, B_ANY_KERNEL_ADDRESS, + trysize, B_LOMEM, B_READ_AREA | B_WRITE_AREA); + TRACE("create_area(%lx) returned %lx logical %p\n", trysize, curarea, addr); + + if (curarea < 0) + goto oops; + + if (get_memory_map(addr, low_size, &where, 1) < 0){ + delete_area(curarea); + curarea = B_ERROR; + goto oops; + } + TRACE("physical %p\n", where.address); + if ((uint32)where.address & 0xff000000){ + delete_area(curarea); + curarea = B_ERROR; + goto oops; + } + if ((((uint32)where.address)+low_size) & 0xff000000){ + delete_area(curarea); + curarea = B_ERROR; + goto oops; + } + /* hey, it worked! */ + if (trysize > low_size) /* don't waste */ + resize_area(curarea, low_size); + +oops: + if (curarea < 0){ + TRACE("failed to create area\n"); + return curarea; + } +//a_o_k: + TRACE("successfully created area!\n"); + + ch->mem_size = low_size; + ch->mem_ptr = addr; + ch->mem_phys = (vuchar *)where.address; + + ch->wr_1 = ch->mem_ptr; + ch->wr_2 = ch->wr_1+ch->mem_size/2; + ch->wr_size = ch->mem_size/2; + + ch->areaid = curarea; + + if(ch->active){ + hw_stop(&ch->card->pcm); + hw_start(&ch->card->pcm); + } + + return B_OK; +} + +size_t hw_pchannel_setblocksize(pcm_dev *dev, size_t blocksize) +{ + sis7018_ch *ch = &dev->play_channel; + + if(ch->mem_size/2 != blocksize){ + if(ch->areaid >= 0){ + TRACE("delete area on resize\n"); + delete_area(ch->areaid); + ch->areaid = -1; + } + //TODO : error cheking. + hw_find_memory(ch, blocksize); + } + return blocksize; +} diff --git a/src/add-ons/kernel/drivers/audio/sis7018/sis7018hw.h b/src/add-ons/kernel/drivers/audio/sis7018/sis7018hw.h new file mode 100644 index 0000000000..a192488396 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/sis7018hw.h @@ -0,0 +1,35 @@ +/* + * This file is a part of SiS 7018 BeOS driver project. + * Copyright (c) 2002-2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * See the file "License" for details. + */ +#ifndef _SIS7018HW_H_ +#define _SIS7018HW_H_ + +#ifndef _SOUND_H +#include "sound.h" +#endif + +extern pci_module_info* pci; + +uint32 hw_read(sis7018_dev *dev, int offset, int size); +void hw_write(sis7018_dev *dev, int offset, uint32 value, int size); +status_t hw_pchannel_init(pcm_dev *dev); +void hw_pchannel_free(pcm_dev *dev); +size_t hw_pchannel_setblocksize(pcm_dev *dev, size_t blocksize); +void hw_start(pcm_dev *dev); +void hw_stop(pcm_dev *dev); +void hw_increment_interrupt_handler(sis7018_dev * card); +void hw_decrement_interrupt_handler(sis7018_dev * card); +status_t hw_initialize(sis7018_dev *card); +void hw_rdch(sis7018_ch *ch); + +void hw_dump_device(int card_id); +void hw_dump_pci_info(int card_id); +void hw_dump_pcm_device(int card_id); +void hw_dump_midi_device(int card_id); +void hw_dump_play_channel(int card_id); + +#endif //_SIS7018HW_H_ diff --git a/src/add-ons/kernel/drivers/audio/sis7018/sound.h b/src/add-ons/kernel/drivers/audio/sis7018/sound.h new file mode 100644 index 0000000000..4f6b192f8b --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/sound.h @@ -0,0 +1,94 @@ +/* ++++++++++ + Data structures and control calls for using the sound driver ++++++ */ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ +/* + * This file is a part of SiS 7018 BeOS driver project. + * Copyright permissions see above. + * + * Portion copyright (c) 2002-2003 by Siarzuk Zharski + */ +#ifndef _SOUND_H +#define _SOUND_H + +#ifndef _DRIVERS_H +#include +#endif + +enum adc_source { + line=0, aux1, mic, loopback +}; + +enum sample_rate { + kHz_8_0 = 0, kHz_5_51, kHz_16_0, kHz_11_025, kHz_27_42, kHz_18_9, + kHz_32_0, kHz_22_05, kHz_37_8 = 9, kHz_44_1 = 11, kHz_48_0, kHz_33_075, + kHz_9_6, kHz_6_62 +}; + +enum sample_format { + linear_8bit_unsigned_mono = 0, linear_8bit_unsigned_stereo, + ulaw_8bit_companded_mono, ulaw_8bit_companded_stereo, + linear_16bit_little_endian_mono, linear_16bit_little_endian_stereo, + alaw_8bit_companded_mono, alaw_8bit_companded_stereo, + sample_format_reserved_1, sample_format_reserved_2, + adpcm_4bit_mono, adpcm_4bit_stereo, + linear_16bit_big_endian_mono, linear_16bit_big_endian_stereo, + sample_format_reserved_3, sample_format_reserved_4 +}; + +struct channel { + enum adc_source adc_source; /* adc input source */ + char adc_gain; /* 0..15 adc gain, in 1.5 dB steps */ + char mic_gain_enable; /* non-zero enables 20 dB MIC input gain */ + char aux1_mix_gain; /* 0..31 aux1 mix to output gain. 12.0 to -34.5 dB in 1.5dB steps */ + char aux1_mix_mute; /* non-zero mutes aux1 mix */ + char aux2_mix_gain; /* 0..31 aux2 mix to output gain. 12.0 to -34.5 dB in 1.5dB steps */ + char aux2_mix_mute; /* non-zero mutes aux2 mix */ + char line_mix_gain; /* 0..31 line mix to output gain. 12.0 to -34.5 dB in 1.5dB steps */ + char line_mix_mute; /* non-zero mutes line mix */ + char dac_attn; /* 0..61 dac attenuation, in -1.5 dB steps */ + char dac_mute; /* non-zero mutes dac output */ +}; + +typedef struct sound_setup { + struct channel left; /* left channel setup */ + struct channel right; /* right channel setup */ + enum sample_rate sample_rate; /* sample rate */ + enum sample_format playback_format; /* sample format for playback */ + enum sample_format capture_format; /* sample format for capture */ + char dither_enable; /* non-zero enables dither on 16 => 8 bit */ + char loop_attn; /* 0..64 adc to dac loopback attenuation, in -1.5 dB steps */ + char loop_enable; /* non-zero enables loopback */ + char output_boost; /* zero (2.0 Vpp) non-zero (2.8 Vpp) output level boost */ + char highpass_enable;/* non-zero enables highpass filter in adc */ + char mono_gain; /* 0..64 mono speaker gain */ + char mono_mute; /* non-zero mutes speaker */ +} sound_setup; + + +/* ----- + control opcodes for sound driver +----- */ + +enum { + SOUND_GET_PARAMS = B_DEVICE_OP_CODES_END, + SOUND_SET_PARAMS, /* 10000 */ + SOUND_SET_PLAYBACK_COMPLETION_SEM, + SOUND_SET_CAPTURE_COMPLETION_SEM, + SOUND_GET_PLAYBACK_TIMESTAMP, /* 10003 */ + SOUND_GET_CAPTURE_TIMESTAMP, + SOUND_DEBUG_ON, + SOUND_DEBUG_OFF, /* 10006 */ + SOUND_UNSAFE_WRITE, + SOUND_UNSAFE_READ, + SOUND_LOCK_FOR_DMA, /* 10009 */ + SOUND_SET_CAPTURE_PREFERRED_BUF_SIZE, + SOUND_SET_PLAYBACK_PREFERRED_BUF_SIZE, + SOUND_GET_CAPTURE_PREFERRED_BUF_SIZE, /* 10012 */ + SOUND_GET_PLAYBACK_PREFERRED_BUF_SIZE +}; + +#endif diff --git a/src/add-ons/kernel/drivers/audio/sis7018/t4dwave.h b/src/add-ons/kernel/drivers/audio/sis7018/t4dwave.h new file mode 100644 index 0000000000..4dc4e78064 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/t4dwave.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1999 Cameron Grant + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/sound/pci/t4dwave.h,v 1.3.2.3 2001/08/30 23:10:50 greid Exp $ + */ +/* + * This file is a part of SiS 7018 BeOS driver project. + * Copyright permissions see above. + * + * Portion copyright (c) 2002 by Siarzuk Zharski + * + * $Source: /cvsroot/sis4be/sis7018/t4dwave.h,v $ + * $Author: zharik $ + * $Revision: 1.4 $ + * $Date: 2004/06/24 15:47:40 $ + */ +#ifndef _T4DWAVE_REG_H +#define _T4DWAVE_REG_H + +#define TR_REG_CIR 0xa0 +#define TR_CIR_MASK 0x0000003f +#define TR_CIR_ADDRENA 0x00001000 +#define TR_CIR_MIDENA 0x00002000 +#define TR_REG_MISCINT 0xb0 +#define TR_INT_ADDR 0x00000020 +#define TR_INT_SB 0x00000004 + +#define TR_REG_DMAR0 0x00 +#define TR_REG_DMAR4 0x04 +#define TR_REG_DMAR11 0x0b +#define TR_REG_DMAR15 0x0f +#define TR_REG_SBR4 0x14 +#define TR_REG_SBR5 0x15 +#define TR_SB_INTSTATUS 0x82 +#define TR_REG_SBR9 0x1e +#define TR_REG_SBR10 0x1f +#define TR_REG_SBBL 0xc0 +#define TR_REG_SBCTRL 0xc4 +#define TR_REG_SBDELTA 0xac + +#define TR_CDC_DATA 16 +#define TDX_REG_CODECWR 0x40 +#define TDX_REG_CODECRD 0x44 +#define TDX_CDC_RWSTAT 0x00008000 +#define TDX_REG_CODECST 0x48 +#define TDX_CDC_SBCTRL 0x40 +#define TDX_CDC_ACTIVE 0x20 +#define TDX_CDC_READY 0x10 +#define TDX_CDC_ADCON 0x08 +#define TDX_CDC_DACON 0x02 +#define TDX_CDC_RESET 0x01 +#define TDX_CDC_ON (TDX_CDC_ADCON|TDX_CDC_DACON) + +#define SPA_REG_CODECRD 0x44 +#define SPA_REG_CODECWR 0x40 +#define SPA_REG_CODECST 0x48 +#define SPA_RST_OFF 0x0f0000 +#define SPA_REG_GPIO 0x48 +#define SPA_CDC_RWSTAT 0x00008000 + +#define TNX_REG_CODECWR 0x44 +#define TNX_REG_CODEC1RD 0x48 +#define TNX_REG_CODEC2RD 0x4c +#define TNX_CDC_RWSTAT 0x00000c00 +#define TNX_CDC_SEC 0x00000100 +#define TNX_REG_CODECST 0x40 +#define TNX_CDC_READY2 0x40 +#define TNX_CDC_ADC2ON 0x20 +#define TNX_CDC_DAC2ON 0x10 +#define TNX_CDC_READY1 0x08 +#define TNX_CDC_ADC1ON 0x04 +#define TNX_CDC_DAC1ON 0x02 +#define TNX_CDC_RESET 0x01 +#define TNX_CDC_ON (TNX_CDC_ADC1ON|TNX_CDC_DAC1ON) + + +#define TR_REG_STARTA 0x80 +#define TR_REG_STOPA 0x84 +#define TR_REG_CSPF_A 0x90 +#define TR_REG_ADDRINTA 0x98 +#define TR_REG_INTENA 0xa4 + +#define TR_REG_STARTB 0xb4 +#define TR_REG_STOPB 0xb8 +#define TR_REG_CSPF_B 0xbc +#define TR_REG_ADDRINTB 0xd8 +#define TR_REG_INTENB 0xdc + +#define TR_REG_CHNBASE 0xe0 +#define TR_CHN_REGS 5 + +#endif diff --git a/src/add-ons/kernel/drivers/audio/sis7018/uninstall.sh b/src/add-ons/kernel/drivers/audio/sis7018/uninstall.sh new file mode 100644 index 0000000000..fe6aeee54f --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/sis7018/uninstall.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +answer=`alert "Do you really want to uninstall the Sis 7018 driver?" "No" "Yes"` +if [ $answer == "No" ]; then + exit +fi + +rm ~/config/add-ons/kernel/drivers/bin/sis7018 +rm ~/config/settings/kernel/drivers/sis7018 +rm ~/config/add-ons/kernel/drivers/dev/audio/old/sis7018 + +alert "The SiS7018 driver has been removed. + +Restart your system now." diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/Jamfile b/src/add-ons/kernel/drivers/audio/usb_audio/Jamfile index 2bcf54179b..b6620afeec 100644 --- a/src/add-ons/kernel/drivers/audio/usb_audio/Jamfile +++ b/src/add-ons/kernel/drivers/audio/usb_audio/Jamfile @@ -1,5 +1,9 @@ SubDir HAIKU_TOP src add-ons kernel drivers audio usb_audio ; +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders audio ; + KernelAddon usb_audio : kernel drivers bin : usb_audio.c USB_audio_utils.c diff --git a/src/add-ons/kernel/drivers/audio/usb_audio/R3MediaDefs.h b/src/add-ons/kernel/drivers/audio/usb_audio/R3MediaDefs.h deleted file mode 100644 index 814a5c8c03..0000000000 --- a/src/add-ons/kernel/drivers/audio/usb_audio/R3MediaDefs.h +++ /dev/null @@ -1,88 +0,0 @@ -/****************************************************************************** - - File: MediaDefs.h - - Copyright 1995-1999, Be Incorporated - This file may be used under the terms of the Be Sample Code License. - -******************************************************************************/ -#ifndef _R3_MEDIA_DEFS_H -#define _R3_MEDIA_DEFS_H - -#include -#include -#if defined(__cplusplus) - #include -#else -/* values for byte_ordering */ -enum { B_BIG_ENDIAN, B_LITTLE_ENDIAN }; - -/* values for sample_format */ -enum { - B_UNDEFINED_SAMPLES, - B_LINEAR_SAMPLES, - B_FLOAT_SAMPLES, - B_MULAW_SAMPLES - }; -#endif - -/* Buffer header for audio server */ - -typedef struct audio_buffer_header { - int32 buffer_number; - int32 subscriber_count; - bigtime_t time; - int32 reserved_1; - int32 reserved_2; - bigtime_t sample_clock; -} audio_buffer_header; - - -#define B_MEDIA_LEVEL B_REAL_TIME_PRIORITY - -#define B_NO_CHANGE (-1) - -/* ================ - Subscriber IDs and special values - ================ */ - -#define B_NO_SUBSCRIBER_ID ((subscriber_id)-1) -#define B_NO_SUBSCRIBER_NAME "not subscribed" - -#define B_SHARED_SUBSCRIBER_ID ((subscriber_id)-2) -#define B_SHARED_SUBSCRIBER_NAME "shared subscriber" - -/* ================ - Values for sound files and audio streams - ================ */ - - -/* Audio device codes for BAudioSubscriber's - * Get/SetVolume() and EnableDevice() calls - */ -enum { - B_CD_THROUGH=0, - B_LINE_IN_THROUGH, - B_ADC_IN, - B_LOOPBACK, - B_DAC_OUT, - B_MASTER_OUT, - B_SPEAKER_OUT, - B_SOUND_DEVICE_END - }; - -/* ADC input codes */ -enum { - B_CD_IN, - B_LINE_IN, - B_MIC_IN - }; - - -enum { - B_DAC_STREAM = 2354, - B_ADC_STREAM - }; - -#endif -/* #ifndef _R3_MEDIA_DEFS_H*/ diff --git a/src/add-ons/kernel/drivers/bus/Jamfile b/src/add-ons/kernel/drivers/bus/Jamfile index dae876c50f..817b78c74d 100644 --- a/src/add-ons/kernel/drivers/bus/Jamfile +++ b/src/add-ons/kernel/drivers/bus/Jamfile @@ -1,4 +1,4 @@ SubDir HAIKU_TOP src add-ons kernel drivers bus ; -SubInclude HAIKU_TOP src add-ons kernel drivers bus scsi ; SubInclude HAIKU_TOP src add-ons kernel drivers bus pcmcia ; +SubInclude HAIKU_TOP src add-ons kernel drivers bus scsi ; diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp index 3640da720e..0b454a9b90 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp @@ -129,6 +129,7 @@ read_settings(size_t &memorySize, bool &hardwareCursor) static size_t determine_stolen_memory_size(intel_info &info) { +#if 0 // read stolen memory from the PCI configuration of the PCI bridge uint16 memoryConfig = gPCI->read_pci_config(0, 0, 0, INTEL_GRAPHICS_MEMORY_CONTROL, 2); size_t memorySize = 1 << 20; // 1 MB @@ -171,6 +172,10 @@ determine_stolen_memory_size(intel_info &info) } return memorySize; +#endif +// stippi: das sorgt dafür, daß er den Speicher vom BIOS komplett +// wegwirft + return 0; } @@ -315,7 +320,7 @@ intel_extreme_init(intel_info &info) // on demand only, but we're lazy here... info.additional_memory_area = additionalMemoryCreator.Create("intel additional memory", (void **)&additionalMemory, B_ANY_KERNEL_ADDRESS, - totalSize - stolenSize, B_FULL_LOCK, 0); + totalSize - stolenSize, B_FULL_LOCK | B_CONTIGUOUS, 0); if (info.additional_memory_area < B_OK) return info.additional_memory_area; } else diff --git a/src/add-ons/kernel/drivers/ports/Jamfile b/src/add-ons/kernel/drivers/ports/Jamfile new file mode 100644 index 0000000000..05ec19bdd2 --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/Jamfile @@ -0,0 +1,3 @@ +SubDir HAIKU_TOP src add-ons kernel drivers ports ; + +SubInclude HAIKU_TOP src add-ons kernel drivers ports usb_serial ; diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/Jamfile b/src/add-ons/kernel/drivers/ports/usb_serial/Jamfile new file mode 100644 index 0000000000..80d0e38b82 --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/Jamfile @@ -0,0 +1,27 @@ +SubDir HAIKU_TOP src add-ons kernel drivers ports usb_serial ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +local defines = [ FDefines DB_USB_USE_V2_MODULE ] ; + +SubDirCcFlags $(defines) ; + +KernelAddon usb_serial : kernel drivers bin : + driver.c + tracing.c + acm.c + prolific.c + ftdi.c +; + +AddResources usb_serial : usb_serial.rdef ; + + +Package haiku-usb_serial-cvs + : + usb_serial + : + boot home config add-ons kernel drivers bin ; + +Package haiku-usb_serial-cvs : usb_serial.settings.sample + : boot home config settings kernel drivers sample ; diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/ReadMe.html b/src/add-ons/kernel/drivers/ports/usb_serial/ReadMe.html new file mode 100644 index 0000000000..60152ba583 --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/ReadMe.html @@ -0,0 +1,262 @@ + +BeOS driver for USB serial adapters and CDC ACM compatible USB modems + +

BeOS driver for USB serial adapters and CDC ACM compatible USB modems

+ +

Introduction

+

This driver is designed to support following USB serial adapters and modems:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameVendor IDProduct ID
USB CDC ACM-compatible modems:anyany
Prolific PL2303-based adapters:
PL2303 Serial adapter (IODATA USB-RSAQ2)0x067b0x04bb
I/O Data USB serial adapter USB-RSAQ10x04bb0x0a03
Aten Serial adapter"0x05570x2008
TDK USB-PHS Adapter UHA64000x04bf0x0117
Ratoc USB serial adapter REX-USB600x05840xb000 +
PL2303 Serial adapter (ATEN/IOGEAR UC232A)0x067b0x2303
Elecom UC-SGT0x056e0x5003
FTDI-based:
FTDI 8U100AX serial converter0x04030x8372
FTDI 8U232AM serial converter0x04030x6001
+ +
+NOTE that + +There are a lot of USB modems in this world. Not every one can be supported by this driver. +Only CDC ACM-compatible modems will works with it. How you can guess it? Just try to install +this driver and plug your modem in. If you get the usb0 in ports list - it probably works. +If not - obtain the information about your device and +send it to me. +
+NOTE that + +If your computer has the OHCI-compatible USB hardware you are out of luck. This hardware is not +supported by non-Dan0-like versions. See the BeOS.USB.patches vor details and +solutions. +
+NOTE that + +For Dan0 you have to build a special version of binaries. +Read here for details. +
+WARNING!!! + +If your system was patched with BeOS.USB.patches - your system is candidate to crash +trying this driver!! You must very accurate read this. +
+ +What's new: +
+Version: + +History: +
+0.1.0-dev-0 + +very first "development" release. +
+1.0.0-RC-1 + +Release Candidate 1. +
    +
  • Code re-designed +
  • Code is chaged to be compatible with Dan0. +
+
+ + +

1. Installation

+
    +
  • Run install.sh +
  • If all is OK run SerialConnect application and press Alt-D. If you can select the port, that + looks like "usb0" - your device was identified as supported. You can use this "usb" - port as + you do with usual "serial" ones. Good luck! +
  • If something goes wrong - open the Terminal and run the following command: +

    ls /dev/ports/ +

    It lists all ports that present on your system. If you have no "usb0" here but sure, that you + have USB to Serial adapter plugged in your USB port - write an e-mail about your problem. I'll + try to help you. +

+

2. Uninstallation

+
    +
  • Run uninstall.sh +
+ +

3. Problems solving

+
    +
  • If this driver crash your system - reboot and press "Space" during load. In boot menu select + "Disable user add-ons" and continue boot. Uninstall driver and reboot again into normal mode. + Write me a e-mail about this problem. +
+

4. "Unknown" devices

+ + If you have something, that looks like USB->RS232(serial) adapter or USB modem and tried it with + this driver but have no success - download + usb device info tool and use it to get required information. +
    +
  • Unplug all USB devices and hubs from your PC. +
  • Go into Terminal and run the following command: + ls -alR /dev/bus/usb + You should see something like this: +
    +$ ls -alR /dev/bus/usb/
    +/dev/bus/usb:
    +total 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 .
    +drw-r--r--   1 walther  users           0 Jun  1  2003 ..
    +drw-r--r--   1 walther  users           0 May 31 23:16 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 1
    +crw-r--r--   1 walther  users      0,   0 May 31 23:16 unload
    +
    +/dev/bus/usb/0:
    +total 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 .
    +drw-r--r--   1 walther  users           0 May 31 23:16 ..
    +crw-r--r--   1 walther  users      0,   0 May 31 23:16 hub
    +
    +/dev/bus/usb/1:
    +total 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 .
    +drw-r--r--   1 walther  users           0 May 31 23:16 ..
    +crw-r--r--   1 walther  users      0,   0 May 31 23:16 hub
    +
    + +
  • Note this information. +
  • Now plug your USB serial adapter into PC and run ls -alR /dev/bus/usb/ again. +You'll get something slightly different: +
    +$ ls -alR /dev/bus/usb/
    +/dev/bus/usb:
    +total 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 .
    +drw-r--r--   1 walther  users           0 Jun  1  2003 ..
    +drw-r--r--   1 walther  users           0 May 31 23:16 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 1
    +crw-r--r--   1 walther  users      0,   0 May 31 23:16 unload
    +
    +/dev/bus/usb/0:
    +total 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 .
    +drw-r--r--   1 walther  users           0 May 31 23:16 ..
    +crw-r--r--   1 walther  users      0,   0 May 31 23:17 1
    +crw-r--r--   1 walther  users      0,   0 May 31 23:16 hub
    +
    +/dev/bus/usb/1:
    +total 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 .
    +drw-r--r--   1 walther  users           0 May 31 23:16 ..
    +crw-r--r--   1 walther  users      0,   0 May 31 23:16 hub
    +
    + +$ +
  • Compare this results with previous one and look for file, +that appeared. This file is your USB serial adapter. +
  • Unpack downloaded usb_dev_info command and run it with full path to file appeared in +the second listing. For my sample I should run: +usb_dev_info /dev/bus/usb/0/1 +I'll get the following: +
    +$ usb_dev_info /dev/bus/usb/0/1
    +[Device]
    +Class .................. 0
    +Subclass ............... 0
    +Protocol ............... 0
    +Vendor ID .............. 0x067b
    +Product ID ............. 0x2303
    +Version ................ 0x0202
    +Manufacturer String .... ""
    +Product String ......... ""
    +Serial Number .......... ""
    +  [Configuration 0]
    +    [Interface 0]
    +    Class .............. 255
    +    Subclass ........... 0
    +    Protocol ........... 0
    +      [Endpoint 0]
    +      MaxPacketSize .... 10
    +      Interval ......... 1
    +      Type ............. Interrupt
    +      Direction ........ Input
    +      [Endpoint 1]
    +      MaxPacketSize .... 64
    +      Interval ......... 0
    +      Type ............. Bulk
    +      Direction ........ Output
    +      [Endpoint 2]
    +      MaxPacketSize .... 64
    +      Interval ......... 0
    +      Type ............. Bulk
    +      Direction ........ Input
    +
    +
  • Send this information to me with some additional words about your device. +
+ +

What is wrong with BeOS.USB.patches?

+ +All know that "classical" BeOS R5 don't works on OHCI USB hardware. But some time ago on one well-known +BeOS file-sharing network appeared patches for plain R5. Those patches allows to work with OHCI +hardware under this system version. Looks like it is some part of Dan0 or other "leaked" versions. +There are 3 patches in BeOS.USB.patches.zip: +

1. beos-usb-patch, +

2. beos-usb.modem-patch, +

3. beos-usb.modem-patch.sm. +

The Evil is in two last patches. The source of problem - changed functions in tty module. The +Dan0 contains two additional functions in the middle of tty module description table. But the module version +was not changed - it is still v1. So if driver, that was compiled with old tty module layout, will try to use it - system +crashes. Looks like those patches contains the same "enchanced" tty module like in Dan0. So - you should roll back +those modem-patches - restore the previous configuration as described in patches readme. The first one +- "beos-usb-patch" is OK. + +

Information for Dan0 users

+ +The driver is still not working under Dan0 out of box. At first you have no need to use it for ACM-compatible devices, +because Dan0 has it's own implementation of usb_acm driver. There is also one problem with Dan0 - the +"tty" module was chaged in very dangerous way - there is no possibility to create backward compatible +implementation of serial port driver with the new tty interfaces. If you really have one of those USB Serial +Adapters and want to use it under Dan0 - you have to make some hand work. Sorry for this, but I have not +using Dan0 as my main working system. So you must to build Dan0 version by yourself. Thank you for your patience. Below +is an operations you need to install USB serial driver for Dan0: +
    +
  • Obtain the zip archive with the USB Serial driver for R5. +
  • Obtain the zip archive with sources of the driver. +
  • ATTENTION!!! Unplug all USB devices from your PC. You must to do this - in opposite case you +system can crash! +
  • Install the USB Serial driver as was described in this document. +
  • Unpack the sources of the driver, go to Terminal, change dir to unpacked sources and run the +"make" command. You should see many warnings but no errors. +
  • Stay in Terminal and change the current directory to "obj.x86". You should see the "usb_serial" +driver binary if everything went OK. +
  • Now copy the usb_serial to right place: +
    +cp ./usb_serial ~/config/add-ons/kernel/drivers/bin/usb_serial
    +
    +and let the system to know about changes: +
    +rescan usb_serial
    +
    +
  • The last thing you have to do - disable ACM support in this driver: +Open the file /boot/home/config/settings/kernel/drivers/usb_serial in your text editor and add or +uncomment the following string: +
    +support_acm_devices false
    +
    +
  • Now you should have working version of USB Serial driver under Dan0. +
+

Siarzuk Zharski +

http://www.zharik.host.sk/ + \ No newline at end of file diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/acm.c b/src/add-ons/kernel/drivers/ports/usb_serial/acm.c new file mode 100644 index 0000000000..0b2ed7432e --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/acm.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2003 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#include +#include +#include +#include + +#include "driver.h" +#include "acm.h" + +status_t add_acm_device(usb_serial_device *usd, + const usb_configuration_info *uci) +{ + struct usb_endpoint_info *comm_epi = NULL; + struct usb_endpoint_info *data_out_epi = NULL; + struct usb_endpoint_info *data_in_epi = NULL; + status_t status = ENODEV; + int i = 0; + + TRACE_FUNCALLS("> add_acm_device(%08x, %08x)\n", usd, uci); + + for(i=0; i < uci->interface_count; i++){ + usb_interface_descriptor *uid = + uci->interface[i].active->descr; + if(uid->interface_class == USB_INT_CLASS_CDC && + uid->interface_subclass == USB_INT_SUBCLASS_ABSTRACT_CONTROL_MODEL && + uid->num_endpoints == 1){ + comm_epi = uci->interface[i].active->endpoint; + } + + if(uid->interface_class == USB_INT_CLASS_CDC_DATA && + (uid->interface_subclass == 2 || // ????????????? + uid->interface_subclass == USB_INT_SUBCLASS_DATA)){ + if(uid->num_endpoints == 2){ + data_out_epi = &uci->interface[i].active->endpoint[0]; + data_in_epi = &uci->interface[i].active->endpoint[1]; + } + } + if(comm_epi && data_out_epi && data_in_epi) + break; + } + + if(comm_epi && data_out_epi && data_in_epi){ + status = add_device(usd, uci, comm_epi, data_out_epi, data_in_epi); + } + + TRACE_FUNCRET("< add_acm_device returns:%08x\n", status); + return status; +} + +status_t reset_acm_device(usb_serial_device *usd){ + status_t status = B_OK; + TRACE_FUNCALLS("> reset_acm_device(%08x)\n", usd); + TRACE_FUNCRET("< reset_acm_device returns:%08x\n", status); + return status; +} + +status_t set_line_coding_acm(usb_serial_device *usd, + usb_serial_line_coding *line_coding){ + size_t len = 0; + status_t status = B_OK; + TRACE_FUNCALLS("> set_line_coding_acm(%08x, {%d, %02x, %02x, %02x})\n", + usd, line_coding->speed, + line_coding->stopbits, + line_coding->parity, + line_coding->databits); + status = (*usb_m->send_request)(usd->dev, + USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, + SET_LINE_CODING, 0x0, 0x0, + sizeof(usb_serial_line_coding), + line_coding, + sizeof(usb_serial_line_coding), &len); + TRACE_FUNCRET("< set_line_coding_acm returns:%08x\n", status); + return status; +} + +status_t set_control_line_state_acm(usb_serial_device *usd, uint16 state){ + size_t len = 0; + status_t status = B_OK; + TRACE_FUNCALLS("> set_control_line_state_acm(%08x, %04x)\n", usd, state); + status = (*usb_m->send_request)(usd->dev, + USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, + SET_CONTROL_LINE_STATE, state, 0, 0, 0, 0, + &len); + TRACE_FUNCRET("< set_control_line_state_acm returns:%08x\n", status); + return status; +} + +void on_read_acm(usb_serial_device *usd, char **buf, size_t *num_bytes){ +} + +void on_write_acm(usb_serial_device *usd, const char *buf, size_t *num_bytes){ + if(*num_bytes > usd->write_buffer_size) + *num_bytes = usd->write_buffer_size; + memcpy(usd->write_buffer, buf, *num_bytes); +} + +void on_close_acm(usb_serial_device *usd){ + TRACE_FUNCALLS("> add_acm_device(%08x)\n", usd); + (*usb_m->cancel_queued_transfers)(usd->pipe_read); + (*usb_m->cancel_queued_transfers)(usd->pipe_write); + (*usb_m->cancel_queued_transfers)(usd->pipe_control); +} + diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/acm.h b/src/add-ons/kernel/drivers/ports/usb_serial/acm.h new file mode 100644 index 0000000000..e1043cdd6c --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/acm.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2003 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#ifndef _USB_ACM_H_ + #define _USB_ACM_H_ + +status_t add_acm_device(usb_serial_device *usd, + const usb_configuration_info *uci); +status_t reset_acm_device(usb_serial_device *usd); +status_t set_line_coding_acm(usb_serial_device *usd, + usb_serial_line_coding *line_coding); +status_t set_control_line_state_acm(usb_serial_device *usd, uint16 state); +void on_read_acm(usb_serial_device *usd, char **buf, size_t *num_bytes); +void on_write_acm(usb_serial_device *usd, const char *buf, size_t *num_bytes); +void on_close_acm(usb_serial_device *usd); + +#endif //_USB_ACM_H_ diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/driver.c b/src/add-ons/kernel/drivers/ports/usb_serial/driver.c new file mode 100644 index 0000000000..80ae4698c1 --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/driver.c @@ -0,0 +1,867 @@ +/* + * Copyright (c) 2003 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#include +#include +#include +#include +#include +#include /* strerror */ +#include /* strtol */ +#include /* sprintf */ + +#include "driver.h" +#include "acm.h" +#include "prolific.h" +#include "ftdi.h" + +/* driver callbacks forward declarations */ +static status_t usb_serial_open (const char *name, uint32 flags, void** cookie); +static status_t usb_serial_read (void* cookie, + off_t position, void *buf, size_t* num_bytes); +static status_t usb_serial_write (void* cookie, off_t position, + const void* buffer, size_t* num_bytes); +static status_t usb_serial_control (void* cookie, uint32 op, void* arg, size_t len); +static status_t usb_serial_close (void* cookie); +static status_t usb_serial_free (void* cookie); +/* USB notify callbacks forward declarations */ +status_t usb_serial_device_added(const usb_device *dev, void **cookie); +status_t usb_serial_device_removed(void *cookie); + +/* The base name of drivers created in /dev/ports/ directory */ +#define BASENAME_LEN 0x09 /*must be synchronized with below !!!*/ +static const char *basename = "ports/usb%u"; + +/* function pointers for the device hooks entry points */ +device_hooks usb_serial_hooks = { + usb_serial_open, /* -> open entry point */ + usb_serial_close, /* -> close entry point */ + usb_serial_free, /* -> free cookie */ + usb_serial_control, /* -> control entry point */ + usb_serial_read, /* -> read entry point */ + usb_serial_write /* -> write entry point */ +}; +/* USB notify hooks */ +static usb_notify_hooks notify_hooks = { + &usb_serial_device_added, + &usb_serial_device_removed +}; +/* kernel modules */ +usb_module_info *usb_m; /* usb layer */ +tty_module_info *tty_m; /* tty layer */ + +struct tty usb_serial_tty[DEVICES_COUNT]; +struct ddomain usb_serial_dd; +/* hardware devices, supported by this driver. + See description field for human readable names */ +usb_serial_hw usb_serial_hw_devices[] = { + {0, 0, add_acm_device, reset_acm_device, + set_line_coding_acm, set_control_line_state_acm, + on_read_acm, on_write_acm, on_close_acm, + "CDC ACM compatible device"}, + + {VND_PROLIFIC, PROD_PROLIFIC_RSAQ2, + add_prolific_device, reset_prolific_device, + set_line_coding_acm, set_control_line_state_acm, + on_read_acm, on_write_acm, on_close_acm, + "PL2303 Serial adapter (IODATA USB-RSAQ2)"}, + {VND_IODATA, PROD_IODATA_USBRSAQ, + add_prolific_device, reset_prolific_device, + set_line_coding_acm, set_control_line_state_acm, + on_read_acm, on_write_acm, on_close_acm, + "I/O Data USB serial adapter USB-RSAQ1"}, + {VND_ATEN, PROD_ATEN_UC232A, + add_prolific_device, reset_prolific_device, + set_line_coding_acm, set_control_line_state_acm, + on_read_acm, on_write_acm, on_close_acm, + "Aten Serial adapter"}, + {VND_TDK, PROD_TDK_UHA6400, + add_prolific_device, reset_prolific_device, + set_line_coding_acm, set_control_line_state_acm, + on_read_acm, on_write_acm, on_close_acm, + "TDK USB-PHS Adapter UHA6400"}, + {VND_RATOC, PROD_RATOC_REXUSB60, + add_prolific_device, reset_prolific_device, + set_line_coding_acm, set_control_line_state_acm, + on_read_acm, on_write_acm, on_close_acm, + "Ratoc USB serial adapter REX-USB60"}, + {VND_PROLIFIC, PROD_PROLIFIC_PL2303, + add_prolific_device, reset_prolific_device, + set_line_coding_acm, set_control_line_state_acm, + on_read_acm, on_write_acm, on_close_acm, + "PL2303 Serial adapter (ATEN/IOGEAR UC232A)"}, + {VND_ELECOM, PROD_ELECOM_UCSGT, + add_prolific_device, reset_prolific_device, + set_line_coding_acm, set_control_line_state_acm, + on_read_acm, on_write_acm, on_close_acm, + "Elecom UC-SGT"}, + {VND_SOURCENEXT, PROD_SOURCENEXT_KEIKAI8, + add_prolific_device, reset_prolific_device, + set_line_coding_acm, set_control_line_state_acm, + on_read_acm, on_write_acm, on_close_acm, + "SOURCENEXT KeikaiDenwa 8"}, + {VND_SOURCENEXT, PROD_SOURCENEXT_KEIKAI8_CHG, + add_prolific_device, reset_prolific_device, + set_line_coding_acm, set_control_line_state_acm, + on_read_acm, on_write_acm, on_close_acm, + "SOURCENEXT KeikaiDenwa 8 with charger"}, + {VND_HAL, PROD_HAL_IMR001, + add_prolific_device, reset_prolific_device, + set_line_coding_acm, set_control_line_state_acm, + on_read_acm, on_write_acm, on_close_acm, + "HAL Corporation Crossam2+USB"}, + + {VND_FTDI, PROD_8U100AX, + add_ftdi_device, reset_ftdi_device, + set_line_coding_ftdi, set_control_line_state_ftdi, + on_read_ftdi, on_write_ftdi, on_close_ftdi, + "FTDI 8U100AX serial converter"}, + {VND_FTDI, PROD_8U232AM, + add_ftdi_device, reset_ftdi_device, + set_line_coding_ftdi, set_control_line_state_ftdi, + on_read_ftdi, on_write_ftdi, on_close_ftdi, + "FTDI 8U232AM serial converter"}, +}; +/* supported devices*/ +usb_support_descriptor supported_devices[] = { + {USB_DEV_CLASS_COMM, 0, 0, 0, 0}, + {0, 0, 0, VND_PROLIFIC, PROD_PROLIFIC_RSAQ2 }, + {0, 0, 0, VND_IODATA, PROD_IODATA_USBRSAQ }, + {0, 0, 0, VND_ATEN, PROD_ATEN_UC232A }, + {0, 0, 0, VND_TDK, PROD_TDK_UHA6400 }, + {0, 0, 0, VND_RATOC, PROD_RATOC_REXUSB60 }, + {0, 0, 0, VND_PROLIFIC, PROD_PROLIFIC_PL2303 }, + {0, 0, 0, VND_ELECOM, PROD_ELECOM_UCSGT }, + + {0, 0, 0, VND_FTDI, PROD_8U100AX }, + {0, 0, 0, VND_FTDI, PROD_8U232AM }, +}; +/* main devices table locking semaphore */ +sem_id usb_serial_lock = -1; +/* array of pointers to device objects */ +usb_serial_device *usb_serial_devices[DEVICES_COUNT]; +/* the names of "ports" */ +char * usb_serial_names[DEVICES_COUNT + 1]; +/* speed constants, supported by this driver. */ +const uint32 serial_tty_speed[] = { + 0x00000000, //B0 + 0x00000032, //B50 + 0x0000004B, //B75 + 0x0000006E, //B110 + 0x00000086, //B134 + 0x00000096, //B150 + 0x000000C8, //B200 + 0x0000012C, //B300 + 0x00000258, //B600 + 0x000004B0, //B1200 + 0x00000708, //B1800 + 0x00000960, //B2400 + 0x000012C0, //B4800 + 0x00002580, //B9600 + 0x00004B00, //B19200 + 0x00009600, //B38400 + 0x0000E100, //B57600 + 0x0001C200, //B115200 + 0x00038400, //B230400 + 0x00070800, //460800 + 0x000E1000, //921600 +}; + +/* init_hardware - called once the first time the driver is loaded */ +status_t init_hardware (void){ + TRACE("init_hardware\n"); /*special case - no file-logging activated now*/ + return B_OK; +} + +/* init_driver - optional function - called every time the driver + is loaded. */ +status_t init_driver (void){ + int i; + status_t status = B_OK; + load_setting(); + create_log(); + + TRACE_FUNCALLS("init_driver\n"); + + if((status = get_module(B_TTY_MODULE_NAME, (module_info **)&tty_m)) == B_OK){ + if((status = get_module(B_USB_MODULE_NAME, (module_info **)&usb_m)) == B_OK){ + if(tty_m && usb_m){ + for(i = 0; i < DEVICES_COUNT; i++) + usb_serial_devices[i] = 0; + + usb_serial_names[0] = NULL; + load_driver_symbols(DRIVER_NAME); + + (*usb_m->register_driver)(DRIVER_NAME, supported_devices, + SIZEOF(supported_devices), DRIVER_NAME); + (*usb_m->install_notify)(DRIVER_NAME, ¬ify_hooks); + + usb_serial_lock = create_sem(1, DRIVER_NAME"_devices_table_lock"); + }else{ + status = B_ERROR; + TRACE_ALWAYS("init_driver failed: tty_m:%08x usb_m:%08x", tty_m, usb_m); + } + }else + TRACE_ALWAYS("init_driver failed:%lx cannot get a module %s", status, + B_USB_MODULE_NAME); + }else + TRACE_ALWAYS("init_driver failed:%lx cannot get a module %s", status, + B_TTY_MODULE_NAME); + + TRACE_FUNCRET("init_driver returns:%08x\n", status); + return status; +} + +/* uninit_driver - optional function - called every time the driver + is unloaded */ +void uninit_driver (void){ + int i; + TRACE_FUNCALLS("uninit_driver\n"); + + (*usb_m->uninstall_notify)(DRIVER_NAME); + acquire_sem(usb_serial_lock); + + for(i = 0; i < DEVICES_COUNT; i++) + if(usb_serial_devices[i]){ + delete_area(usb_serial_devices[i]->buffers_area); + delete_sem(usb_serial_devices[i]->done_read); + delete_sem(usb_serial_devices[i]->done_write); + free(usb_serial_devices[i]); + usb_serial_devices[i] = 0; + } + + release_sem_etc(usb_serial_lock, 1, B_DO_NOT_RESCHEDULE); + delete_sem(usb_serial_lock); + + for(i = 0; usb_serial_names[i]; i++) + free(usb_serial_names[i]); + + put_module(B_USB_MODULE_NAME); + put_module(B_TTY_MODULE_NAME); +} + +void usb_serial_device_notify_in(void *cookie, + uint32 status, void *data, uint32 actual_len){ + TRACE_FUNCALLS("usb_serial_device_notify_in:cookie:%08x status:%08x data:%08x len:%d\n", cookie, status, data, actual_len); + if(cookie){ + usb_serial_device *usd = ((usb_serial_device_info *)cookie)->device; + usd->actual_len_read = actual_len; + usd->dev_status_read = status; + release_sem(usd->done_read); + } +} + +void usb_serial_device_notify_out(void *cookie, uint32 status, + void *data, uint32 actual_len){ + TRACE_FUNCALLS("usb_serial_device_notify_out:cookie:%08x status:%08x " + "data:%08x len:%d\n", cookie, status, data, actual_len); + if(cookie){ + usb_serial_device *usd = ((usb_serial_device_info *)cookie)->device; + usd->actual_len_write = actual_len; + usd->dev_status_write = status; + release_sem(usd->done_write); + } +} + +status_t usb_serial_device_thread(void *param){ + status_t status = B_ERROR; + usb_serial_device_info *usdi = (usb_serial_device_info *)param; + usb_serial_device *usd = usdi->device; + TRACE_FUNCALLS("usb_serial_device_thread:%08x\n", param); + + while(true){ + size_t i, to_read; + char *buf; + struct ddrover *ddr; + usd->actual_len_read = 0; + usd->dev_status_read = 0; + status = (*usb_m->queue_bulk)(usd->pipe_read, usd->read_buffer, + usd->read_buffer_size, usb_serial_device_notify_in, usdi); + if(status != B_OK){ + TRACE_ALWAYS("usb_serial_device_thread : queue_bulk error : %lx\n", status); + break; + } + + status = acquire_sem_etc(usd->done_read, 1, B_CAN_INTERRUPT, 0); + if(status != B_OK){ + TRACE_ALWAYS("usb_serial_device_thread : acquire_sem_etc : " + "error %08lx (%s)\n", status, strerror(status)); + break; + } + + if(usd->dev_status_read){ + TRACE_ALWAYS("usb_serial_device_thread : dev_status error !!!\n"); + break; + } + + buf = usd->read_buffer; + to_read = usd->actual_len_read; + (*usd->hw->on_read)(usd, &buf, &to_read); + + if(!to_read) + continue; + + ddr = (*tty_m->ddrstart)(NULL); + if(!ddr){ + TRACE_ALWAYS("usb_serial_device_thread : ddrstart problem !!!\n"); + status = B_NO_MEMORY; + break; + } + + (*tty_m->ttyilock)(usd->tty, ddr, true); + for(i = 0; i < to_read; i++){ + (*tty_m->ttyin)(usd->tty, ddr, buf[i]); + } + (*tty_m->ttyilock)(usd->tty, ddr, false); + (*tty_m->ddrdone)(ddr); + } + + TRACE_FUNCRET("usb_serial_device_thread returns %08x\n", status); + return status; +} + +void usb_serial_setmodes(usb_serial_device *usd){ + usb_serial_line_coding line_coding; + struct termios tios; + + int newctrl, baud_index; + TRACE_FUNCALLS("usb_serial_setmodes:%08x\n", usd); + + memcpy(&tios, &usd->tty->t, sizeof(struct termios)); + newctrl = usd->ctrlout; + + TRACE_FUNCRES(trace_termios, &tios); + TRACE("newctrl:%08x\n", newctrl); + + baud_index = tios.c_cflag & CBAUD; + if(baud_index > SIZEOF(serial_tty_speed)) + baud_index = SIZEOF(serial_tty_speed) - 1; + + line_coding.speed = serial_tty_speed[baud_index]; + line_coding.stopbits = ( tios.c_cflag & CSTOPB ) ? LC_STOP_BIT_2 : LC_STOP_BIT_1; + + if(PARENB & tios.c_cflag){ + line_coding.parity = LC_PARITY_EVEN; + + if(PARODD & tios.c_cflag){ + line_coding.parity = LC_PARITY_ODD; + } + }else + line_coding.parity = LC_PARITY_NONE; + + line_coding.databits = (tios.c_cflag & CS8) ? 8 : 7; + + if(line_coding.speed == 0){ + newctrl &= 0xfffffffe; + line_coding.speed = usd->line_coding.speed; + }else + newctrl = CLS_LINE_DTR; + + if(usd->ctrlout != newctrl ){ + usd->ctrlout = newctrl; + TRACE("newctrl send to modem:%08x\n", newctrl); + (*usd->hw->set_control_line_state)(usd, newctrl); + } + + if(memcmp (&line_coding, &usd->line_coding, sizeof(usb_serial_line_coding))){ + usd->line_coding.speed = line_coding.speed; + usd->line_coding.stopbits = line_coding.stopbits; + usd->line_coding.databits = line_coding.databits; + usd->line_coding.parity = line_coding.parity; + TRACE("send to modem:speed %d sb:%08x db:%08x parity:%08x\n", + usd->line_coding.speed, usd->line_coding.stopbits, + usd->line_coding.databits, usd->line_coding.parity); + (*usd->hw->set_line_coding)(usd, &usd->line_coding); + } +} + +bool usb_serial_service(struct tty *ptty, struct ddrover *ddr, uint flags){ + int i; + bool bret = false; + usb_serial_device *usd; + TRACE_FUNCALLS("usb_serial_service:%08x ddr:%08x flags:%08x\n", ptty, ddr, flags); + + for(i = 0; i < DEVICES_COUNT; i++){ + if(usb_serial_devices[i]){ + if(ptty == usb_serial_devices[i]->tty){ + usd = usb_serial_devices[i]; + break; + } + } + } + + if(usd){ + if(flags <= TTYGETSIGNALS){ + switch(flags){ + case TTYENABLE: + (*tty_m->ttyhwsignal)(ptty, ddr, TTYHWDCD, false); + (*tty_m->ttyhwsignal)(ptty, ddr, TTYHWCTS, true); + + usd->ctrlout = CLS_LINE_DTR | CLS_LINE_RTS; + (*usd->hw->set_control_line_state)(usd, usd->ctrlout); + break; + + case TTYDISABLE: + + (*tty_m->ttyhwsignal)(ptty, ddr, TTYHWDCD, false); + + usd->ctrlout = 0x0; + (*usd->hw->set_control_line_state)(usd, usd->ctrlout); + break; + + case TTYISTOP: + (*tty_m->ttyhwsignal)(ptty, ddr, TTYHWCTS, false); + break; + + case TTYIRESUME: + (*tty_m->ttyhwsignal)(ptty, ddr, TTYHWCTS, true); + break; + + case TTYGETSIGNALS: + (*tty_m->ttyhwsignal)(ptty, ddr, TTYHWDCD, true); + (*tty_m->ttyhwsignal)(ptty, ddr, TTYHWCTS, true); + (*tty_m->ttyhwsignal)(ptty, ddr, TTYHWDSR, false); + (*tty_m->ttyhwsignal)(ptty, ddr, TTYHWRI, false); + break; + + case TTYSETMODES: + usb_serial_setmodes(usd); + break; + + case TTYOSTART: + case TTYOSYNC: + case TTYSETBREAK: + case TTYCLRBREAK: + case TTYSETDTR: + case TTYCLRDTR: + break; + } + } + bret = true; + } + + TRACE_FUNCRET("usb_serial_service returns %d\n", bret); + return bret; +} + +void usb_serial_notify_interrupt(void *cookie, uint32 status, + void *data, uint32 actual_len){ + TRACE_FUNCALLS("usb_serial_notify_interrupt : %p %lx %p %ld\n", + cookie, status, data, actual_len); + if(cookie){ + usb_serial_device *usd = ((usb_serial_device_info *)cookie)->device; + usd->actual_len_interrupt = actual_len; + usd->dev_status_interrupt = status; + } +} + +/* usb_serial_open - handle open() calls */ +static status_t usb_serial_open (const char *name, uint32 flags, void** cookie){ + int i; + status_t status = ENODEV; + TRACE_FUNCALLS("usb_serial_open:%s flags:%d cookie:%08x\n", + name, flags, cookie); + + for(i=0;i= 0 && i < DEVICES_COUNT){ + acquire_sem(usb_serial_lock); + if(usb_serial_devices[i]){ + usb_serial_device_info *usdi = malloc(sizeof(usb_serial_device_info)); + if(usdi){ + struct ddrover *ddr; + memset(usdi, 0, sizeof(usb_serial_device_info)); + *cookie = usdi; + + TRACE("cookie in open:%08x\n", *cookie); + + usdi->device = usb_serial_devices[i]; + + (*tty_m->ttyinit)(&usb_serial_tty[i], true); + + usdi->ttyfile.tty = &usb_serial_tty[i]; + usdi->ttyfile.flags = flags; + usb_serial_devices[i]->tty = &usb_serial_tty[i]; + + (*usdi->device->hw->reset_device)(usdi->device); + + TRACE("Opened:%s %08x\n", usdi->device->hw->descr, usdi->device->dev); + + ddr = (*tty_m->ddrstart)(NULL); + if(ddr){ + (*tty_m->ddacquire)(ddr, &usb_serial_dd); + status = (*tty_m->ttyopen)(&usdi->ttyfile, ddr, usb_serial_service); + (*tty_m->ddrdone)(ddr); + + if(status == B_OK){ + sem_id sem = spawn_kernel_thread(usb_serial_device_thread, + "usb_serial_device_thread", 0xa, usdi); + if(sem != -1) + resume_thread(sem); + else + TRACE_ALWAYS("usb_serial_open: cannot spawn kernel thread!!!\n"); + + usdi->device->ctrlout = CLS_LINE_DTR | CLS_LINE_RTS; + (*usdi->device->hw->set_control_line_state)(usdi->device, + usdi->device->ctrlout); + + status = (*usb_m->queue_interrupt)(usdi->device->pipe_control, + usdi->device->interrupt_buffer, + usdi->device->interrupt_buffer_size, + usb_serial_notify_interrupt, usdi); + } + }else + status = B_NO_MEMORY; + + if(status != B_OK) + free(usdi); + }else + status = B_NO_MEMORY; + } + release_sem(usb_serial_lock); + } + + TRACE_FUNCRET("usb_serial_open returns:%08x\n", status); + return status; +} + +/* usb_serial_read - handle read() calls */ +static status_t usb_serial_read (void* cookie, off_t position, + void *buf, size_t* num_bytes){ + status_t status = B_OK; + struct ddrover *ddr; + TRACE_FUNCALLS("usb_serial_read:%08x position:%Ld buf:%08x len:%d\n", + cookie, position, buf, *num_bytes); + + ddr = (*tty_m->ddrstart)(NULL); + if(ddr){ + if(cookie) + status = (*tty_m->ttyread)(cookie, ddr, buf, num_bytes); + else + (*tty_m->ddacquire)(ddr, &usb_serial_dd); + (*tty_m->ddrdone)(ddr); + }else{ + TRACE_ALWAYS("usb_serial_read : ddrstart problem !!!\n"); + status = B_NO_MEMORY; + } + + TRACE_FUNCRET("usb_serial_read returns:%08x readed:%d\n", status, *num_bytes); + return status; +} + +/* usb_serial_write - handle write() calls */ + +static status_t usb_serial_write (void* cookie, off_t position, + const void* buffer, size_t* num_bytes){ + status_t status = B_OK; + usb_serial_device_info *usdi = (usb_serial_device_info *)cookie; + usb_serial_device *usd = usdi->device; + size_t to_write = *num_bytes; + TRACE_FUNCALLS("usb_serial_write:%08x position:%Ld buf:%08x len:%d\n", + cookie, position, buffer, *num_bytes); + *num_bytes = 0; /* tell caller nothing was written */ + + while(to_write > 0){ + size_t len = to_write; + + (*usd->hw->on_write)(usd, buffer, &len); + + usd->actual_len_write = 0; + usd->dev_status_write = 0; + + status = (*usb_m->queue_bulk)(usd->pipe_write, usd->write_buffer, + len, usb_serial_device_notify_out, cookie); + if(status != B_OK){ + TRACE_ALWAYS("usb_serial_write : dev %p status %lx", cookie, status); + break; + } + + status = acquire_sem_etc(usd->done_write, 1, B_CAN_INTERRUPT, 0); + if(status != B_OK){ + TRACE_ALWAYS("usb_serial_write : acquire_sem_etc() %lx (%s)", + status, strerror(status)); + break; + } + + ((const char*)buffer) += usd->actual_len_write; + *num_bytes += usd->actual_len_write; + to_write -= usd->actual_len_write; + } + + TRACE_FUNCRET("usb_serial_write returns:%08x written:%d\n", status, *num_bytes); + return status; +} + +/* usb_serial_control - handle ioctl calls */ +static status_t usb_serial_control (void* cookie, uint32 op, void* arg, size_t len){ + status_t status = B_BAD_VALUE; + TRACE_FUNCALLS("usb_serial_control cookie:%08x op:%08x arg:%08x len:%d\n", + cookie, op, arg, len); + + if(cookie){ + struct ddrover *ddr = (*tty_m->ddrstart)(NULL); + if(ddr){ + status = (*tty_m->ttycontrol)(cookie, ddr, op, arg, len); + (*tty_m->ddrdone)(ddr); + }else + status = B_NO_MEMORY; + }else + status = ENODEV; + + TRACE_FUNCRET("usb_serial_control returns:%08x\n", status); + return status; +} + +/* usb_serial_close - handle close() calls */ +static status_t usb_serial_close (void* cookie){ + status_t status = ENODEV; + TRACE_FUNCALLS("usb_serial_close:%08x\n", cookie); + + if(cookie){ + usb_serial_device_info *usdi = (usb_serial_device_info *)cookie; + usb_serial_device *usd = usdi->device; + struct ddrover *ddr; + + (*usd->hw->on_close)(usd); + + ddr = (*tty_m->ddrstart)(NULL); + if(ddr){ + status = (*tty_m->ttyclose)(cookie, ddr); + (*tty_m->ddrdone)(ddr); + }else + status = B_NO_MEMORY; + } + + TRACE_FUNCRET("usb_serial_close returns:%08x\n", status); + return status; +} + +/* usb_serial_free - called after the last device is closed, and after + all i/o is complete.*/ +static status_t usb_serial_free (void* cookie){ + status_t status = B_OK; + TRACE_FUNCALLS("usb_serial_free:%08x\n", cookie); + + if(cookie){ + struct ddrover *ddr = (*tty_m->ddrstart)(NULL); + if(ddr){ + status = (*tty_m->ttyfree)(cookie, ddr); + (*tty_m->ddrdone)(ddr); + }else + status = B_NO_MEMORY; + free(cookie); + } + + TRACE_FUNCRET("usb_serial_free returns:%08x\n", status); + return status; +} + +/* publish_devices - return a null-terminated array of devices + supported by this driver. */ +const char** publish_devices(){ + int i, j; + TRACE_FUNCALLS("publish_devices\n"); + + for(i=0; usb_serial_names[i]; i++) + free(usb_serial_names[i]); + + acquire_sem(usb_serial_lock); + for(i=0, j=0; i < DEVICES_COUNT; i++){ + if(usb_serial_devices[i]){ + usb_serial_names[j] = malloc(strlen(basename + 2)); + if(usb_serial_names[j]){ + sprintf(usb_serial_names[j], basename, i); + j++; + } + else + TRACE_ALWAYS("publish_devices - NO MEMORY\n"); + } + } + usb_serial_names[j] = NULL; + release_sem(usb_serial_lock); + + return (const char **)&usb_serial_names[0]; +} + +/* find_device - return ptr to device hooks structure for a + given device name */ +device_hooks* find_device(const char* name){ + TRACE_FUNCALLS("find_device(%s)\n", name); + return &usb_serial_hooks; +} + +status_t add_device(usb_serial_device *usd, const usb_configuration_info *uci, + usb_endpoint_info *comm_epi, + usb_endpoint_info *data_out_epi, + usb_endpoint_info *data_in_epi){ + char name[32]; + status_t status = ENODEV; + size_t buf_len; + int i = 0; + + TRACE_FUNCALLS("add_device(%08x, %08x, %08x, %08x, %08x)\n", + usd, uci, comm_epi, data_in_epi, data_out_epi); + + acquire_sem(usb_serial_lock); + + for(i = 0; i < DEVICES_COUNT; i++){ + if(usb_serial_devices[i] != NULL) + continue; + + usb_serial_devices[i] = usd; + + usd->active = 1; + usd->open = 0; + + sprintf(name, "usb_serial:%d:done_read", i ); + usd->done_read = create_sem(0, name); + + sprintf(name, "usb_serial:%d:done_write", i); + usd->done_write = create_sem(0, name); + + usd->tty = NULL; + + buf_len = usd->read_buffer_size + usd->write_buffer_size + + usd->interrupt_buffer_size; + + usd->buffers_area = create_area("usb_serial:buffers_area", + (void *)&usd->read_buffer, + B_ANY_KERNEL_ADDRESS, + ROUNDUP(buf_len, B_PAGE_SIZE), + B_CONTIGUOUS, B_READ_AREA|B_WRITE_AREA); + + usd->write_buffer = usd->read_buffer + usd->read_buffer_size; + usd->interrupt_buffer = usd->write_buffer + usd->write_buffer_size; + + (*usb_m->set_configuration)(usd->dev, uci); + + usd->pipe_control = (comm_epi) ? comm_epi->handle : 0; + usd->pipe_write = data_out_epi->handle; + usd->pipe_read = data_in_epi->handle; + + status = B_OK; + break; + } + + release_sem(usb_serial_lock); + + TRACE_FUNCRET("add_device returns:%08x\n", status); + return status; +} + + +status_t usb_serial_device_added(const usb_device *dev, void **cookie){ + int i; + status_t status = B_OK; + const usb_device_descriptor *udd; + usb_serial_device *usd = 0; + TRACE_FUNCALLS("usb_serial_device_added:%08x cookie:%08x\n", dev, cookie); + + udd = (*usb_m->get_device_descriptor)(dev); + + TRACE_ALWAYS("Probing device: %08x/%08x\n", udd->vendor_id, udd->product_id); + + *cookie = 0; + for(i=1; i < sizeof(usb_serial_hw_devices)/sizeof(usb_serial_hw_devices[0]); i++) + if(usb_serial_hw_devices[i].vendor_id == udd->vendor_id + && usb_serial_hw_devices[i].product_id == udd->product_id){ + const usb_configuration_info *uci; + uci = (*usb_m->get_nth_configuration)(dev, 0); + if(uci){ + usd = malloc(sizeof(usb_serial_device)); + if(usd){ + usd->dev = dev; + usd->hw = &usb_serial_hw_devices[i]; + usd->read_buffer_size = + usd->write_buffer_size = + usd->interrupt_buffer_size = ROUNDUP(DEF_BUFFER_SIZE, 16); + if((status = (*usb_serial_hw_devices[i].add_device)(usd, uci)) == B_OK){ + *cookie = dev; + TRACE_ALWAYS("%s (%04x/%04x) added \n", + usb_serial_hw_devices[i].descr, + usb_serial_hw_devices[i].vendor_id, + usb_serial_hw_devices[i].product_id); + }else + free(usd); + }else + status = B_NO_MEMORY; + } + break; + } + + if(!*cookie){ + if(b_acm_support && + udd->device_class == USB_DEV_CLASS_COMM && + udd->device_subclass == 0 && + udd->device_protocol == 0 ){ + const usb_configuration_info *uci; + uint16 idx = 0; + do{ + uci = (*usb_m->get_nth_configuration)(dev, idx++); + if(uci){ + if(uci->interface_count != 2) + continue; + usd = malloc(sizeof(usb_serial_device)); + if(usd){ + usd->dev = dev; + usd->hw = &usb_serial_hw_devices[0]; + usd->read_buffer_size = + usd->write_buffer_size = + usd->interrupt_buffer_size = ROUNDUP(DEF_BUFFER_SIZE, 16); + if((status = (*usb_serial_hw_devices[0].add_device)(usd, uci)) == B_OK){ + *cookie = dev; + TRACE_ALWAYS("%s (%04x/%04x) added \n", + usb_serial_hw_devices[0].descr, + udd->vendor_id, udd->product_id); + }else + free(usd); + }else + status = B_NO_MEMORY; + } + }while(uci); + }else{ + TRACE_ALWAYS("device has wrong class, subclass and protocol\n"); + status = B_ERROR; + } + } + TRACE_FUNCRET("usb_serial_device_added returns:%08x\n", status); + return status; +} + +status_t usb_serial_device_removed(void *cookie){ + int i; + status_t status = B_OK; + usb_device *ud = (usb_device *) cookie; + TRACE_FUNCALLS("usb_serial_device_removed:%08x\n", cookie); + + acquire_sem(usb_serial_lock); + + for(i = 0; i < DEVICES_COUNT; i++ ){ + usb_serial_device *usd = usb_serial_devices[i]; + if(usd){ + if(ud == usd->dev){ + usd->active = 0; + if(!usd->open) + break; + + delete_area(usd->buffers_area); + delete_sem(usd->done_read); + delete_sem(usd->done_write); + free(usd); + usb_serial_devices[i] = 0; + } + } + } + + release_sem(usb_serial_lock); + + TRACE_FUNCRET("usb_serial_device_removed returns:%08x\n", status); + return status; +} + diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/driver.h b/src/add-ons/kernel/drivers/ports/usb_serial/driver.h new file mode 100644 index 0000000000..885fd642cf --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/driver.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2003 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#ifndef _USB_SERIAL_DRIVER_H_ + #define _USB_SERIAL_DRIVER_H_ + +/* The name of this driver ... */ +#define DRIVER_NAME "usb_serial" +/* Maximal count of devices supported by this driver at the same time. */ +#define DEVICES_COUNT 20 + +#include "tracing.h" + +/* Some usefull helper defines ... */ +#define SIZEOF(array) (sizeof(array)/sizeof(array[0])) /* size of array */ +/* This one rounds the size to integral count of segs (segments) */ +#define ROUNDUP(size, seg) (((size) + (seg) - 1) & ~((seg) - 1)) +/* buffer size */ +#define DEF_BUFFER_SIZE 0x100 + +/* line coding defines ... Come from CDC USB specs? */ +#define LC_STOP_BIT_1 0 +#define LC_STOP_BIT_2 2 + +#define LC_PARITY_NONE 0 +#define LC_PARITY_ODD 1 +#define LC_PARITY_EVEN 2 +/* struct that represents line coding */ +typedef struct _s_usb_serial_line_coding{ + uint32 speed; + uint8 stopbits; + uint8 parity; + uint8 databits; +} usb_serial_line_coding; + +/* "forgotten" requests for CDC ACM devices */ +#define SET_LINE_CODING 0x20 +#define SET_CONTROL_LINE_STATE 0x22 + +/* control line states */ +#define CLS_LINE_DTR 0x0001 +#define CLS_LINE_RTS 0x0002 + +/* "forgotten" attributes etc ...*/ +#define USB_EP_ADDR_DIR_IN 0x80 +#define USB_EP_ADDR_DIR_OUT 0x00 + +#define USB_EP_ATTR_CONTROL 0x00 +#define USB_EP_ATTR_ISOCHRONOUS 0x01 +#define USB_EP_ATTR_BULK 0x02 +#define USB_EP_ATTR_INTERRUPT 0x03 +/* USB class - communication devices */ +#define USB_DEV_CLASS_COMM 0x02 + +#define USB_INT_CLASS_CDC 0x02 +#define USB_INT_SUBCLASS_ABSTRACT_CONTROL_MODEL 0x02 + +#define USB_INT_CLASS_CDC_DATA 0x0a +#define USB_INT_SUBCLASS_DATA 0x00 + +/* a kind of forward declaration */ +typedef struct _s_usb_serial_device usb_serial_device; + +/* usb_serial_hw - represents the different hardware devices */ +typedef struct _s_usb_serial_hw{ + uint16 vendor_id; /* vendor id and card id of device */ + uint16 product_id; + /* callbacks used in "customization" of the driver behaviour */ + status_t (*add_device)(usb_serial_device *usd, + const usb_configuration_info *uci); + status_t (*reset_device)(usb_serial_device *usd); + status_t (*set_line_coding)(usb_serial_device *usd, + usb_serial_line_coding *line_coding); + status_t (*set_control_line_state)(usb_serial_device *usd, uint16 state); + void (*on_read)(usb_serial_device *usd, char **buf, size_t *num_bytes); + void (*on_write)(usb_serial_device *usd, const char *buf, + size_t *num_bytes); + void (*on_close)(usb_serial_device *usd); + const char *descr; /* informational description */ +}usb_serial_hw; + +status_t add_device(usb_serial_device *usd, const usb_configuration_info *uci, + usb_endpoint_info *comm_epi, + usb_endpoint_info *data_out_epi, + usb_endpoint_info *data_in_epi); + +/* this one was typedefed into usb_serial_device - see above for details + this struct represents the main device object */ +struct _s_usb_serial_device{ + int active; /* is device active - performing some tasks */ + int32 open; /* is device opened */ + const usb_device *dev; /* points to usb device handle */ + /* communication pipes */ + usb_pipe *pipe_control; + usb_pipe *pipe_read; + usb_pipe *pipe_write; + /* line coding */ + usb_serial_line_coding line_coding; + + /* data buffers */ + area_id buffers_area; + /* read buffer */ + char *read_buffer; + size_t read_buffer_size; + /* write buffer */ + char *write_buffer; + size_t write_buffer_size; + /* interrupt buffer */ + char *interrupt_buffer; + size_t interrupt_buffer_size; + + /* variables used in callback functionality */ + size_t actual_len_read; + uint32 dev_status_read; + size_t actual_len_write; + uint32 dev_status_write; + size_t actual_len_interrupt; + uint32 dev_status_interrupt; + /* semaphores used in callbacks */ + sem_id done_read; + sem_id done_write; + + uint16 ctrlout; + + struct tty *tty; + + usb_serial_hw *hw; /* points to corresponding hardware description */ + /* place for device specific data */ + union{ + struct _spec_acm{ /* ACM-compatible devices */ + }acm; + struct _spec_prolific{ /* Prolific devices*/ + }prolific; + struct _spec_ftdi{ /* FTDI devices*/ + uint8 hdrlen; + uint8 status_msr; + uint8 status_lsr; + }ftdi; + }spec; +}; /*already typedef-ed - see comment above! */ +/* high-level of abstraction of the device*/ +typedef struct _s_usb_serial_device_info{ + struct ttyfile ttyfile; /* */ + usb_serial_device *device; /* */ +}usb_serial_device_info; + +extern usb_serial_device *usb_serial_devices[]; +extern char * usb_serial_names[]; +extern usb_module_info *usb_m; + +#endif//_USB_SERIAL_DRIVER_H_ diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/ftdi.c b/src/add-ons/kernel/drivers/ports/usb_serial/ftdi.c new file mode 100644 index 0000000000..7bcfc3deee --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/ftdi.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2003 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#include +#include +#include +#include +#include + +#include "driver.h" +#include "ftdi.h" +#include "uftdireg.h" + + +status_t add_ftdi_device(usb_serial_device *usd, + const usb_configuration_info *uci) +{ + struct usb_endpoint_info *comm_epi = NULL; + struct usb_endpoint_info *data_out_epi = NULL; + struct usb_endpoint_info *data_in_epi = NULL; + status_t status = ENODEV; + int i = 0; + + TRACE_FUNCALLS("> add_ftdi_device(%08x, %08x)\n", usd, uci); + + if(uci->interface_count){ + struct usb_interface_info *uii = uci->interface[0].active; + for(i = 0; i < uii->endpoint_count; i++){ + if(uii->endpoint[i].descr->attributes == USB_EP_ATTR_BULK){ + if((uii->endpoint[i].descr->endpoint_address & USB_EP_ADDR_DIR_IN) + == USB_EP_ADDR_DIR_IN){ + data_in_epi = &uii->endpoint[i]; + }else{ + if(uii->endpoint[i].descr->endpoint_address + /*USB_EP_ADDR_DIR_OUT = 0x0*/){ + comm_epi = data_out_epi = &uii->endpoint[i]; + } + } + } + } + + if(comm_epi && data_in_epi && data_out_epi){ + if(usd->hw->product_id == PROD_8U100AX) + usd->spec.ftdi.hdrlen = 1; + else + usd->spec.ftdi.hdrlen = 0; + + usd->read_buffer_size = + usd->write_buffer_size = + usd->interrupt_buffer_size = ROUNDUP(FTDI_BUF_SIZE, 16); + status = add_device(usd, uci, comm_epi, data_out_epi, data_in_epi); + } + } + + TRACE_FUNCRET("< add_ftdi_device returns:%08x\n", status); + return status; +} + +status_t reset_ftdi_device(usb_serial_device *usd){ + status_t status = B_OK; + size_t len = 0; + TRACE_FUNCALLS("> reset_ftdi_device(%08x)\n", usd); + status = (*usb_m->send_request)(usd->dev, + USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, + FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, + FTDI_PIT_DEFAULT, 0, 0, 0, &len); + TRACE_FUNCRET("< reset_ftdi_device returns:%08x\n", status); + return status; +} + +status_t set_line_coding_ftdi(usb_serial_device *usd, + usb_serial_line_coding *line_coding){ + status_t status = B_OK; + int32 rate, data = 0; + size_t len1 = 0, len2 = 0; + TRACE_FUNCALLS("> set_line_coding_ftdi(%08x, {%d, %02x, %02x, %02x})\n", + usd, line_coding->speed, + line_coding->stopbits, + line_coding->parity, + line_coding->databits); + + if(usd->hw->product_id == PROD_8U100AX){ + switch (line_coding->speed){ + case 300: rate = ftdi_sio_b300; break; + case 600: rate = ftdi_sio_b600; break; + case 1200: rate = ftdi_sio_b1200; break; + case 2400: rate = ftdi_sio_b2400; break; + case 4800: rate = ftdi_sio_b4800; break; + case 9600: rate = ftdi_sio_b9600; break; + case 19200: rate = ftdi_sio_b19200; break; + case 38400: rate = ftdi_sio_b38400; break; + case 57600: rate = ftdi_sio_b57600; break; + case 115200: rate = ftdi_sio_b115200; break; + default: + rate = ftdi_sio_b19200; + TRACE_ALWAYS("= set_line_coding_ftdi: Datarate:%d is not supported " + "by this hardware. Defaulted to %d\n", + line_coding->speed, rate); + break; + } + }else{ + switch(line_coding->speed){ + case 300: rate = ftdi_8u232am_b300; break; + case 600: rate = ftdi_8u232am_b600; break; + case 1200: rate = ftdi_8u232am_b1200; break; + case 2400: rate = ftdi_8u232am_b2400; break; + case 4800: rate = ftdi_8u232am_b4800; break; + case 9600: rate = ftdi_8u232am_b9600; break; + case 19200: rate = ftdi_8u232am_b19200; break; + case 38400: rate = ftdi_8u232am_b38400; break; + case 57600: rate = ftdi_8u232am_b57600; break; + case 115200: rate = ftdi_8u232am_b115200; break; + case 230400: rate = ftdi_8u232am_b230400; break; + case 460800: rate = ftdi_8u232am_b460800; break; + case 921600: rate = ftdi_8u232am_b921600; break; + default: + rate = ftdi_sio_b19200; + TRACE_ALWAYS("= set_line_coding_ftdi: Datarate:%d is not supported " + "by this hardware. Defaulted to %d\n", + line_coding->speed, rate); + break; + } + } + + status = (*usb_m->send_request)(usd->dev, + USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, + FTDI_SIO_SET_BAUD_RATE, rate, + FTDI_PIT_DEFAULT, 0, 0, 0, &len1); + if(status != B_OK) + TRACE_ALWAYS("= set_line_coding_ftdi: datarate set request failed:%08x", + status); + + switch(line_coding->stopbits){ + case LC_STOP_BIT_2: data = FTDI_SIO_SET_DATA_STOP_BITS_2; break; + case LC_STOP_BIT_1: data = FTDI_SIO_SET_DATA_STOP_BITS_1; break; + default: + TRACE_ALWAYS("= set_line_coding_ftdi: Wrong stopbits param:%d", + line_coding->stopbits); + break; + } + + switch(line_coding->parity){ + case LC_PARITY_NONE: data |= FTDI_SIO_SET_DATA_PARITY_NONE; break; + case LC_PARITY_EVEN: data |= FTDI_SIO_SET_DATA_PARITY_EVEN; break; + case LC_PARITY_ODD: data |= FTDI_SIO_SET_DATA_PARITY_ODD; break; + default: + TRACE_ALWAYS("= set_line_coding_ftdi: Wrong parity param:%d", + line_coding->parity); + break; + } + + switch(line_coding->databits){ + case 8: data |= FTDI_SIO_SET_DATA_BITS(8); break; + case 7: data |= FTDI_SIO_SET_DATA_BITS(7); break; + default: + TRACE_ALWAYS("= set_line_coding_ftdi: Wrong databits param:%d", + line_coding->databits); + break; + } + + status = (*usb_m->send_request)(usd->dev, + USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, + FTDI_SIO_SET_DATA, data, + FTDI_PIT_DEFAULT, 0, 0, 0, &len2); + if(status != B_OK) + TRACE_ALWAYS("= set_line_coding_ftdi: data set request failed:%08x", + status); + + TRACE_FUNCRET("< set_line_coding_ftdi returns:%08x\n", status); + return status; +} + +status_t set_control_line_state_ftdi(usb_serial_device *usd, uint16 state){ + status_t status = B_OK; + int32 ctrl; + size_t len = 0; + TRACE_FUNCALLS("> set_control_line_state_ftdi(%08x, %04x)\n", usd, state); + + ctrl = (state & CLS_LINE_RTS) ? + FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW; + ctrl |= (state & CLS_LINE_DTR) ? + FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW; + status = (*usb_m->send_request)(usd->dev, + USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, + FTDI_SIO_MODEM_CTRL, ctrl, + FTDI_PIT_DEFAULT, 0, 0, 0, &len); + if(status != B_OK) + TRACE_ALWAYS("= set_control_line_state_ftdi: control set request " + "failed:%08x", status); + + TRACE_FUNCRET("< set_control_line_state_ftdi returns:%08x\n", status); + return status; +} + +void on_read_ftdi(usb_serial_device *usd, char **buf, size_t *num_bytes){ + usd->spec.ftdi.status_msr = FTDI_GET_MSR(*buf); + usd->spec.ftdi.status_lsr = FTDI_GET_LSR(*buf); + TRACE("MSR:%02x LSR:%02x\n", usd->spec.ftdi.status_msr, + usd->spec.ftdi.status_lsr); + *buf += 2; + *num_bytes -= 2; +} + +void on_write_ftdi(usb_serial_device *usd, const char *buf, + size_t *num_bytes){ + char *buf_to = usd->write_buffer; + int hdrlen = usd->spec.ftdi.hdrlen; + TRACE("hdrlen:%d\n", hdrlen); + if(*num_bytes > usd->write_buffer_size - hdrlen) + *num_bytes = usd->write_buffer_size - hdrlen; + if(hdrlen > 0) + *buf_to = FTDI_OUT_TAG(*num_bytes, FTDI_PIT_DEFAULT); + memcpy(buf_to + hdrlen, buf, *num_bytes); + *num_bytes += hdrlen; +} + +void on_close_ftdi(usb_serial_device *usd){ + TRACE_FUNCALLS("> on_close_ftdi(%08x)\n", usd); + (*usb_m->cancel_queued_transfers)(usd->pipe_read); + (*usb_m->cancel_queued_transfers)(usd->pipe_write); +} + diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/ftdi.h b/src/add-ons/kernel/drivers/ports/usb_serial/ftdi.h new file mode 100644 index 0000000000..5f80bb1c48 --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/ftdi.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2003 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#ifndef _USB_FTDI_H_ + #define _USB_FTDI_H_ + +#define VND_FTDI 0x0403 + +#define PROD_8U100AX 0x8372 +#define PROD_8U232AM 0x6001 + +#define FTDI_BUF_SIZE 0x40 + +status_t add_ftdi_device(usb_serial_device *usd, + const usb_configuration_info *uci); +status_t reset_ftdi_device(usb_serial_device *usd); +status_t set_line_coding_ftdi(usb_serial_device *usd, + usb_serial_line_coding *line_coding); +status_t set_control_line_state_ftdi(usb_serial_device *usd, uint16 state); +void on_read_ftdi(usb_serial_device *usd, char **buf, size_t *num_bytes); +void on_write_ftdi(usb_serial_device *usd, const char *buf, size_t *num_bytes); +void on_close_ftdi(usb_serial_device *usd); + +#endif //_USB_FTDI_H_ diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/install.sh b/src/add-ons/kernel/drivers/ports/usb_serial/install.sh new file mode 100755 index 0000000000..b373eba71c --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/install.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +DRIVER_TITLE="USB Serial" +DRIVER_NAME=usb_serial + +answer=`alert "Do you really want to install the $DRIVER_TITLE driver?" "No" "Yes"` +if [ $answer == "No" ]; then + exit +fi + +/boot/beos/bin/install -d ~/config/add-ons/kernel/drivers/bin/ +/boot/beos/bin/install -d ~/config/settings/kernel/drivers/ +/boot/beos/bin/install -d ~/config/add-ons/kernel/drivers/dev/ports/ +/boot/beos/bin/install `dirname $0`/$DRIVER_NAME ~/config/add-ons/kernel/drivers/bin/ +/boot/beos/bin/cp `dirname $0`/$DRIVER_NAME.settings.sample ~/config/settings/kernel/drivers/$DRIVER_NAME + +mimeset ~/config/add-ons/kernel/drivers/bin/$DRIVER_NAME +mimeset ~/config/settings/kernel/drivers/$DRIVER_NAME + +ln -sf ../../bin/$DRIVER_NAME ~/config/add-ons/kernel/drivers/dev/ports/$DRIVER_NAME + +rescan $DRIVER_NAME + +alert "The $DRIVER_TITLE driver has been installed in your system." diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/prolific.c b/src/add-ons/kernel/drivers/ports/usb_serial/prolific.c new file mode 100644 index 0000000000..823963d164 --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/prolific.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2003 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#include +#include +#include +#include + +#include "driver.h" +#include "prolific.h" + +status_t add_prolific_device(usb_serial_device *usd, + const usb_configuration_info *uci) +{ + struct usb_endpoint_info *comm_epi = NULL; + struct usb_endpoint_info *data_out_epi = NULL; + struct usb_endpoint_info *data_in_epi = NULL; + status_t status = ENODEV; + int i = 0; + + TRACE_FUNCALLS("> add_prolific_device(%08x, %08x)\n", usd, uci); + + if(uci->interface_count){ + struct usb_interface_info *uii = uci->interface[0].active; + for(i = 0; i < uii->endpoint_count; i++){ + if(uii->endpoint[i].descr->attributes == USB_EP_ATTR_INTERRUPT){ + if((uii->endpoint[i].descr->endpoint_address & USB_EP_ADDR_DIR_IN) + == USB_EP_ADDR_DIR_IN) /*USB_EP_ADDR_DIR_OUT = 0x0*/ + comm_epi = &uii->endpoint[i]; + } + } + /*They say that USB-RSAQ1 has 2 interfaces */ + if(uci->interface_count == 2){ + uii = uci->interface[1].active; + } + + for(i = 0; i < uii->endpoint_count; i++){ + if(uii->endpoint[i].descr->attributes == USB_EP_ATTR_BULK){ + if((uii->endpoint[i].descr->endpoint_address & USB_EP_ADDR_DIR_IN) + == USB_EP_ADDR_DIR_IN){ + data_in_epi = &uii->endpoint[i]; + }else{ + if(uii->endpoint[i].descr->endpoint_address + /*USB_EP_ADDR_DIR_OUT = 0x0*/){ + data_out_epi = &uii->endpoint[i]; + } + } + } + } + + if(comm_epi && data_in_epi && data_out_epi){ + usd->read_buffer_size = + usd->write_buffer_size = + usd->interrupt_buffer_size = ROUNDUP(PROLIFIC_BUF_SIZE, 16); + status = add_device(usd, uci, comm_epi, data_out_epi, data_in_epi); + } + } + + TRACE_FUNCRET("< add_prolific_device returns:%08x\n", status); + return status; +} + +status_t reset_prolific_device(usb_serial_device *usd){ + status_t status; + size_t len = 0; + TRACE_FUNCALLS("> reset_prolific_device(%08x)\n", usd); + status = (*usb_m->send_request)(usd->dev, + USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, + PROLIFIC_SET_REQUEST, 0, 0, 0, 0, 0, &len); + TRACE_FUNCRET("< reset_prolific_device returns:%08x\n", status); + return status; +} diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/prolific.h b/src/add-ons/kernel/drivers/ports/usb_serial/prolific.h new file mode 100644 index 0000000000..10e86ab193 --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/prolific.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2003-2004 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#ifndef _USB_PROLIFIC_H_ + #define _USB_PROLIFIC_H_ + +#define VND_PROLIFIC 0x067b +#define VND_IODATA 0x04bb +#define VND_ATEN 0x0557 +#define VND_TDK 0x04bf +#define VND_RATOC 0x0584 +#define VND_ELECOM 0x056e +#define VND_SOURCENEXT 0x0833 +#define VND_HAL 0x0b41 + +#define PROD_IODATA_USBRSAQ 0x0a03 +#define PROD_PROLIFIC_RSAQ2 0x04bb +#define PROD_ATEN_UC232A 0x2008 +#define PROD_PROLIFIC_PL2303 0x2303 +#define PROD_TDK_UHA6400 0x0117 +#define PROD_RATOC_REXUSB60 0xb000 +#define PROD_ELECOM_UCSGT 0x5003 +#define PROD_SOURCENEXT_KEIKAI8 0x039f +#define PROD_SOURCENEXT_KEIKAI8_CHG 0x012e +#define PROD_HAL_IMR001 0x0011 + +// dobavit?!!!!!!!!!!!!! +// { 0, 0, 0, 0x0eba, 0x1080 }, // ITEGNO +// { 0, 0, 0, 0x0df7, 0x2620 } // MA620 + +#define PROLIFIC_SET_REQUEST 0x01 + +#define PROLIFIC_BUF_SIZE 0x100 + +status_t add_prolific_device(usb_serial_device *usd, + const usb_configuration_info *uci); +status_t reset_prolific_device(usb_serial_device *usd); + +#endif //_USB_PROLIFIC_H_ diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/tracing.c b/src/add-ons/kernel/drivers/ports/usb_serial/tracing.c new file mode 100644 index 0000000000..33075b1a3c --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/tracing.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2003 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#include +#include +#include + +#include //sprintf +#include //posix file i/o - create, write, close +#include + + +#include "driver.h" +//#include "dano_hack.h" + +#if DEBUG +bool b_log = true; +#else +bool b_log = false; +#endif +bool b_log_file = false; +bool b_log_append = false; +bool b_log_funcalls = false; +bool b_log_funcret = false; +bool b_log_funcres = false; +bool b_acm_support = true; + +static const char *private_log_path="/boot/home/"DRIVER_NAME".log"; +static sem_id loglock; + +void load_setting(){ + void *settingshandle; + settingshandle = load_driver_settings(DRIVER_NAME); +#if !DEBUG + b_log = get_driver_boolean_parameter( + settingshandle, "debug_output", b_log, true); +#endif + b_log_file = get_driver_boolean_parameter( + settingshandle, "debug_output_in_file", b_log_file, true); + b_log_append = ! get_driver_boolean_parameter( + settingshandle, "debug_output_file_rewrite", !b_log_append, true); + b_log_funcalls = get_driver_boolean_parameter( + settingshandle, "debug_trace_func_calls", b_log_funcalls, false); + b_log_funcret = get_driver_boolean_parameter( + settingshandle, "debug_trace_func_returns", b_log_funcret, false); + b_log_funcres = get_driver_boolean_parameter( + settingshandle, "debug_trace_func_results", b_log_funcres, false); + b_acm_support = get_driver_boolean_parameter( + settingshandle, "support_acm_devices", b_acm_support, true); + + unload_driver_settings(settingshandle); +} + +void create_log(){ + int flags = O_WRONLY | O_CREAT | ((!b_log_append) ? O_TRUNC : 0); + if(!b_log_file) + return; + close(open(private_log_path, flags, 0666)); + loglock = create_sem(1, DRIVER_NAME"-logging"); +} + +void usb_serial_trace(bool b_force, char *fmt, ...){ + if(!(b_force || b_log)) + return; + { + va_list arg_list; + static char *prefix = "\33[32m"DRIVER_NAME":\33[0m"; + static char buf[1024]; + char *buf_ptr = buf; + if(!b_log_file){ + strcpy(buf, prefix); + buf_ptr += strlen(prefix); + } + + va_start(arg_list, fmt); + vsprintf(buf_ptr, fmt, arg_list); + va_end(arg_list); + + if(b_log_file){ + int fd; + acquire_sem(loglock); + fd = open(private_log_path, O_WRONLY | O_APPEND); + write(fd, buf, strlen(buf)); + close(fd); + release_sem(loglock); + } + else + dprintf(buf); + } +} + +void trace_ddomain(struct ddomain *dd){ + TRACE("struct ddomain\n" + " ddrover: %08x\n" + " bg:%d, locked:%d\n", dd->r, dd->bg, dd->locked); +} + +void trace_termios(struct termios *tios){ + TRACE("struct termios\n" + " c_iflag:%08x\n" + " c_oflag:%08x\n" + " c_cflag:%08x\n" + " c_lflag:%08x\n" + " c_line: %08x\n" + " c_ixxxxx:%08x\n" + " c_oxxxxx:%08x\n" + " c_cc [%02x, %02x, %02x, %02x, %02x, %02x, " + "%02x, %02x, %02x, %02x, %02x]\n", + tios->c_iflag, tios->c_oflag, tios->c_cflag, tios->c_lflag, + tios->c_line, tios->c_ixxxxx, tios->c_oxxxxx, + tios->c_cc[0], tios->c_cc[1], tios->c_cc[2], tios->c_cc[3], + tios->c_cc[4], tios->c_cc[5], tios->c_cc[6], tios->c_cc[7], + tios->c_cc[8], tios->c_cc[9], tios->c_cc[10]); +} + +void trace_str(struct str *str){ + TRACE("struct str\n" + " buffer:%08x\n" + " bufsize:%d\n" + " count:%d\n" + " tail:%d\n" + " allocated: %d\n", + str->buffer, + str->bufsize, str->count, str->tail, + str->allocated); +} + +void trace_winsize(struct winsize *ws){ + TRACE("struct winsize\n" + " ws_row:%d\n" + " ws_col:%d\n" + " ws_xpixel:%d\n" + " ws_ypixel:%d\n", + ws->ws_row, ws->ws_col, ws->ws_xpixel, ws->ws_ypixel); +} + +void trace_tty(struct tty *tty){ + TRACE("\n>> STRUCT tty\n" + " nopen:%d, flags:%08x,\n", + tty->nopen, tty->flags); + + TRACE("\n ddomain dd:\n"); + trace_ddomain(&tty->dd); + TRACE("\n ddomain ddi:\n"); + trace_ddomain(&tty->ddi); + + TRACE(" pgid: %08x\n", tty->pgid); + + TRACE("\n termios t:"); + trace_termios(&tty->t); + + TRACE(" iactivity: %d, ibusy:%d\n", tty->iactivity, tty->ibusy); + + TRACE("\n str istr:\n"); + trace_str(&tty->istr); + TRACE("\n str rstr:\n"); + trace_str(&tty->rstr); + TRACE("\n str ostr:\n"); + trace_str(&tty->ostr); + + TRACE("\n winsize wsize:\n"); + trace_winsize(&tty->wsize); + + TRACE(" service: %08x\n", tty->service); + TRACE("\n<< STRUCT tty\n"); +} diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/tracing.h b/src/add-ons/kernel/drivers/ports/usb_serial/tracing.h new file mode 100644 index 0000000000..e15ab9ee67 --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/tracing.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#ifndef _USB_SERIAL_TRACING_H_ + #define _USB_SERIAL_TRACING_H_ + +void load_setting(); +void create_log(); +void usb_serial_trace(bool b_force, char *fmt, ...); + +#define TRACE_ALWAYS(x...) usb_serial_trace(true, x); +#define TRACE(x...) usb_serial_trace(false, x); + +extern bool b_log_funcalls; +#define TRACE_FUNCALLS(x...)\ + { if(b_log_funcalls) usb_serial_trace(false, x);} + +extern bool b_log_funcret; +#define TRACE_FUNCRET(x...)\ + { if(b_log_funcret) usb_serial_trace(false, x);} + +extern bool b_log_funcres; +#define TRACE_FUNCRES(func, param)\ + { if(b_log_funcres) func(param);} + +void trace_ddomain(struct ddomain *dd); +void trace_termios(struct termios *tios); +void trace_str(struct str *str); +void trace_winsize(struct winsize *ws); +void trace_tty(struct tty *tty); + +extern bool b_acm_support; + +#endif//_USB_SERIAL_TRACING_H_ diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/uftdireg.h b/src/add-ons/kernel/drivers/ports/usb_serial/uftdireg.h new file mode 100644 index 0000000000..04586e8030 --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/uftdireg.h @@ -0,0 +1,358 @@ +/* $NetBSD: uftdireg.h,v 1.6 2002/07/11 21:14:28 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/uftdireg.h,v 1.1 2002/08/11 23:32:33 joe Exp $ */ + +/* + * Definitions for the FTDI USB Single Port Serial Converter - + * known as FTDI_SIO (Serial Input/Output application of the chipset) + * + * The device is based on the FTDI FT8U100AX chip. It has a DB25 on one side, + * USB on the other. + * + * Thanx to FTDI (http://www.ftdi.co.uk) for so kindly providing details + * of the protocol required to talk to the device and ongoing assistence + * during development. + * + * Bill Ryder - bryder@sgi.com of Silicon Graphics, Inc. is the original + * author of this file. + */ +/* Modified by Lennart Augustsson */ + +/* + * Added to BeOS USB Serial Driver project by Siarzhuk Zharski + * + * $Source: /cvsroot/sis4be/usb_serial/uftdireg.h,v $ + * $Author: zharik $ + * $Revision: 1.1 $ + * $Date: 2003/05/29 18:55:43 $ + * + */ + +/* Vendor Request Interface */ +#define FTDI_SIO_RESET 0 /* Reset the port */ +#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ +#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ +#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */ +#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */ +#define FTDI_SIO_GET_STATUS 5 /* Retrieve current value of status reg */ +#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ +#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ + +/* Port Identifier Table */ +#define FTDI_PIT_DEFAULT 0 /* SIOA */ +#define FTDI_PIT_SIOA 1 /* SIOA */ +#define FTDI_PIT_SIOB 2 /* SIOB */ +#define FTDI_PIT_PARALLEL 3 /* Parallel */ + +enum uftdi_type { + UFTDI_TYPE_SIO, + UFTDI_TYPE_8U232AM +}; + +/* + * BmRequestType: 0100 0000B + * bRequest: FTDI_SIO_RESET + * wValue: Control Value + * 0 = Reset SIO + * 1 = Purge RX buffer + * 2 = Purge TX buffer + * wIndex: Port + * wLength: 0 + * Data: None + * + * The Reset SIO command has this effect: + * + * Sets flow control set to 'none' + * Event char = 0x0d + * Event trigger = disabled + * Purge RX buffer + * Purge TX buffer + * Clear DTR + * Clear RTS + * baud and data format not reset + * + * The Purge RX and TX buffer commands affect nothing except the buffers + * + */ +/* FTDI_SIO_RESET */ +#define FTDI_SIO_RESET_SIO 0 +#define FTDI_SIO_RESET_PURGE_RX 1 +#define FTDI_SIO_RESET_PURGE_TX 2 + + +/* + * BmRequestType: 0100 0000B + * bRequest: FTDI_SIO_SET_BAUDRATE + * wValue: BaudRate value - see below + * wIndex: Port + * wLength: 0 + * Data: None + */ +/* FTDI_SIO_SET_BAUDRATE */ +enum { + ftdi_sio_b300 = 0, + ftdi_sio_b600 = 1, + ftdi_sio_b1200 = 2, + ftdi_sio_b2400 = 3, + ftdi_sio_b4800 = 4, + ftdi_sio_b9600 = 5, + ftdi_sio_b19200 = 6, + ftdi_sio_b38400 = 7, + ftdi_sio_b57600 = 8, + ftdi_sio_b115200 = 9 +}; + +enum { + ftdi_8u232am_b300 = 0x2710, + ftdi_8u232am_b600 = 0x1388, + ftdi_8u232am_b1200 = 0x09c4, + ftdi_8u232am_b2400 = 0x04e2, + ftdi_8u232am_b4800 = 0x0271, + ftdi_8u232am_b9600 = 0x4138, + ftdi_8u232am_b19200 = 0x809c, + ftdi_8u232am_b38400 = 0xc04e, + ftdi_8u232am_b57600 = 0x0034, + ftdi_8u232am_b115200 = 0x001a, + ftdi_8u232am_b230400 = 0x000d, + ftdi_8u232am_b460800 = 0x4006, + ftdi_8u232am_b921600 = 0x8003 +}; + +/* + * BmRequestType: 0100 0000B + * bRequest: FTDI_SIO_SET_DATA + * wValue: Data characteristics (see below) + * wIndex: Port + * wLength: 0 + * Data: No + * + * Data characteristics + * + * B0..7 Number of data bits + * B8..10 Parity + * 0 = None + * 1 = Odd + * 2 = Even + * 3 = Mark + * 4 = Space + * B11..13 Stop Bits + * 0 = 1 + * 1 = 1.5 + * 2 = 2 + * B14..15 Reserved + * + */ +/* FTDI_SIO_SET_DATA */ +#define FTDI_SIO_SET_DATA_BITS(n) (n) +#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8) +#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8) +#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8) +#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8) +#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8) +#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) +#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) +#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) +#define FTDI_SIO_SET_BREAK (0x1 << 14) + + +/* + * BmRequestType: 0100 0000B + * bRequest: FTDI_SIO_MODEM_CTRL + * wValue: ControlValue (see below) + * wIndex: Port + * wLength: 0 + * Data: None + * + * NOTE: If the device is in RTS/CTS flow control, the RTS set by this + * command will be IGNORED without an error being returned + * Also - you can not set DTR and RTS with one control message + * + * ControlValue + * B0 DTR state + * 0 = reset + * 1 = set + * B1 RTS state + * 0 = reset + * 1 = set + * B2..7 Reserved + * B8 DTR state enable + * 0 = ignore + * 1 = use DTR state + * B9 RTS state enable + * 0 = ignore + * 1 = use RTS state + * B10..15 Reserved + */ +/* FTDI_SIO_MODEM_CTRL */ +#define FTDI_SIO_SET_DTR_MASK 0x1 +#define FTDI_SIO_SET_DTR_HIGH (1 | ( FTDI_SIO_SET_DTR_MASK << 8)) +#define FTDI_SIO_SET_DTR_LOW (0 | ( FTDI_SIO_SET_DTR_MASK << 8)) +#define FTDI_SIO_SET_RTS_MASK 0x2 +#define FTDI_SIO_SET_RTS_HIGH (2 | ( FTDI_SIO_SET_RTS_MASK << 8)) +#define FTDI_SIO_SET_RTS_LOW (0 | ( FTDI_SIO_SET_RTS_MASK << 8)) + + +/* + * BmRequestType: 0100 0000b + * bRequest: FTDI_SIO_SET_FLOW_CTRL + * wValue: Xoff/Xon + * wIndex: Protocol/Port - hIndex is protocl / lIndex is port + * wLength: 0 + * Data: None + * + * hIndex protocol is: + * B0 Output handshaking using RTS/CTS + * 0 = disabled + * 1 = enabled + * B1 Output handshaking using DTR/DSR + * 0 = disabled + * 1 = enabled + * B2 Xon/Xoff handshaking + * 0 = disabled + * 1 = enabled + * + * A value of zero in the hIndex field disables handshaking + * + * If Xon/Xoff handshaking is specified, the hValue field should contain the + * XOFF character and the lValue field contains the XON character. + */ +/* FTDI_SIO_SET_FLOW_CTRL */ +#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 +#define FTDI_SIO_RTS_CTS_HS 0x1 +#define FTDI_SIO_DTR_DSR_HS 0x2 +#define FTDI_SIO_XON_XOFF_HS 0x4 + + +/* + * BmRequestType: 0100 0000b + * bRequest: FTDI_SIO_SET_EVENT_CHAR + * wValue: Event Char + * wIndex: Port + * wLength: 0 + * Data: None + * + * wValue: + * B0..7 Event Character + * B8 Event Character Processing + * 0 = disabled + * 1 = enabled + * B9..15 Reserved + * + * FTDI_SIO_SET_EVENT_CHAR + * + * Set the special event character for the specified communications port. + * If the device sees this character it will immediately return the + * data read so far - rather than wait 40ms or until 62 bytes are read + * which is what normally happens. + */ + + + +/* + * BmRequestType: 0100 0000b + * bRequest: FTDI_SIO_SET_ERROR_CHAR + * wValue: Error Char + * wIndex: Port + * wLength: 0 + * Data: None + * + * Error Char + * B0..7 Error Character + * B8 Error Character Processing + * 0 = disabled + * 1 = enabled + * B9..15 Reserved + * + * + * FTDI_SIO_SET_ERROR_CHAR + * Set the parity error replacement character for the specified communications + * port. + */ + + +/* + * BmRequestType: 1100 0000b + * bRequest: FTDI_SIO_GET_MODEM_STATUS + * wValue: zero + * wIndex: Port + * wLength: 1 + * Data: Status + * + * One byte of data is returned + * B0..3 0 + * B4 CTS + * 0 = inactive + * 1 = active + * B5 DSR + * 0 = inactive + * 1 = active + * B6 Ring Indicator (RI) + * 0 = inactive + * 1 = active + * B7 Receive Line Signal Detect (RLSD) + * 0 = inactive + * 1 = active + * + * FTDI_SIO_GET_MODEM_STATUS + * Retrieve the current value of the modem status register. + */ +#define FTDI_SIO_CTS_MASK 0x10 +#define FTDI_SIO_DSR_MASK 0x20 +#define FTDI_SIO_RI_MASK 0x40 +#define FTDI_SIO_RLSD_MASK 0x80 + + + +/* + * + * DATA FORMAT + * + * IN Endpoint + * + * The device reserves the first two bytes of data on this endpoint to contain + * the current values of the modem and line status registers. In the absence of + * data, the device generates a message consisting of these two status bytes + * every 40 ms. + * + * Byte 0: Modem Status + * NOTE: 4 upper bits have same layout as the MSR register in a 16550 + * + * Offset Description + * B0..3 Port + * B4 Clear to Send (CTS) + * B5 Data Set Ready (DSR) + * B6 Ring Indicator (RI) + * B7 Receive Line Signal Detect (RLSD) + * + * Byte 1: Line Status + * NOTE: same layout as the LSR register in a 16550 + * + * Offset Description + * B0 Data Ready (DR) + * B1 Overrun Error (OE) + * B2 Parity Error (PE) + * B3 Framing Error (FE) + * B4 Break Interrupt (BI) + * B5 Transmitter Holding Register (THRE) + * B6 Transmitter Empty (TEMT) + * B7 Error in RCVR FIFO + * + * + * OUT Endpoint + * + * This device reserves the first bytes of data on this endpoint contain the + * length and port identifier of the message. For the FTDI USB Serial converter + * the port identifier is always 1. + * + * Byte 0: Port & length + * + * Offset Description + * B0..1 Port + * B2..7 Length of message - (not including Byte 0) + * + */ +#define FTDI_PORT_MASK 0x0f +#define FTDI_MSR_MASK 0xf0 +#define FTDI_GET_MSR(p) (((p)[0]) & FTDI_MSR_MASK) +#define FTDI_GET_LSR(p) ((p)[1]) +#define FTDI_LSR_MASK (~0x60) /* interesting bits */ +#define FTDI_OUT_TAG(len, port) (((len) << 2) | (port)) diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/uninstall.sh b/src/add-ons/kernel/drivers/ports/usb_serial/uninstall.sh new file mode 100755 index 0000000000..351b914a64 --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/uninstall.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +DRIVER_TITLE="USB Serial" +DRIVER_NAME=usb_serial + +answer=`alert "Do you really want to uninstall the $DRIVER_TITLE driver?" "No" "Yes"` +if [ $answer == "No" ]; then + exit +fi + +rm ~/config/add-ons/kernel/drivers/bin/$DRIVER_NAME +rm ~/config/settings/kernel/drivers/$DRIVER_NAME +rm ~/config/add-ons/kernel/drivers/dev/ports/$DRIVER_NAME + +rescan $DRIVER_NAME + +alert "The $DRIVER_TITLE driver has been removed from your system." diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/usb_serial.rdef b/src/add-ons/kernel/drivers/ports/usb_serial/usb_serial.rdef new file mode 100644 index 0000000000..5e16be8d69 --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/usb_serial.rdef @@ -0,0 +1,54 @@ +resource(1, "BEOS:L:STD_ICON") #'ICON' array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFF0000FFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFF0000FFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF0000FFFFFFFF0000FFFFFFFFFFFFFF00" + $"FFFFFFFFFFFFFFFFFFFFFF001C00000000FFFFFFFF0000FFFFFFFFFFFFFF0000" + $"FFFFFFFFFFFFFFFFFFFF001B1818180000FFFFFF0000FFFFFFFF000000000000" + $"FFFFFFFFFFFFFFFFFF001B183F3F3F181800000000FFFFFFFF001C1C1C000000" + $"FFFFFFFFFFFFFFFF001B180F0F0F0F0F1818180000FFFFFF001C1818181800FF" + $"FFFFFFFFFFFFFF001C1818181818181818181818180000001C181818183F00FF" + $"FFFFFFFFFFFF001C18181818181818181818181818181800001818183F0F00FF" + $"FFFFFFFFFF001B18181818181818181818181818181818181800003F0F0F00FF" + $"FFFFFFFF001C181818181818181818181818181818181818181818000000FFFF" + $"FFFFFF001C181818181818181818181818181818181818181818183F0E00FFFF" + $"FFFF001B181818181818181818181818181818181818181818183F0F0F00FFFF" + $"FF001C181818181818181818181818181818181818181818183F0F0F0F00FFFF" + $"000E181818181818181818181818181818181818181818183F0F0F0F0F00FFFF" + $"003F3F1818183F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F183F0F0F0F0F0F00FFFF" + $"0017173F3F18180F0F0F0F0F0F0F0F0F0F0F0F0F0F183F0F0F0F0F0F0F000FFF" + $"00202018173F3F1818183F3F3F3F3F3F3F3F3F3F183F0F0F0F0F0F0F000E0EFF" + $"001717202017183F3F18180F0F0F0F0F0F0F0F183F0F0F0F0F0F0F000F0F0FFF" + $"00182A1817202017183F3F1818183F3F3F18183F0F0F0F0F0F0F000F0F0FFFFF" + $"002A2A182E1817171718173F3F18180F0F183F0F0F0F0F0F0F000F0F0FFFFFFF" + $"0017182E2E182E1818171718173F3F18183F0F0F0F0F0F0F000F0F0FFFFFFFFF" + $"FF000017182E2E182A1718171718173F3F0F0F0F0F0F0F000F0F0FFFFFFFFFFF" + $"FFFFFF000017172A2A182E171817171C170F0F0F0F0F000F0F0FFFFFFFFFFFFF" + $"FFFFFFFFFF000017172E2E182A17181B180E0F0F0F000F0F0FFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFF000017172A2A18341B180F0F0E000F0F0FFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFF0000171734341C170F0F000F0F0EFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFF000017171C170F000F0F0FFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFF00001B18000E0F0FFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000E0F0FFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" +}; + +resource(1, "BEOS:M:STD_ICON") #'MICN' array { + $"FFFFFFFFFFFFFFFFFF00FFFF00FFFFFF" + $"FFFFFFFFFFFF09FF00FFFF00FFFFFF00" + $"FFFFFFFFFF131B1308FF00FFFF0E0700" + $"FFFFFFFF13151313181208FF141819FF" + $"FFFFFF1318181818181818120C1313FF" + $"FFFF14181818181818181818181303FF" + $"FF1318181818181818181818191307FF" + $"0B19181B1B1B1B1B1B1B1B19130F07FF" + $"D5871B1713171717171717130F0F07FF" + $"0BA8AD871B1713171517130F0F070FFF" + $"D0A3A91317191B1717130F0F070FFFFF" + $"FF07A9A3A313171A150F0F070FFFFFFF" + $"FFFFFF07A9A3A368130E070FFFFFFFFF" + $"FFFFFFFFFF078F6813070FFFFFFFFFFF" + $"FFFFFFFFFFFFFF09090EFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" +}; + diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/usb_serial.settings.sample b/src/add-ons/kernel/drivers/ports/usb_serial/usb_serial.settings.sample new file mode 100644 index 0000000000..2e008c263d --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/usb_serial/usb_serial.settings.sample @@ -0,0 +1,37 @@ +# +# The sample USB serial driver settings file +# +# Rename it to usb_serial and put into +# /boot/home/config/settings/kernel/drivers/ +# After restarting your system the new settings will works. + +#support_acm_devices - if you have other ACM driver in your system you can disable +# ACM support by setting this key to "false". The default value is "true" - the ACM +# support is activated. +#support_acm_devices true + +# Following settings are for debugging purposes. +# Debug output - this is a possibility to view some kind of development related +# information - error and warning messages etc. + +# debug_output - activates debug output. The debug builds has debug output +# activated by default and this key has no effect on it. The release builds requires +# to activate this if you want to see debug messages in syslog or in private log file. +# +# debug_output true + +# debug_output_in_file - activates writing of debug messages into private log file. +# The name of this file is /boot/home/usb_serial.log. If this key is set to true - no messages +# will be written into syslog. +# +# debug_output_in_file true + +# debug_output_file_rewrite - activates rewriting of private log file on +# calling driver_init() syscall. By default this set in false. +# +# debug_output_file_rewrite false + +# debug_trace_func_calls - the information about driver functions calls +# will be traced. Would you like to see internals? Then activate this. +# +# debug_trace_func_calls true diff --git a/src/add-ons/kernel/drivers/video/Jamfile b/src/add-ons/kernel/drivers/video/Jamfile new file mode 100644 index 0000000000..9c40f09ee8 --- /dev/null +++ b/src/add-ons/kernel/drivers/video/Jamfile @@ -0,0 +1,3 @@ +SubDir HAIKU_TOP src add-ons kernel drivers video ; + +SubInclude HAIKU_TOP src add-ons kernel drivers video usb_vision ; diff --git a/src/add-ons/kernel/drivers/video/usb_vision/Jamfile b/src/add-ons/kernel/drivers/video/usb_vision/Jamfile new file mode 100644 index 0000000000..81e259797c --- /dev/null +++ b/src/add-ons/kernel/drivers/video/usb_vision/Jamfile @@ -0,0 +1,24 @@ +SubDir HAIKU_TOP src add-ons kernel drivers video ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders usb_vision ; + +#local defines = [ FDefines DB_USB_USE_V2_MODULE ] ; +#SubDirCcFlags $(defines) ; + +KernelAddon usb_vision : kernel drivers bin : + usb_vision.c + tracing.c +; + +# driver goes in dev/video + +Package haiku-usb_vision-cvs + : + usb_vision + : + boot home config add-ons kernel drivers bin ; + +Package haiku-usb_vision-cvs : usb_vision.settings.sample + : boot home config settings kernel drivers sample ; diff --git a/src/add-ons/kernel/drivers/video/usb_vision/ReadMe.html b/src/add-ons/kernel/drivers/video/usb_vision/ReadMe.html new file mode 100644 index 0000000000..40716c245b --- /dev/null +++ b/src/add-ons/kernel/drivers/video/usb_vision/ReadMe.html @@ -0,0 +1,240 @@ + +BeOS driver for USBVision (Nogatech) TV tuners + +

BeOS driver for USBVision (Nogatech) TV tuners

+ +

Introduction

+

This driver is designed to support USBVision (Nogatech) TV Tuners. Tested with:

+ +
+ + + +
NameVendor IDProduct ID
Hauppauge WinTV FM0x05730x4d31
+ +
+NOTE that + +I have one small request for you - if you tried this driver and it works - +PLEASE e-mail me the information about your USB TV Tuner and results of your +experiments. This information is very interesting for me and helps in improvement +this driver! Thank you for co-operation! +
+NOTE that + +If you definetily have the some kind of USB TV Tuner but this driver didn't +help you - see section "Unknown devices" below for instructions. +
+ +
+NOTE that + +If your computer has the OHCI-compatible USB hardware you are out of luck. This hardware is not +supported by non-Dan0-like versions. See the BeOS.USB.patches vor details and +solutions. +
+ +What's new: +
+Version: + +History: +
+0.1.0-dev-0 + +very first "development" release. +
+ + +

1. Installation

+
    +
  • Run install.sh +
  • If all is OK ... //TODO: +
  • If something goes wrong ... //TODO: +
+

2. Uninstallation

+
    +
  • Run uninstall.sh +
+ +

3. Problems solving

+
    +
  • If this driver crash your system - reboot and press "Space" during load. In boot menu select + "Disable user add-ons" and continue boot. Uninstall driver and reboot again into normal mode. + Write me a e-mail about this problem. +
+

4. "Unknown" devices

+ + If you have something, that looks like USB TV tuner and tried it with + this driver but have no success - download + usb device info tool and use it to get required information. +
    +
  • Unplug all USB devices and hubs from your PC. +
  • Go into Terminal and run the following command: + ls -alR /dev/bus/usb + You should see something like this: +
    +$ ls -alR /dev/bus/usb/
    +/dev/bus/usb:
    +total 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 .
    +drw-r--r--   1 walther  users           0 Jun  1  2003 ..
    +drw-r--r--   1 walther  users           0 May 31 23:16 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 1
    +crw-r--r--   1 walther  users      0,   0 May 31 23:16 unload
    +
    +/dev/bus/usb/0:
    +total 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 .
    +drw-r--r--   1 walther  users           0 May 31 23:16 ..
    +crw-r--r--   1 walther  users      0,   0 May 31 23:16 hub
    +
    +/dev/bus/usb/1:
    +total 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 .
    +drw-r--r--   1 walther  users           0 May 31 23:16 ..
    +crw-r--r--   1 walther  users      0,   0 May 31 23:16 hub
    +
    + +
  • Note this information. +
  • Now plug your USB TV tuner into PC and run ls -alR /dev/bus/usb/ again. +You'll get something slightly different: +
    +$ ls -alR /dev/bus/usb/
    +/dev/bus/usb:
    +total 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 .
    +drw-r--r--   1 walther  users           0 Jun  1  2003 ..
    +drw-r--r--   1 walther  users           0 May 31 23:16 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 1
    +crw-r--r--   1 walther  users      0,   0 May 31 23:16 unload
    +
    +/dev/bus/usb/0:
    +total 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 .
    +drw-r--r--   1 walther  users           0 May 31 23:16 ..
    +crw-r--r--   1 walther  users      0,   0 May 31 23:17 1
    +crw-r--r--   1 walther  users      0,   0 May 31 23:16 hub
    +
    +/dev/bus/usb/1:
    +total 0
    +drw-r--r--   1 walther  users           0 May 31 23:16 .
    +drw-r--r--   1 walther  users           0 May 31 23:16 ..
    +crw-r--r--   1 walther  users      0,   0 May 31 23:16 hub
    +
    + +$ +
  • Compare this results with previous one and look for file, +that appeared. This file is your USB TV tuner. +
  • Unpack downloaded usb_dev_info command and run it with full path to file appeared in +the second listing. For my sample I should run: +usb_dev_info /dev/bus/usb/0/1 +I'll get the following: +
    +$ usb_dev_info /dev/bus/usb/0/1
    +[Device]
    +Class .................. 0
    +Subclass ............... 0
    +Protocol ............... 0
    +Vendor ID .............. 0x0573
    +Product ID ............. 0x4d31
    +Version ................ 0x0100
    +Manufacturer String .... "NT"
    +Product String ......... ""
    +Serial Number .......... ""
    +  [Configuration 0]
    +    [Interface 0]
    +    Class .............. 0
    +    Subclass ........... 0
    +    Protocol ........... 0
    +      [Endpoint 0]
    +      MaxPacketSize .... 8
    +      Interval ......... 1
    +      Direction ........ Input
    +      [Endpoint 1]
    +      MaxPacketSize .... 0
    +      Interval ......... 1
    +      Type ............. Isochronous
    +      Direction ........ Output
    +  [Configuration 1]
    +    [Interface 0]
    +    Class .............. 0
    +    Subclass ........... 0
    +    Protocol ........... 0
    +      [Endpoint 0]
    +      MaxPacketSize .... 8
    +      Interval ......... 1
    +      Direction ........ Input
    +      [Endpoint 1]
    +      MaxPacketSize .... 0
    +      Interval ......... 1
    +      Type ............. Isochronous
    +      Direction ........ Output
    +      [Endpoint 2]
    +      MaxPacketSize .... 0
    +      Interval ......... 1
    +      Type ............. Isochronous
    +      Direction ........ Input
    +  [Configuration 2]
    +    [Interface 0]
    +    Class .............. 0
    +    Subclass ........... 0
    +    Protocol ........... 0
    +      [Endpoint 0]
    +      MaxPacketSize .... 8
    +      Interval ......... 1
    +      Direction ........ Input
    +      [Endpoint 1]
    +      MaxPacketSize .... 0
    +      Interval ......... 1
    +      Type ............. Isochronous
    +      Direction ........ Output
    +      [Endpoint 2]
    +      MaxPacketSize .... 64
    +      Interval ......... 1
    +      Type ............. Bulk
    +      Direction ........ Output
    +  [Configuration 3]
    +    [Interface 0]
    +    Class .............. 0
    +    Subclass ........... 0
    +    Protocol ........... 0
    +      [Endpoint 0]
    +      MaxPacketSize .... 8
    +      Interval ......... 1
    +      Direction ........ Input
    +      [Endpoint 1]
    +      MaxPacketSize .... 0
    +      Interval ......... 1
    +      Type ............. Isochronous
    +      Direction ........ Output
    +      [Endpoint 2]
    +      MaxPacketSize .... 0
    +      Interval ......... 1
    +      Type ............. Isochronous
    +      Direction ........ Input
    +      [Endpoint 3]
    +      MaxPacketSize .... 64
    +      Interval ......... 1
    +      Type ............. Bulk
    +      Direction ........ Output
    +
    +
  • Send this information to me with some additional words about your device. +
+ +

What is "BeOS.USB.patches"?

+ +All know that "classical" BeOS R5 don't works on OHCI USB hardware. But some time ago on one well-known +BeOS file-sharing network appeared patches for plain R5. Those patches allows to work with OHCI +hardware under this system version. Looks like it is some part of Dan0 or other "leaked" versions. +There are 3 patches in BeOS.USB.patches.zip: +

1. beos-usb-patch, +

2. beos-usb.modem-patch, +

3. beos-usb.modem-patch.sm. +

You need the first one to make your OHCI hardware working under R5. Install it and proceed with this +driver. Good luck! + + +

Siarzuk Zharski +

http://www.zharik.host.sk/ + \ No newline at end of file diff --git a/src/add-ons/kernel/drivers/video/usb_vision/install.sh b/src/add-ons/kernel/drivers/video/usb_vision/install.sh new file mode 100644 index 0000000000..6bb874e9c0 --- /dev/null +++ b/src/add-ons/kernel/drivers/video/usb_vision/install.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +DRIVER_TITLE="USBVision" +DRIVER_NAME=usbvision + +answer=`alert "Do you really want to install the $DRIVER_TITLE driver?" "No" "Yes"` +if [ $answer == "No" ]; then + exit +fi + +/boot/beos/bin/install -d ~/config/add-ons/kernel/drivers/bin/ +/boot/beos/bin/install -d ~/config/settings/kernel/drivers/ +/boot/beos/bin/install -d ~/config/add-ons/kernel/drivers/dev/video/ +/boot/beos/bin/install `dirname $0`/$DRIVER_NAME ~/config/add-ons/kernel/drivers/bin/ +/boot/beos/bin/cp `dirname $0`/$DRIVER_NAME.settings.sample ~/config/settings/kernel/drivers/$DRIVER_NAME + +mimeset ~/config/add-ons/kernel/drivers/bin/$DRIVER_NAME +mimeset ~/config/settings/kernel/drivers/$DRIVER_NAME + +ln -sf ../../bin/$DRIVER_NAME ~/config/add-ons/kernel/drivers/dev/video/$DRIVER_NAME + +rescan $DRIVER_NAME + +alert "The $DRIVER_TITLE driver has been installed in your system." diff --git a/src/add-ons/kernel/drivers/video/usb_vision/tracing.c b/src/add-ons/kernel/drivers/video/usb_vision/tracing.c new file mode 100644 index 0000000000..e9cbd19d4f --- /dev/null +++ b/src/add-ons/kernel/drivers/video/usb_vision/tracing.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2003 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#include +#include + +#include +//#include +#include //sprintf +#include //posix file i/o - create, write, close +#include + +#include "usbvision.h" + +#if DEBUG +bool b_log = true; +#else +bool b_log = false; +#endif +bool b_log_file = false; +bool b_log_append = false; +bool b_log_funcalls = false; +bool b_log_funcret = false; +bool b_log_funcres = false; + +bool b_log_settings_loaded = false; + +static const char *private_log_path="/boot/home/"DRIVER_NAME".log"; +static sem_id loglock; + +void load_setting(){ + if(!b_log_settings_loaded){ + void *settingshandle; + settingshandle = load_driver_settings(DRIVER_NAME); +#if !DEBUG + b_log = get_driver_boolean_parameter(settingshandle, "debug_output", b_log, true); +#endif + b_log_file = get_driver_boolean_parameter(settingshandle, "debug_output_in_file", b_log_file, true); + b_log_append = ! get_driver_boolean_parameter(settingshandle, "debug_output_file_rewrite", !b_log_append, true); + b_log_funcalls = get_driver_boolean_parameter(settingshandle, "debug_trace_func_calls", b_log_funcalls, false); + b_log_funcret = get_driver_boolean_parameter(settingshandle, "debug_trace_func_returns", b_log_funcret, false); + b_log_funcres = get_driver_boolean_parameter(settingshandle, "debug_trace_func_results", b_log_funcres, false); + unload_driver_settings(settingshandle); + b_log_settings_loaded = true; + } +} + +void create_log(){ + int flags = O_WRONLY | O_CREAT | ((!b_log_append) ? O_TRUNC : 0); + if(!b_log_file) + return; + close(open(private_log_path, flags, 0666)); + loglock = create_sem(1, DRIVER_NAME"-logging"); +} + +void usbvision_trace(bool b_force, char *fmt, ...){ + if(!(b_force || b_log)) + return; + { + va_list arg_list; + static char *prefix = "\33[32m"DRIVER_NAME":\33[0m"; + static char buf[1024]; + char *buf_ptr = buf; + if(!b_log_file){ + strcpy(buf, prefix); + buf_ptr += strlen(prefix); + } + +/* { + bigtime_t time = system_time(); + uint32 msec = time / 1000; + uint32 sec = msec / 1000; + sprintf(buf_ptr, "%02d.%02d.%03d:", sec / 60, sec % 60, msec % 1000); + buf_ptr += strlen(buf_ptr); + } +*/ + va_start(arg_list, fmt); + vsprintf(buf_ptr, fmt, arg_list); + va_end(arg_list); + + if(b_log_file){ + int fd; + acquire_sem(loglock); + fd = open(private_log_path, O_WRONLY | O_APPEND); + write(fd, buf, strlen(buf)); + close(fd); + release_sem(loglock); + } + else + dprintf(buf); + } +} + +void trace_reginfo(xet_nt100x_reg *ri) +{ + int i; + TRACE("struct set_nt100x_reg\n" + " reg:%02x\n" + " data_length:%d\n", + ri->reg, ri->data_length); + for(i = 0; i < ri->data_length; i++) + TRACE("%02x ", ri->data[i]); + TRACE("\n"); +} diff --git a/src/add-ons/kernel/drivers/video/usb_vision/tracing.h b/src/add-ons/kernel/drivers/video/usb_vision/tracing.h new file mode 100644 index 0000000000..08908e64e5 --- /dev/null +++ b/src/add-ons/kernel/drivers/video/usb_vision/tracing.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2003 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#ifndef _USBVISION_TRACING_H_ + #define _USBVISION_TRACING_H_ + +void load_setting(); +void create_log(); +void usbvision_trace(bool b_force, char *fmt, ...); + +#define TRACE_ALWAYS(x...) usbvision_trace(true, x); +#define TRACE(x...) usbvision_trace(false, x); + +extern bool b_log_funcalls; +#define TRACE_FUNCALLS(x...)\ + { if(b_log_funcalls) usbvision_trace(false, x);} + +extern bool b_log_funcret; +#define TRACE_FUNCRET(x...)\ + { if(b_log_funcret) usbvision_trace(false, x);} + +extern bool b_log_funcres; +#define TRACE_FUNCRES(func, param)\ + { if(b_log_funcres) func(param);} + +void trace_reginfo(xet_nt100x_reg *reginfo); + +#endif /*_USBVISION_TRACING_H_*/ diff --git a/src/add-ons/kernel/drivers/video/usb_vision/uninstall.sh b/src/add-ons/kernel/drivers/video/usb_vision/uninstall.sh new file mode 100644 index 0000000000..6ccbaa68a9 --- /dev/null +++ b/src/add-ons/kernel/drivers/video/usb_vision/uninstall.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +DRIVER_TITLE="USBVision" +DRIVER_NAME=usbvision + +answer=`alert "Do you really want to uninstall the $DRIVER_TITLE driver?" "No" "Yes"` +if [ $answer == "No" ]; then + exit +fi + +rm ~/config/add-ons/kernel/drivers/bin/$DRIVER_NAME +rm ~/config/settings/kernel/drivers/$DRIVER_NAME +rm ~/config/add-ons/kernel/drivers/dev/video/$DRIVER_NAME + +rescan $DRIVER_NAME + +alert "The $DRIVER_TITLE driver has been removed from your system." diff --git a/src/add-ons/kernel/drivers/video/usb_vision/usb_vision.c b/src/add-ons/kernel/drivers/video/usb_vision/usb_vision.c new file mode 100644 index 0000000000..620f49cbfd --- /dev/null +++ b/src/add-ons/kernel/drivers/video/usb_vision/usb_vision.c @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2003 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#include +#include +#include + +#include +#include +#include /* strerror */ +#include /* strtol */ +#include /* sprintf */ + + +#include "usb_vision.h" +#include "tracing.h" + +#define BASENAME_LEN 0x10 /*must be synchronized with below !!!*/ +static const char *basename = "video/usb_vision/%u"; + +status_t usb_vision_device_added(const usb_device *dev, void **cookie); +status_t usb_vision_device_removed(void *cookie); + +static usb_notify_hooks notify_hooks = { + &usb_vision_device_added, + &usb_vision_device_removed +}; + +struct usb_module_info *usb; +usb_vision_device *usb_vision_devices[DEVICES_COUNT]; +char * usb_vision_names[DEVICES_COUNT + 1]; +sem_id usb_vision_lock = -1; + +struct usb_support_descriptor supported_devices[] = { + {0, 0, 0, 0x0573, 0x4d31}, +}; + +/* init_hardware - called once the first time the driver is loaded */ +status_t init_hardware (void){ + TRACE("init_hardware\n"); /*special case - no file-logging activated now*/ + return B_OK; +} + +/* init_driver - optional function - called every time the driver is loaded. */ +status_t init_driver (void){ + int i; + status_t status = B_OK; + load_setting(); + create_log(); + + TRACE_FUNCALLS("init_driver\n"); + + if((status = get_module(B_USB_MODULE_NAME, (module_info **)&usb)) == B_OK){ + if(usb){ + for(i = 0; i < DEVICES_COUNT; i++) + usb_vision_devices[i] = 0; + + usb_vision_names[0] = NULL; + load_driver_symbols(DRIVER_NAME); + + (*usb->register_driver)(DRIVER_NAME, supported_devices, SIZEOF(supported_devices), DRIVER_NAME); + (*usb->install_notify)(DRIVER_NAME, ¬ify_hooks); + + usb_vision_lock = create_sem(1, DRIVER_NAME"_devices_table_lock"); + }else{ + status = B_ERROR; + TRACE_ALWAYS("init_driver failed: usb:%08x", usb); + } + }else + TRACE_ALWAYS("init_driver failed:%lx cannot get a module %s", status, B_USB_MODULE_NAME); + + TRACE_FUNCRET("init_driver returns:%08x\n", status); + return status; +} + + +/* uninit_driver - optional function - called every time the driver is unloaded */ +void uninit_driver (void){ + int i; + TRACE_FUNCALLS("uninit_driver\n"); + + (*usb->uninstall_notify)(DRIVER_NAME); + acquire_sem(usb_vision_lock); + + for(i = 0; i < DEVICES_COUNT; i++) + if(usb_vision_devices[i]){ + free(usb_vision_devices[i]); + usb_vision_devices[i] = 0; + } + + release_sem_etc(usb_vision_lock, 1, B_DO_NOT_RESCHEDULE); + delete_sem(usb_vision_lock); + + for(i = 0; usb_vision_names[i]; i++) + free(usb_vision_names[i]); + + put_module(B_USB_MODULE_NAME); +} + + +/* usb_vision_open - handle open() calls */ + +static status_t usb_vision_open (const char *name, uint32 flags, void** cookie) +{ + int i; + status_t status = ENODEV; + TRACE_FUNCALLS("usb_vision_open:%s flags:%d cookie:%08x\n", name, flags, cookie); + + for(i = 0; i < DEVICES_COUNT; i++) + TRACE("%08x\n", usb_vision_devices[i]); + + *cookie = NULL; + i = strtol(name + BASENAME_LEN, NULL, 10); + if(i >= 0 && i < DEVICES_COUNT){ + acquire_sem(usb_vision_lock); + if(usb_vision_devices[i]){ + if(atomic_add(&usb_vision_devices[i]->open_count, 1) == 0){ + *cookie = usb_vision_devices[i]; + TRACE("cookie in open:%08x\n", *cookie); + status = B_OK; + }else{ + atomic_add(&usb_vision_devices[i]->open_count, -1); + status = B_BUSY; + } + } + release_sem(usb_vision_lock); + } + + TRACE_FUNCRET("usb_vision_open returns:%08x\n", status); + return status; +} + +/* usb_vision_read - handle read() calls */ + +static status_t usb_vision_read (void* cookie, off_t position, void *buf, size_t* num_bytes) +{ + *num_bytes = 0; /* tell caller nothing was read */ + return B_IO_ERROR; +} + + +/* usb_vision_write - handle write() calls */ + +static status_t usb_vision_write (void* cookie, off_t position, const void* buffer, size_t* num_bytes) +{ + *num_bytes = 0; /* tell caller nothing was written */ + return B_IO_ERROR; +} + +static status_t xet_nt_register(bool is_read, usb_vision_device *uvd, xet_nt100x_reg *ri) +{ + status_t status = B_ERROR; + uint8 req_type = USB_REQTYPE_VENDOR | (is_read ? USB_REQTYPE_DEVICE_IN : USB_REQTYPE_DEVICE_OUT); + + TRACE_FUNCALLS("set_nt_register:%08x, %08x\n", uvd, ri); + TRACE_FUNCRES(trace_reginfo, ri); + + //(*usb->send_request)(uvd->dev, req_type, + // ) + + TRACE_FUNCRET("set_nt_register returns:%08x\n", status); + return status; +} + +/* usb_vision_control - handle ioctl calls */ +static status_t usb_vision_control (void* cookie, uint32 op, void* arg, size_t len) +{ + status_t status = B_BAD_VALUE; + TRACE_FUNCALLS("usb_vision_control:%08x, %d, %08x, %d\n", cookie, op, arg, len); + switch(op){ + case NT_IOCTL_READ_REGISTER: + status = xet_nt_register(true, (usb_vision_device *)cookie, (xet_nt100x_reg *) arg); + break; + case NT_IOCTL_WRITE_REGISTER: + status = xet_nt_register(false, (usb_vision_device *)cookie, (xet_nt100x_reg *) arg); + break; + default: + break; + } + TRACE_FUNCRET("usb_vision_control returns:%08x\n", status); + return status; +} + +/* usb_vision_close - handle close() calls */ +static status_t usb_vision_close (void* cookie) +{ + status_t status = B_OK;//ENODEV; + TRACE_FUNCALLS("usb_vision_close:%08x\n", cookie); + + TRACE_FUNCRET("usb_vision_close returns:%08x\n", status); + return status; +} + + +/* usb_vision_free - called after the last device is closed, and after all i/o is complete. */ +static status_t usb_vision_free (void* cookie) +{ + status_t status = B_OK; + TRACE_FUNCALLS("usb_vision_free:%08x\n", cookie); + + if(cookie){ + usb_vision_device *uvd = (usb_vision_device *)cookie; + atomic_add(&uvd->open_count, -1); + } + + TRACE_FUNCRET("usb_vision_free returns:%08x\n", status); + return status; +} + +/* function pointers for the device hooks entry points */ +device_hooks usb_vision_hooks = { + usb_vision_open, /* -> open entry point */ + usb_vision_close, /* -> close entry point */ + usb_vision_free, /* -> free cookie */ + usb_vision_control, /* -> control entry point */ + usb_vision_read, /* -> read entry point */ + usb_vision_write /* -> write entry point */ +}; + +/* publish_devices - return a null-terminated array of devices + supported by this driver. */ + +const char** publish_devices(){ + int i, j; + TRACE_FUNCALLS("publish_devices\n"); + + for(i=0; usb_vision_names[i]; i++) + free(usb_vision_names[i]); + + acquire_sem(usb_vision_lock); + for(i=0, j=0; i < DEVICES_COUNT; i++){ + if(usb_vision_devices[i]){ + usb_vision_names[j] = malloc(strlen(basename + 2)); + if(usb_vision_names[j]){ + sprintf(usb_vision_names[j], basename, i); + j++; + } + else + TRACE_ALWAYS("publish_devices - NO MEMORY\n"); + } + } + usb_vision_names[j] = NULL; + release_sem(usb_vision_lock); + + return (const char **)&usb_vision_names[0]; +} + +/* find_device - return ptr to device hooks structure for a + given device name */ +device_hooks* find_device(const char* name){ + TRACE_FUNCALLS("find_device(%s)\n", name); + return &usb_vision_hooks; +} + +status_t create_add_device(usb_vision_device *uvd, const struct usb_configuration_info *uci, + struct usb_endpoint_info *control_epi, + struct usb_endpoint_info *data_epi){ +// char name[32]; + status_t status = ENODEV; +// size_t buf_len; + int i = 0; + + TRACE_FUNCALLS("create_add_device(%08x, %08x, %08x, %08x)\n", uvd, uci, control_epi, data_epi); + + acquire_sem(usb_vision_lock); + + for(i = 0; i < DEVICES_COUNT; i++){ + if(usb_vision_devices[i] != NULL) + continue; + + usb_vision_devices[i] = uvd; + /* + usd->active = 1; + usd->open = 0; + + sprintf(name, "usb_vision:%d:done_read", i ); + usd->done_read = create_sem(0, name); + + sprintf(name, "usb_vision:%d:done_write", i); + usd->done_write = create_sem(0, name); + + usd->tty = NULL; + + buf_len = usd->read_buffer_size + usd->write_buffer_size + usd->interrupt_buffer_size; + + usd->buffers_area = create_area("usb_serial:buffers_area", (void *)&usd->read_buffer, B_ANY_KERNEL_ADDRESS, + ROUNDUP(buf_len, B_PAGE_SIZE), + B_CONTIGUOUS, B_READ_AREA|B_WRITE_AREA); + + usd->write_buffer = usd->read_buffer + usd->read_buffer_size; + usd->interrupt_buffer = usd->write_buffer + usd->write_buffer_size; +*/ + (*usb->set_configuration)(uvd->dev, uci); + + uvd->control_pipe = control_epi->handle; + uvd->data_pipe = data_epi->handle; + + status = B_OK; + break; + } + release_sem(usb_vision_lock); + + TRACE_FUNCRET("add_device returns:%08x\n", status); + return status; +} + +status_t add_device(usb_vision_device *uvd, const usb_configuration_info *uci){ + usb_endpoint_info *control_epi = NULL; + usb_endpoint_info *data_epi = NULL; + status_t status = ENODEV; + int i = 0; + usb_interface_info *uii = uci->interface[0].active; + TRACE_FUNCALLS("> add_device(%08x, %08x)\n", uvd, uci); + + for(i=0; i < uii->endpoint_count; i++){ + if(uii->endpoint[i].descr->attributes == USB_EP_ATTR_ISOCHRONOUS){ + if((uii->endpoint[i].descr->endpoint_address & USB_EP_ADDR_DIR_IN) == USB_EP_ADDR_DIR_IN){ + data_epi = &uii->endpoint[i]; + TRACE("iso_ep:%d\n", i); + } + } + if(uii->endpoint[i].descr->attributes == USB_EP_ATTR_CONTROL){ + control_epi = &uii->endpoint[i]; + TRACE("cont_ep:%d\n", i); + } + if(control_epi && data_epi) + break; + } + + if(control_epi && data_epi){ + status = create_add_device(uvd, uci, control_epi, data_epi); + } + + TRACE_FUNCRET("< create_add_device returns:%08x\n", status); + return status; +} + +status_t usb_vision_device_added(const usb_device *dev, void **cookie){ + int dev_idx; + status_t status = B_OK; + const usb_device_descriptor *udd; + usb_vision_device *uvd = 0; + TRACE_FUNCALLS("usb_vision_device_added:%08x cookie:%08x\n", dev, cookie); + + udd = (*usb->get_device_descriptor)(dev); + TRACE_ALWAYS("Probing device: %08x/%08x\n", udd->vendor_id, udd->product_id); + + *cookie = 0; + for(dev_idx = 0; dev_idx < SIZEOF(supported_devices); dev_idx++) + if(supported_devices[dev_idx].vendor == udd->vendor_id + && supported_devices[dev_idx].product == udd->product_id){ + const usb_configuration_info *uci; + int cfg_idx; + for(cfg_idx = 0; (uci = (*usb->get_nth_configuration)(dev, cfg_idx)) != NULL; cfg_idx++){ + uvd = malloc(sizeof(usb_vision_device)); + if(uvd){ + memset(uvd, 0, sizeof(usb_vision_device)); + uvd->dev = dev; + if((status = add_device(uvd, uci)) == B_OK){ + *cookie = dev; + TRACE_ALWAYS("(%04x/%04x) added \n", supported_devices[dev_idx].vendor, + supported_devices[dev_idx].product); + break; + }else + free(uvd); + }else + status = B_NO_MEMORY; + } + break; + } + + TRACE_FUNCRET("usb_vision_device_added returns:%08x\n", status); + return status; +} + +status_t usb_vision_device_removed(void *cookie){ + int i; + status_t status = B_OK; + struct usb_device *ud = (struct usb_device *) cookie; + TRACE_FUNCALLS("usb_vision_device_removed:%08x\n", cookie); + + acquire_sem(usb_vision_lock); + + for(i = 0; i < DEVICES_COUNT; i++ ){ + usb_vision_device *uvd = usb_vision_devices[i]; + if(uvd){ + if(ud == uvd->dev){ + free(uvd); + usb_vision_devices[i] = 0; + } + } + } + + release_sem(usb_vision_lock); + + TRACE_FUNCRET("usb_vision_device_removed returns:%08x\n", status); + return status; +} diff --git a/src/add-ons/kernel/drivers/video/usb_vision/usb_vision.h b/src/add-ons/kernel/drivers/video/usb_vision/usb_vision.h new file mode 100644 index 0000000000..cfbd73517e --- /dev/null +++ b/src/add-ons/kernel/drivers/video/usb_vision/usb_vision.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2003 by Siarzhuk Zharski + * Distributed under the terms of the MIT License. + * + */ + +#ifndef _USBVISION_DRIVER_H_ + #define _USBVISION_DRIVER_H_ + +#define DRIVER_NAME "usb_vision" + +#define DEVICES_COUNT 0x1f + +#include "nt100x.h" +#include "tracing.h" + +#define SIZEOF(array) (sizeof(array)/sizeof(array[0])) + +/* "forgotten" attributes etc ...*/ +#define USB_EP_ADDR_DIR_IN 0x80 +#define USB_EP_ADDR_DIR_OUT 0x00 + +#define USB_EP_ATTR_CONTROL 0x00 +#define USB_EP_ATTR_ISOCHRONOUS 0x01 +#define USB_EP_ATTR_BULK 0x02 +#define USB_EP_ATTR_INTERRUPT 0x03 + + +typedef struct{ + uint32 open_count; + const usb_device *dev; + usb_pipe *control_pipe; + usb_pipe *data_pipe; +} usb_vision_device; + +#endif//_USB_SERIAL_DRIVER_H_ diff --git a/src/add-ons/kernel/drivers/video/usb_vision/usb_vision.settings.sample b/src/add-ons/kernel/drivers/video/usb_vision/usb_vision.settings.sample new file mode 100644 index 0000000000..27a25a61c2 --- /dev/null +++ b/src/add-ons/kernel/drivers/video/usb_vision/usb_vision.settings.sample @@ -0,0 +1,31 @@ +# +# The sample USBVision driver settings file +# +# Rename it to usbvision and put into +# /boot/home/config/settings/kernel/drivers/ +# After restarting your system the new settings will works. + +# Debug output - this is a possibility to view some kind of development related +# information - error and warning messages etc. + +# debug_output - activates debug output. The debug builds has debug output +# activated by default and this key has no effect on it. The release builds requires +# to activate this if you want to see debug messages in syslog or in private log file. +# +# debug_output true + +# debug_output_in_file - activates writing of debug messages into private log file. +# The name of this file is /boot/home/usbvision.log. If this key is set to true - no messages +# will be written into syslog. +# +# debug_output_in_file true + +# debug_output_file_rewrite - activates rewriting of private log file on +# calling driver_init() syscall. By default this set in false. +# +# debug_output_file_rewrite false + +# debug_trace_func_calls - the information about driver functions calls +# will be traced. Would you like to see internals? Then activate this. +# +# debug_trace_func_calls true diff --git a/src/add-ons/media/media-add-ons/Jamfile b/src/add-ons/media/media-add-ons/Jamfile index 73edbe465d..8949fd2788 100644 --- a/src/add-ons/media/media-add-ons/Jamfile +++ b/src/add-ons/media/media-add-ons/Jamfile @@ -8,5 +8,6 @@ SubInclude HAIKU_TOP src add-ons media media-add-ons mixer ; SubInclude HAIKU_TOP src add-ons media media-add-ons multi_audio ; SubInclude HAIKU_TOP src add-ons media media-add-ons radeon ; SubInclude HAIKU_TOP src add-ons media media-add-ons tone_producer_demo ; +SubInclude HAIKU_TOP src add-ons media media-add-ons usb_vision ; SubInclude HAIKU_TOP src add-ons media media-add-ons video_producer_demo ; diff --git a/src/add-ons/media/media-add-ons/usb_vision/AddOn.cpp b/src/add-ons/media/media-add-ons/usb_vision/AddOn.cpp new file mode 100644 index 0000000000..8280622cee --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_vision/AddOn.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * + * Skeletal part of this code was inherired from original BeOS sample code, + * that is distributed under the terms of the Be Sample Code License. + * + */ + +#include +#include +#include + +#include +#include +#include + +#include "AddOn.h" +#include "Producer.h" + +#include "nt100x.h" + +MediaAddOn::MediaAddOn(image_id imid) + : BMediaAddOn(imid) +{ + /* Customize these parameters to match those of your node */ + fFlavorInfo.name = "USB Vision"; + fFlavorInfo.info = "USB Vision"; + fFlavorInfo.kinds = B_BUFFER_PRODUCER | B_CONTROLLABLE | B_PHYSICAL_INPUT; + fFlavorInfo.flavor_flags = 0; + fFlavorInfo.internal_id = 0; + fFlavorInfo.possible_count = 1; + fFlavorInfo.in_format_count = 0; + fFlavorInfo.in_format_flags = 0; + fFlavorInfo.in_formats = NULL; + fFlavorInfo.out_format_count = 1; + fFlavorInfo.out_format_flags = 0; + fMediaFormat.type = B_MEDIA_RAW_VIDEO; + fMediaFormat.u.raw_video = media_raw_video_format::wildcard; + fMediaFormat.u.raw_video.interlace = 1; + fMediaFormat.u.raw_video.display.format = B_RGB32; + fFlavorInfo.out_formats = &fMediaFormat; + + fInitStatus = B_NO_INIT; + fDriverFD = -1; + if(USBVisionInit()){ + fInitStatus = B_OK; + } +} + +MediaAddOn::~MediaAddOn() +{ + if(fInitStatus == B_OK){ + USBVisionUninit(); + } +} + + +status_t +MediaAddOn::InitCheck(const char **out_failure_text) +{ + if (fInitStatus < B_OK) { + *out_failure_text = "Unknown error"; + return fInitStatus; + } + + return B_OK; +} + +int32 +MediaAddOn::CountFlavors() +{ + if (fInitStatus < B_OK) + return fInitStatus; + + /* This addon only supports a single flavor, as defined in the + * constructor */ + return 1; +} + +/* + * The pointer to the flavor received only needs to be valid between + * successive calls to BMediaAddOn::GetFlavorAt(). + */ +status_t +MediaAddOn::GetFlavorAt(int32 n, const flavor_info **out_info) +{ + if (fInitStatus < B_OK) + return fInitStatus; + + if (n != 0) + return B_BAD_INDEX; + + /* Return the flavor defined in the constructor */ + *out_info = &fFlavorInfo; + return B_OK; +} + +BMediaNode * +MediaAddOn::InstantiateNodeFor( + const flavor_info *info, BMessage *config, status_t *out_error) +{ + VideoProducer *node; + + if (fInitStatus < B_OK) + return NULL; + + if (info->internal_id != fFlavorInfo.internal_id) + return NULL; + + /* At most one instance of the node should be instantiated at any given + * time. The locking for this restriction may be found in the VideoProducer + * class. */ + node = new VideoProducer(this, fFlavorInfo.name, fFlavorInfo.internal_id); + if (node && (node->InitCheck() < B_OK)) { + delete node; + node = NULL; + } + + return node; +} + +BMediaAddOn * +make_media_addon(image_id imid) +{ + return new MediaAddOn(imid); +} + +bool MediaAddOn::USBVisionInit() +{ + //TODO - support for multiple devices !!! + fDriverFD = open("/dev/video/usb_vision/0", O_RDWR); + if(fDriverFD < 0) + fInitStatus = ENODEV; + return (fDriverFD >= 0); +} + +void MediaAddOn::USBVisionUninit() +{ //TODO - correct work on detach device from usb port ... + close(fDriverFD); +} + +status_t MediaAddOn::USBVisionWriteRegister(uint8 reg, uint8 *data, uint8 len /*= sizeof(uint8)*/) +{ + status_t status = ENODEV; + if(fDriverFD >= 0){ + xet_nt100x_reg ri = {reg, len}; + memcpy(ri.data, data, len); + status = ioctl(fDriverFD, NT_IOCTL_WRITE_REGISTER, &ri, sizeof(ri)); + } + return status; +} + +status_t MediaAddOn::USBVisionReadRegister(uint8 reg, uint8 *data, uint8 len /* = sizeof(uint8)*/) +{ + status_t status = ENODEV; + if(fDriverFD >= 0){ + xet_nt100x_reg ri = {reg, len}; + if((status = ioctl(fDriverFD, NT_IOCTL_READ_REGISTER, &ri, sizeof(ri))) == B_OK){ + memcpy(data, ri.data, ri.data_length); + } + } + return status; +} diff --git a/src/add-ons/media/media-add-ons/usb_vision/AddOn.h b/src/add-ons/media/media-add-ons/usb_vision/AddOn.h new file mode 100644 index 0000000000..d489d7f26e --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_vision/AddOn.h @@ -0,0 +1,59 @@ +/* + * This file is a part of BeOS USBVision driver project. + * Copyright (c) 2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * + * Skeletal part of this code was inherired from original BeOS sample code, + * that is distributed under the terms of the Be Sample Code License. + * + */ + +#ifndef _USBVISION_ADDON_H +#define _USBVISION_ADDON_H + +#include + +#define TOUCH(x) ((void)(x)) + +extern "C" _EXPORT BMediaAddOn *make_media_addon(image_id you); + +class MediaAddOn : public BMediaAddOn +{ +public: + MediaAddOn(image_id imid); + virtual ~MediaAddOn(); + + virtual status_t InitCheck(const char **out_failure_text); + + virtual int32 CountFlavors(); + virtual status_t GetFlavorAt(int32 n, const flavor_info ** out_info); + virtual BMediaNode *InstantiateNodeFor( + const flavor_info * info, + BMessage * config, + status_t * out_error); + + virtual status_t GetConfigurationFor(BMediaNode *node, BMessage *message) + { TOUCH(node); TOUCH(message); return B_OK; } + virtual status_t SaveConfigInfo(BMediaNode *node, BMessage *message) + { TOUCH(node); TOUCH(message); return B_OK; } + + virtual bool WantsAutoStart() { return false; } + virtual status_t AutoStart(int in_count, BMediaNode **out_node, + int32 *out_internal_id, bool *out_has_more) + { TOUCH(in_count); TOUCH(out_node); + TOUCH(out_internal_id); TOUCH(out_has_more); + return B_ERROR; } + bool USBVisionInit(); + void USBVisionUninit(); + status_t USBVisionWriteRegister(uint8 reg, uint8 *data, uint8 len = sizeof(uint8)); + status_t USBVisionReadRegister(uint8 reg, uint8 *data, uint8 len = sizeof(uint8)); + +private: + status_t fInitStatus; + flavor_info fFlavorInfo; + media_format fMediaFormat; + int fDriverFD; +}; + +#endif /*_USBVISION_ADDON_H*/ diff --git a/src/add-ons/media/media-add-ons/usb_vision/Channels.cpp b/src/add-ons/media/media-add-ons/usb_vision/Channels.cpp new file mode 100644 index 0000000000..262cab7178 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_vision/Channels.cpp @@ -0,0 +1,582 @@ +/* + * This file is a part of BeOS USBVision driver project. + * Copyright (c) 2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * + */ + +/* TODO: Look for the following channel lists ... +Brazil Air +China Air +Europe Air +Europe Cable +France Air +France Cable +Great Britain Air +Great Britain Cable +FM Radio +UKW Radio +*/ + +struct Channel{ + const char *name; + float frequency; // in MHz +}; + +Channel Channels_US_Air[] = { + { "2", 55.25}, { "3", 61.25}, { "4", 67.25}, { "5", 77.25}, { "6", 83.25}, + { "7", 175.25}, { "8", 181.25}, { "9", 187.25}, { "10", 193.25}, { "11", 199.25}, + { "12", 205.25}, { "13", 211.25}, { "14", 471.25}, { "15", 477.25}, { "16", 483.25}, + { "17", 489.25}, { "18", 495.25}, { "19", 501.25}, { "20", 507.25}, { "21", 513.25}, + { "22", 519.25}, { "23", 525.25}, { "24", 531.25}, { "25", 537.25}, { "26", 543.25}, + { "27", 549.25}, { "28", 555.25}, { "29", 561.25}, { "30", 567.25}, { "31", 573.25}, + { "32", 579.25}, { "33", 585.25}, { "34", 591.25}, { "35", 597.25}, { "36", 603.25}, + { "37", 609.25}, { "38", 615.25}, { "39", 621.25}, { "40", 627.25}, { "41", 633.25}, + { "42", 639.25}, { "43", 645.25}, { "44", 651.25}, { "45", 657.25}, { "46", 663.25}, + { "47", 669.25}, { "48", 675.25}, { "49", 681.25}, { "50", 687.25}, { "51", 693.25}, + { "52", 699.25}, { "53", 705.25}, { "54", 711.25}, { "55", 717.25}, { "56", 723.25}, + { "57", 729.25}, { "58", 735.25}, { "59", 741.25}, { "60", 747.25}, { "61", 753.25}, + { "62", 759.25}, { "63", 765.25}, { "64", 771.25}, { "65", 777.25}, { "66", 783.25}, + { "67", 789.25}, { "68", 795.25}, { "69", 801.25} }; + +Channel Channels_US_Cable[] = { + { "4A", 73.25}, { "2", 55.25}, { "3", 61.25}, { "4", 67.25}, { "5", 77.25}, + { "6", 83.25}, { "7", 175.25}, { "8", 181.25}, { "9", 187.25}, { "10", 193.25}, + { "11", 199.25}, { "12", 205.25}, { "13", 211.25}, { "A", 121.25}, { "B", 127.25}, + { "C", 133.25}, { "D", 139.25}, { "E", 145.25}, { "F", 151.25}, { "G", 157.25}, + { "H", 163.25}, { "I", 169.25}, { "J", 217.25}, { "K", 223.25}, { "L", 229.25}, + { "M", 235.25}, { "N", 241.25}, { "O", 247.25}, { "P", 253.25}, { "Q", 259.25}, + { "R", 265.25}, { "S", 271.25}, { "T", 277.25}, { "U", 283.25}, { "V", 289.25}, + { "W", 295.25}, { "W+1", 301.25}, { "W+2", 307.25}, { "W+3", 313.25}, { "W+4", 319.25}, + { "W+5", 325.25}, { "W+6", 331.25}, { "W+7", 337.25}, { "W+8", 343.25}, { "W+9", 349.25}, + { "W+10", 355.25}, { "W+11", 361.25}, { "W+12", 367.25}, { "W+13", 373.25}, { "W+14", 379.25}, + { "W+15", 385.25}, { "W+16", 391.25}, { "W+17", 397.25}, { "W+18", 403.25}, { "W+19", 409.25}, + { "W+20", 415.25}, { "W+21", 421.25}, { "W+22", 427.25}, { "W+23", 433.25}, { "W+24", 439.25}, + { "W+25", 445.25}, { "W+26", 451.25}, { "W+27", 457.25}, { "W+28", 463.25}, { "65", 469.25}, + { "66", 475.25}, { "67", 481.25}, { "68", 487.25}, { "69", 493.25}, { "70", 499.25}, + { "71", 505.25}, { "72", 511.25}, { "73", 517.25}, { "74", 523.25}, { "75", 529.25}, + { "76", 535.25}, { "77", 541.25}, { "78", 547.25}, { "79", 553.25}, { "80", 559.25}, + { "81", 565.25}, { "82", 571.25}, { "83", 577.25}, { "84", 583.25}, { "85", 589.25}, + { "86", 595.25}, { "87", 601.25}, { "88", 607.25}, { "89", 613.25}, { "90", 619.25}, + { "91", 625.25}, { "92", 631.25}, { "93", 637.25}, { "94", 643.25}, { "A­5", 91.25 }, + { "A­4", 97.25 }, { "A­3", 103.25}, { "A­2", 109.25}, { "A-1", 115.25}, { "100", 649.25}, + { "101", 655.25}, { "102", 661.25}, { "103", 667.25}, { "104", 673.25}, { "105", 679.25}, + { "106", 685.25}, { "107", 691.25}, { "108", 697.25}, { "109", 703.25}, { "110", 709.25}, + { "111", 715.25}, { "112", 721.25}, { "113", 727.25}, { "114", 733.25}, { "115", 739.25}, + { "116", 745.25}, { "117", 751.25}, { "118", 757.25}, { "119", 763.25}, { "120", 769.25}, + { "121", 775.25}, { "122", 781.25}, { "123", 787.25}, { "124", 793.25}, { "125", 799.25} }; + +Channel Channels_US_Cable_HRC[] = { + { "2", 54.00}, { "3", 60.00}, { "4", 66.00}, { "5", 76.00}, + { "6", 82.00}, { "7", 174.00}, { "8", 180.00}, { "9", 186.00}, { "10", 192.00}, + { "11", 198.00}, { "12", 204.00}, { "13", 210.00}, { "A", 120.00}, { "B", 126.00}, + { "C", 132.00}, { "D", 138.00}, { "E", 144.00}, { "F", 150.00}, { "G", 156.00}, + { "H", 162.00}, { "I", 168.00}, { "J", 216.00}, { "K", 222.00}, { "L", 228.00}, + { "M", 234.00}, { "N", 240.00}, { "O", 246.00}, { "P", 252.00}, { "Q", 258.00}, + { "R", 264.00}, { "S", 270.00}, { "T", 276.00}, { "U", 282.00}, { "V", 288.00}, + { "W", 294.00}, { "W+1", 300.00}, { "W+2", 306.00}, { "W+3", 312.00}, { "W+4", 318.00}, + { "W+5", 324.00}, { "W+6", 330.00}, { "W+7", 336.00}, { "W+8", 342.00}, { "W+9", 348.00}, + { "W+10", 354.00}, { "W+11", 360.00}, { "W+12", 366.00}, { "W+13", 372.00}, { "W+14", 378.00}, + { "W+15", 384.00}, { "W+16", 390.00}, { "W+17", 396.00}, { "W+18", 402.00}, { "W+19", 408.00}, + { "W+20", 414.00}, { "W+21", 420.00}, { "W+22", 426.00}, { "W+23", 432.00}, { "W+24", 438.00}, + { "W+25", 444.00}, { "W+26", 450.00}, { "W+27", 456.00}, { "W+28", 462.00}, { "65", 468.00}, + { "66", 474.00}, { "67", 480.00}, { "68", 486.00}, { "69", 492.00}, { "70", 498.00}, + { "71", 504.00}, { "72", 510.00}, { "73", 516.00}, { "74", 522.00}, { "75", 528.00}, + { "76", 534.00}, { "77", 540.00}, { "78", 546.00}, { "79", 552.00}, { "80", 558.00}, + { "81", 564.00}, { "82", 570.00}, { "83", 576.00}, { "84", 582.00}, { "85", 588.00}, + { "86", 594.00}, { "87", 600.00}, { "88", 606.00}, { "89", 612.00}, { "90", 618.00}, + { "91", 624.00}, { "92", 630.00}, { "93", 636.00}, { "94", 642.00}, { "A­5", 90.00 }, + { "A­4", 96.00 }, { "A­3", 102.00}, { "A­2", 108.00}, { "A-1", 114.00}, { "100", 648.00}, + { "101", 654.00}, { "102", 660.00}, { "103", 666.00}, { "104", 672.00}, { "105", 678.00}, + { "106", 684.00}, { "107", 690.00}, { "108", 696.00}, { "109", 702.00}, { "110", 708.00}, + { "111", 714.00}, { "112", 720.00}, { "113", 726.00}, { "114", 732.00}, { "115", 738.00}, + { "116", 744.00}, { "117", 750.00}, { "118", 756.00}, { "119", 762.00}, { "120", 768.00}, + { "121", 774.00}, { "122", 780.00}, { "123", 786.00}, { "124", 792.00}, { "125", 798.00} }; + +Channel Japan_Air[]={ + { "1", 91.25}, { "2", 97.25}, { "3", 103.25}, { "4", 171.25}, { "5", 177.25}, + { "6", 183.25}, { "7", 189.25}, { "8", 193.25}, { "9", 199.25}, { "10", 205.25}, + { "11", 211.25}, { "12", 217.25}, { "13", 471.25}, { "14", 477.25}, { "15", 483.25}, + { "16", 489.25}, { "17", 495.25}, { "18", 501.25}, { "19", 507.25}, { "20", 513.25}, + { "21", 519.25}, { "22", 525.25}, { "23", 531.25}, { "24", 537.25}, { "25", 543.25}, + { "26", 549.25}, { "27", 555.25}, { "28", 561.25}, { "29", 567.25}, { "30", 573.25}, + { "31", 579.25}, { "32", 585.25}, { "33", 591.25}, { "34", 597.25}, { "35", 603.25}, + { "36", 609.25}, { "37", 615.25}, { "38", 621.25}, { "39", 627.25}, { "40", 633.25}, + { "41", 639.25}, { "42", 645.25}, { "43", 651.25}, { "44", 657.25}, { "45", 663.25}, + { "46", 669.25}, { "47", 675.25}, { "48", 681.25}, { "49", 687.25}, { "50", 693.25}, + { "51", 699.25}, { "52", 705.25}, { "53", 711.25}, { "54", 717.25}, { "55", 723.25}, + { "56", 729.25}, { "57", 735.25}, { "58", 741.25}, { "59", 747.25}, { "60", 753.25}, + { "61", 759.25}, { "62", 765.25} }; + +Channel Japan_Cable[]={ + { "1", 91.25}, { "2", 97.25}, { "3", 103.25}, { "4", 171.25}, { "5", 177.25}, + { "6", 183.25}, { "7", 189.25}, { "8", 193.25}, { "9", 199.25}, { "10", 205.25}, + { "11", 211.25}, { "12", 217.25}, { "C13", 109.25}, { "C14", 115.25}, { "C15", 121.25}, + { "C16", 127.25}, { "C17", 133.25}, { "C18", 139.25}, { "C19", 145.25}, { "C20", 151.25}, + { "C21", 157.25}, { "C22", 165.25}, { "C23", 223.25}, { "C24", 229.25}, { "C25", 235.25}, + { "C26", 241.25}, { "C27", 247.25}, { "C28", 253.25}, { "C29", 259.25}, { "C30", 265.25}, + { "C31", 271.25}, { "C32", 277.25}, { "C33", 293.25}, { "C34", 289.25}, { "C35", 295.25}, + { "C36", 301.25}, { "C37", 307.25}, { "C38", 313.25}, { "C39", 319.25}, { "C40", 325.25}, + { "C41", 331.25}, { "C42", 337.25}, { "C43", 343.25}, { "C44", 349.25}, { "C45", 355.25}, + { "C46", 361.25}, { "C47", 367.25}, { "C48", 373.25}, { "C49", 379.25}, { "C50", 385.25}, + { "C51", 391.25}, { "C52", 397.25}, { "C53", 403.25}, { "C54", 409.25}, { "C55", 415.25}, + { "C56", 421.25}, { "C57", 427.25}, { "C58", 433.25}, { "C59", 439.25}, { "C60", 445.25}, + { "C61", 451.25}, { "C62", 457.25}, { "C63", 463.25} }; + +International_Air +{ + E2 48.25 + E3 55.25 + E4 62.25 + E5 175.25 + E6 182.25 + E7 189.25 + E8 196.25 + E9 203.25 + E10 210.25 + E11 217.25 + E12 224.25 + IA 53.75 + IB 62.25 + IC 82.25 + ID 175.25 + IE 183.25 + IF 192.75 + IG 201.25 + IH 210.25 + 21 471.25 + 22 479.25 + 23 487.25 + 24 495.25 + 25 503.25 + 26 511.25 + 27 519.25 + 28 527.25 + 29 535.25 + + 30 543.25 C30 + 31 551.25 C31 + 32 559.25 C32 + 33 567.25 C33 + 34 575.25 C34 + 35 583.25 C35 + 36 591.25 C36 + 37 599.25 C37 + 38 607.25 C38 + 39 615.25 C39 + 40 623.25 C40 + 41 631.25 C41 + 42 639.25 C42 + 43 647.25 C43 + 44 655.25 C44 + 45 663.25 C45 + 46 671.25 C46 + 47 679.25 C47 + 48 687.25 C48 + 49 695.25 C49 + 50 703.25 C50 + 51 711.25 C51 + 52 719.25 C52 + 53 727.25 C53 + 54 735.25 C54 + 55 743.25 C55 + 56 751.25 C56 + 57 759.25 C57 + 58 767.25 C58 + 59 775.25 C59 + 60 783.25 C60 + 61 791.25 C61 + 62 799.25 C62 + 63 807.25 C63 + 64 815.25 C64 + 65 823.25 C65 + 66 831.25 C66 + 67 839.25 C67 + 68 847.25 C68 + 69 855.25 C69 + E2A 49.75 C70 + AS1 57.25 C71 + AS2 64.25 C72 + AS3 86.25 C73 + AS4 95.25 C74 + AS5 102.25 C75 + AS5A 138.25 + AS10 209.25 + AS11 216.25 + IH1 217.25 + IND2 55.25 + IND3 62.25 + IND4 175.25 + IND5 182.25 + IND6 189.25 + IND7 196.25 + IND8 203.25 + IND9 210.25 + IND10 217.25 + IND11 224.25 + +}; + +International_Cable +{ + Channel Freq + E2 48.25 + E3 55.25 + E4 62.25 + S01 69.25 + S02 76.25 + S03 83.25 + S1 105.25 + + S2 112.25 + S3 119.25 + S4 126.25 + S5 133.25 + S6 140.25 + S7 147.25 + S8 154.25 + S9 161.25 + S10 168.25 + E5 175.25 + E6 182.25 + E7 189.25 + E8 196.25 + E9 203.25 + E10 210.25 + E11 217.25 + E12 224.25 + S11 231.25 + S12 238.25 + S13 245.25 + S14 252.25 + S15 259.25 + S16 266.25 + S17 273.25 + S18 280.25 + S19 287.25 + S20 294.25 + S21 303.25 + S22 311.25 + S23 319.25 + S24 327.25 + S25 335.25 + S26 343.25 + S27 351.25 + S28 359.25 + S29 367.25 + S30 375.25 + S31 383.25 + S32 391.25 + S33 399.25 + S34 407.25 + S35 415.25 + S36 423.25 + S37 431.25 + S38 439.25 + S39 447.25 + S40 455.25 + S41 463.25 +}; + +Channel UK_Air[] = { + { "A", 45.75}, { "B", 53.75}, { "C", 61.75}, { "D", 175.25}, { "E", 183.25}, + { "F", 191.25}, { "G", 199.25}, { "H", 207.25}, { "J", 215.25}, { "C10", 223.25}, + { "C11", 231.25}, { "C13", 247.25}, { "B21", 471.25}, { "B22", 479.25}, { "B23", 487.25}, + { "B24", 495.25}, { "B25", 503.25}, { "B26", 511.25}, { "B27", 519.25}, { "B28", 527.25}, + { "B29", 535.25}, { "B30", 543.25}, { "B31", 551.25}, { "B32", 559.25}, { "B33", 567.25}, + { "B34", 575.25}, { "B35", 583.25}, { "B36", 591.25}, { "B37", 599.25}, { "B38", 607.25}, + { "B39", 615.25}, { "B40", 623.25}, { "B41", 631.25}, { "B42", 639.25}, { "B43", 647.25}, + { "B44", 655.25}, { "B45", 663.25}, { "B46", 671.25}, { "B47", 679.25}, { "B48", 687.25}, + { "B49", 695.25}, { "B50", 703.25}, { "B51", 711.25}, { "B52", 719.25}, { "B53", 727.25}, + { "B54", 735.25}, { "B55", 743.25}, { "B56", 751.25}, { "B57", 759.25}, { "B58", 767.25}, + { "B59", 775.25}, { "B60", 783.25}, { "B61", 791.25}, { "B62", 799.25}, { "B63", 807.25}, + { "B64", 815.25}, { "B65", 823.25}, { "B66", 831.25}, { "B67", 839.25}, { "B68", 847.25}, + { "B69", 855.25}, { "B1", 45.00 }, { "B2", 51.75 }, { "B3", 56.75 }, { "B4", 61.75 }, + { "B5", 66.75 }, { "B6", 179.75}, { "B7", 184.75}, { "B8", 189.75}, { "B9", 194.75}, + { "B10", 199.75}, { "B11", 204.75}, { "B12", 209.75}, { "B13", 214.75}, { "B14", 219.75} }; + +UK_Cable +{ + Channel Freq + A1 47.25 + A2 55.25 + + A3 63.25 + A4 71.25 + A5 79.25 + A6 87.25 + A7 95.25 + A8 103.25 + A9 111.25 + A10 119.25 + A11 127.25 + A12 135.25 + A13 143.25 + A14 151.25 + A15 159.25 + A16 167.25 + A17 175.25 + A18 183.25 + A19 191.25 + A20 199.25 + A21 207.25 + A22 215.25 + A23 223.25 + A24 231.25 + A25 239.25 + A26 247.25 + A27 255.25 + A28 263.25 + A29 271.25 + A30 279.25 + A31 287.25 + A32 295.25 + E2 48.25 + E3 55.25 + E4 62.25 + S01 69.25 + S02 76.25 + S03 83.25 + S1 105.25 + S2 112.25 + S3 119.25 + S4 126.25 + S5 133.25 + S6 140.25 + S7 147.25 + S8 154.25 + S9 161.25 + S10 168.25 + E5 175.25 + E6 182.25 + E7 189.25 + E8 196.25 + E9 203.25 + E10 210.25 + E11 217.25 + E12 224.25 + S11 231.25 + S12 238.25 + S13 245.25 + S14 252.25 + S15 259.25 + S16 266.25 + S17 273.25 + S18 280.25 + S19 287.25 + S20 294.25 + S21 303.25 + S22 311.25 + S23 319.25 + S24 327.25 + S25 335.25 + S26 343.25 + S27 351.25 + S28 359.25 + + S29 367.25 + S30 375.25 + S31 383.25 + S32 391.25 + S33 399.25 + S34 407.25 + S35 415.25 + S36 423.25 + S37 431.25 + S38 439.25 + S39 447.25 + S40 455.25 + S41 463.25 + +}; + +French_Air +{ + Channel Freq + FA 47.75 + L2 49.25 + L3 54.00 + FB 55.75 + L4 57.25 + FC1 60.50 + FC 63.75 + F1 176.00 + F2 184.00 + F3 192.00 + F4 200.00 + F5 208.00 + F6 216.00 + B21 471.25 + B22 479.25 + B23 487.25 + B24 495.25 + B25 503.25 + B26 511.25 + B27 519.25 + B28 527.25 + B29 535.25 + B30 543.25 + B31 551.25 + B32 559.25 + B33 567.25 + B34 575.25 + B35 583.25 + B36 591.25 + B37 599.25 + B38 607.25 + B39 615.25 + B40 623.25 + B41 631.25 + B42 639.25 + B43 647.25 + B44 655.25 + B45 663.25 + B46 671.25 + B47 679.25 + B48 687.25 + B49 695.25 + B50 703.25 + B51 711.25 + B52 719.25 + + + B53 727.25 + B54 735.25 + B55 743.25 + B56 751.25 + B57 759.25 + B58 767.25 + B59 775.25 + B60 783.25 + B61 791.25 + B62 799.25 + B63 807.25 + B64 815.25 + B65 823.25 + B66 831.25 + B67 839.25 + B68 847.25 + B69 855.25 + +}; + +French_Cable +{ + Channel Freq + E2 48.25 + E3 55.25 + E4 62.25 + S01 69.25 + S02 76.25 + S03 83.25 + S1 105.25 + S2 112.25 + S3 119.25 + S4 126.25 + S5 133.25 + S6 140.25 + S7 147.25 + S8 154.25 + S9 161.25 + S10 168.25 + E5 175.25 + E6 182.25 + E7 189.25 + E8 196.25 + E9 203.25 + E10 210.25 + E11 217.25 + E12 224.25 + S11 231.25 + S12 238.25 + S13 245.25 + S14 252.25 + S15 259.25 + S16 266.25 + S17 273.25 + S18 280.25 + S19 287.25 + S20 294.25 + S21 303.25 + S22 311.25 + S23 319.25 + S24 327.25 + S25 335.25 + S26 343.25 + S27 351.25 + S28 359.25 + S29 367.25 + S30 375.25 + S31 383.25 + S32 391.25 + S33 399.25 + S34 407.25 + S35 415.25 + S36 423.25 + + S37 431.25 + S38 439.25 + S39 447.25 + S40 455.25 + S41 463.25 + +}; + +Channel Channels_FMRadio[] = { +/*???*/ +}; + +Channel Channels_UKW_Radio[] = { +/*???*/ +}; + +Channel Channels_xUSSR_Air[] = { + {"1", 49.75}, {"2", 59.25}, {"3", 77.25}, {"4", 85.25}, {"5", 93.25}, + {"6", 175.25}, {"7", 183.25}, {"8", 191.25}, {"9", 199.25}, {"10", 207.25}, + {"11", 215.25}, {"12", 223.25}, + {"21", 471.25}, {"22", 479.25}, {"23", 487.25}, {"24", 495.25}, {"25", 503.25}, + {"26", 511.25}, {"27", 519.25}, {"28", 527.25}, {"29", 535.25}, {"30", 543.25}, + {"31", 551.25}, {"32", 559.25}, {"33", 567.25}, {"34", 575.25}, {"35", 583.25}, + {"36", 591.25}, {"37", 599.25}, {"38", 607.25}, {"39", 615.25}, {"40", 623.25}, + {"41", 631.25}, {"42", 639.25}, {"43", 647.25}, {"44", 655.25}, {"45", 663.25}, + {"46", 671.25}, {"47", 679.25}, {"48", 687.25}, {"49", 695.25}, {"50", 703.25}, + {"51", 711.25}, {"52", 719.25}, {"53", 727.25}, {"54", 735.25}, {"55", 743.25}, + {"56", 751.25}, {"57", 759.25}, {"58", 767.25}, {"59", 775.25}, {"60", 783.25}, + {"61", 791.25}, {"62", 799.25}, {"63", 807.25}, {"64", 815.25}, {"65", 823.25}, + {"66", 831.25}, {"67", 839.25}, {"68", 847.25}, {"69", 855.25}}; + +Channel Channels_xUSSR_Cable[] = { + {"70", 111.25}, {"71", 119.25}, {"72", 127.25}, {"73", 135.25}, {"74", 143.25}, + {"75", 141.25}, {"76", 159.25}, {"77", 167.25}, {"78", 231.25}, {"79", 239.25}, + {"80", 247.25}, {"81", 255.25}, {"82", 263.25}, {"83", 271.25}, {"84", 279.25}, + {"85", 287.25}, {"86", 295.25}, {"87", 303.25}, {"88", 311.25}, {"89", 319.25}, + {"90", 327.25}, {"91", 335.25}, {"92", 343.25}, {"93", 351.25}, {"94", 359.25}, + {"95", 367.25}, {"96", 375.25}, {"97", 383.25}, {"98", 391.25}, {"99", 399.25}, + {"100", 407.25}, {"101", 415.25}, {"102", 423.25}, {"103", 431.25}, {"104", 439.25}, + {"105", 447.25}, {"106", 455.25}, {"107", 463.25} }; + +Channel Channels_EuropeAir[] = { + {"", }, {"", }, {"", }, {"", }, {"", }, {"", }, +}; + +Channel Channels_EuropeCable[] = { + {"", }, {"", }, {"", }, {"", }, {"", }, {"", }, +}; + +Channel Channels_AustraliaAir[] = { + { "0", 46.25}, { "1", 57.25}, { "2", 64.25}, { "3", 86.25}, { "4", 95.25}, + { "5", 102.25}, { "5A", 138.25}, { "6", 175.25}, { "7", 182.25}, { "8", 189.25}, + { "9", 196.25}, { "10", 209.25}, { "11", 216.25}, { "28", 527.25}, { "29", 534.25}, + { "30", 541.25}, { "31", 548.25}, { "32", 555.25}, { "33", 562.25}, { "34", 569.25}, + { "35", 576.25}, { "39", 604.25}, { "40", 611.25}, { "41", 618.25}, { "42", 625.25}, + { "43", 632.25}, { "44", 639.25}, { "45", 646.25}, { "46", 653.25}, { "47", 660.25}, + { "48", 667.25}, { "49", 674.25}, { "50", 681.25}, { "51", 688.25}, { "52", 695.25}, + { "53", 702.25}, { "54", 709.25}, { "55", 716.25}, { "56", 723.25}, { "57", 730.25}, + { "58", 737.25}, { "59", 744.25}, { "60", 751.25}, { "61", 758.25}, { "62", 765.25}, + { "63", 772.25}, { "64", 779.25}, { "65", 786.25}, { "66", 793.25}, { "67", 800.25}, + { "68", 807.25}, { "69", 814.25} }; + +Channel Channels_IrelandAir[] = { + +}; diff --git a/src/add-ons/media/media-add-ons/usb_vision/Jamfile b/src/add-ons/media/media-add-ons/usb_vision/Jamfile new file mode 100644 index 0000000000..52088512de --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_vision/Jamfile @@ -0,0 +1,13 @@ +SubDir HAIKU_TOP src add-ons media media-add-ons usb_vision ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders usb_vision ; + +Addon usb_vision.media_addon : media : + AddOn.cpp + Producer.cpp + TunerLocale.cpp +; + +LinkAgainst usb_vision.media_addon : be media $(TARGET_LIBSTDC++) ; diff --git a/src/add-ons/media/media-add-ons/usb_vision/Producer.cpp b/src/add-ons/media/media-add-ons/usb_vision/Producer.cpp new file mode 100644 index 0000000000..5582de3f18 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_vision/Producer.cpp @@ -0,0 +1,1173 @@ +/* + * This file is a part of BeOS USBVision driver project. + * Copyright (c) 2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * + * Skeletal part of this code was inherired from original BeOS sample code, + * that is distributed under the terms of the Be Sample Code License. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define TOUCH(x) ((void)(x)) + +#define PRINTF(a,b) \ + do { \ + if (a < 2) { \ + printf("VideoProducer::"); \ + printf b; \ + } \ + } while (0) + +#include "Producer.h" + +#define FIELD_RATE 30.f + +const float kUSBBandWidthMin = 0.5f; +const float kUSBBandWidthMax = 7.5f; +const float kUSBBandWidthStep = 0.5f; + +const float kVScreenOffsetMin = 0.f; +const float kVScreenOffsetMax = 4.f; +const float kVScreenOffsetStep = 1.f; +const float kHScreenOffsetMin = 0.f; +const float kHScreenOffsetMax = 4.f; +const float kHScreenOffsetStep = 1.f; + +const float kEffectMin = 0.f; +const float kEffectMax = 31.f; +const float kEffectStep = 1.f; + +const float kBrightnessMin = kEffectMin; +const float kBrightnessMax = kEffectMax; +const float kBrightnessStep = kEffectStep; + +const float kContrastMin = kEffectMin; +const float kContrastMax = kEffectMax; +const float kContrastStep = kEffectStep; + +const float kHueMin = kEffectMin; +const float kHueMax = kEffectMax; +const float kHueStep = kEffectStep; + +const float kSaturationMin = kEffectMin; +const float kSaturationMax = kEffectMax; +const float kSaturationStep = kEffectStep; + +const uint32 kDefChannel = 0; +//const VideoInput kDefVideoInput = P_VI_TUNER; +const uint32 kDefAudioInput = 0; +const uint32 kDefBrightness = 20; +const uint32 kDefContrast = 22; +const uint32 kDefSaturation = 15; +const uint32 kDefHue = 20; +const uint32 kDefCaptureSize = 0; +const uint32 kDefCaptureFormat = 0; +//const VideoStandard kDefStandard = P_VF_PAL_BDGHI; +const float kDefBandwidth = 7.0; +const uint32 kDefLocale = 0; +const uint32 kDefVertOffset = 1; +const uint32 kDefHorzOffset = 2; + +int32 VideoProducer::fInstances = 0; + +VideoProducer::VideoProducer( + BMediaAddOn *addon, const char *name, int32 internal_id) + : BMediaNode(name), + BMediaEventLooper(), + BBufferProducer(B_MEDIA_RAW_VIDEO), + BControllable() +{ + status_t err; + + fInitStatus = B_NO_INIT; + + /* Only allow one instance of the node to exist at any time */ + if (atomic_add(&fInstances, 1) != 0) + return; + + fInternalID = internal_id; + fAddOn = addon; + + fBufferGroup = NULL; + + fThread = -1; + fFrameSync = -1; + fProcessingLatency = 0LL; + + fRunning = false; + fConnected = false; + fEnabled = false; + + fOutput.destination = media_destination::null; + + AddNodeKind(B_PHYSICAL_INPUT); + + fInitStatus = B_OK; + + //debugger("op-op"); + + status_t status = Locale::TunerLocale::LoadLocales(fLocales); + + printf("LoadLocales:%08x\n", status); + + fChannel = kDefChannel; + fVideoInput = P_VI_TUNER; + fAudioInput = kDefAudioInput; + fBrightness = kDefBrightness; + fContrast = kDefContrast; + fSaturation = kDefSaturation; + fHue = kDefHue; + fCaptureSize = kDefCaptureSize; + fCaptureFormat = kDefCaptureFormat; + fStandard = P_VF_PAL_BDGHI; + fLocale = kDefLocale; + fBandwidth = kDefBandwidth; + fVertOffset = kDefVertOffset; + fHorzOffset = kDefHorzOffset; + fColor = B_HOST_TO_LENDIAN_INT32(0x00ff0000); + + fLastChannelChange = + fLastVideoInputChange = + fLastAudioInputChange = + fLastBrightnessChange = + fLastContrastChange = + fLastSaturationChange = + fLastHueChange = + fLastCaptureSizeChange = + fLastCaptureFormatChange = + fLastStandardChange = + fLastLocaleChange = + fLastBandwidthChange = + fLastVertOffsetChange = + fLastHorzOffsetChange = + fLastColorChange = system_time(); + + return; +} + +VideoProducer::~VideoProducer() +{ + if (fInitStatus == B_OK) { + /* Clean up after ourselves, in case the application didn't make us + * do so. */ + if (fConnected) + Disconnect(fOutput.source, fOutput.destination); + if (fRunning) + HandleStop(); + } + + atomic_add(&fInstances, -1); + + Locale::TunerLocale::ReleaseLocales(fLocales); +} + +/* BMediaNode */ + +port_id +VideoProducer::ControlPort() const +{ + return BMediaNode::ControlPort(); +} + +BMediaAddOn * +VideoProducer::AddOn(int32 *internal_id) const +{ + if (internal_id) + *internal_id = fInternalID; + return fAddOn; +} + +status_t +VideoProducer::HandleMessage(int32 message, const void *data, size_t size) +{ + return B_ERROR; +} + +void +VideoProducer::Preroll() +{ + /* This hook may be called before the node is started to give the hardware + * a chance to start. */ +} + +void +VideoProducer::SetTimeSource(BTimeSource *time_source) +{ + /* Tell frame generation thread to recalculate delay value */ + release_sem(fFrameSync); +} + +status_t +VideoProducer::RequestCompleted(const media_request_info &info) +{ + return BMediaNode::RequestCompleted(info); +} + +/* BMediaEventLooper */ + +void +VideoProducer::NodeRegistered() +{ + if (fInitStatus != B_OK) { + ReportError(B_NODE_IN_DISTRESS); + return; + } + + /* After this call, the BControllable owns the BParameterWeb object and + * will delete it for you */ + SetParameterWeb(CreateParameterWeb()); + + fOutput.node = Node(); + fOutput.source.port = ControlPort(); + fOutput.source.id = 0; + fOutput.destination = media_destination::null; + strcpy(fOutput.name, Name()); + + /* Tailor these for the output of your device */ + fOutput.format.type = B_MEDIA_RAW_VIDEO; + fOutput.format.u.raw_video = media_raw_video_format::wildcard; + fOutput.format.u.raw_video.interlace = 1; + fOutput.format.u.raw_video.display.format = B_RGB32; + + /* Start the BMediaEventLooper control loop running */ + Run(); +} + +BParameterWeb *VideoProducer::CreateParameterWeb() +{ + /* Set up the parameter web */ + BParameterWeb *web = new BParameterWeb(); + + BParameterGroup *controls = web->MakeGroup("Controls"); + BParameterGroup *group = controls->MakeGroup("Main Controls"); + BDiscreteParameter *parameter = group->MakeDiscreteParameter( + P_CHANNEL, B_MEDIA_NO_TYPE, "Channel:", B_GENERIC); + for(int i = 0; i < fLocales[fLocale]->ChannelsCount(); i ++){ + parameter->AddItem(i, (fLocales[fLocale]->GetChannel(i)).Name().c_str()); + } + + parameter = group->MakeDiscreteParameter( + P_VIDEO_INPUT, B_MEDIA_NO_TYPE, "Video Input:", B_INPUT_MUX); + parameter->AddItem(P_VI_TUNER, "Tuner"); + parameter->AddItem(P_VI_COMPOSITE, "Composite"); + parameter->AddItem(P_VI_SVIDEO, "SVideo"); + + parameter = group->MakeDiscreteParameter( + P_AUDIO_INPUT, B_MEDIA_NO_TYPE, "Audio Input:", B_INPUT_MUX); + parameter->AddItem(1, "TODO"); + parameter->AddItem(2, "TODO"); + parameter->AddItem(3, "TODO"); + + group = controls->MakeGroup("Effect Controls"); + group->MakeContinuousParameter( + P_BRIGHTNESS, B_MEDIA_NO_TYPE, "Brightness", B_LEVEL, + "", kBrightnessMin, kBrightnessMax, kBrightnessStep); + + group->MakeContinuousParameter( + P_CONTRAST, B_MEDIA_NO_TYPE, "Contrast", B_LEVEL, + "", kContrastMin, kContrastMax, kContrastStep); + + group = controls->MakeGroup("Adv. Effect Controls"); + group->MakeContinuousParameter( + P_SATURATION, B_MEDIA_NO_TYPE, "Saturation", B_LEVEL, + "", kSaturationMin, kSaturationMax, kSaturationStep); + + group->MakeContinuousParameter( + P_HUE, B_MEDIA_NO_TYPE, "Hue", B_LEVEL, + "", kHueMin, kHueMax, kHueStep); + + BParameterGroup *options = web->MakeGroup("Options"); + group = options->MakeGroup("Capture Option"); + parameter = group->MakeDiscreteParameter( + P_CAPTURE_SIZE, B_MEDIA_NO_TYPE, "Capture Size:", B_RESOLUTION); + parameter->AddItem(1, "TODO"); + parameter->AddItem(2, "TODO"); + + parameter = group->MakeDiscreteParameter( + P_CAPTURE_FORMAT, B_MEDIA_NO_TYPE, "Capture Format:", B_COLOR_SPACE); + parameter->AddItem(1, "TODO"); + parameter->AddItem(2, "TODO"); + + BParameterGroup *hardware = web->MakeGroup("Hardware Setup"); + group = hardware->MakeGroup("Format"); + parameter = group->MakeDiscreteParameter( + P_STANDART, B_MEDIA_NO_TYPE, "Video Format:", B_VIDEO_FORMAT); + parameter->AddItem(P_VF_NTSC_M, "NTSC M"); + parameter->AddItem(P_VF_NTSC_MJ, "NTSC MJ"); + parameter->AddItem(P_VF_PAL_BDGHI, "PAL BDGHI"); + parameter->AddItem(P_VF_PAL_M, "PAL M"); + parameter->AddItem(P_VF_PAL_N, "PAL N"); + parameter->AddItem(P_VF_SECAM, "SECAM"); + + parameter = group->MakeDiscreteParameter( + P_LOCALE, B_MEDIA_NO_TYPE, "Tuner Locale:", B_GENERIC); + for(int i = 0; i < fLocales.size(); i++) + parameter->AddItem(i, fLocales[i]->Name().c_str()); + + group = hardware->MakeGroup("Format"); + + group->MakeContinuousParameter( + P_BANDWIDTH, B_MEDIA_NO_TYPE, "Max.Bandwidth", B_LEVEL, + "", kUSBBandWidthMin, kUSBBandWidthMax, kUSBBandWidthStep); + + group = hardware->MakeGroup("Offsets"); + + group->MakeContinuousParameter( + P_VERT_OFFSET, B_MEDIA_NO_TYPE, "Vertical Offset", B_LEVEL, + "", kVScreenOffsetMin, kVScreenOffsetMax, kVScreenOffsetStep); + + group->MakeContinuousParameter( + P_HORZ_OFFSET, B_MEDIA_NO_TYPE, "Horizontal Offset", B_LEVEL, + "", kHScreenOffsetMin, kHScreenOffsetMax, kHScreenOffsetStep); + + BParameterGroup *main = web->MakeGroup(Name()); + BDiscreteParameter *state = main->MakeDiscreteParameter( + P_COLOR, B_MEDIA_RAW_VIDEO, "Color", "Color"); + state->AddItem(B_HOST_TO_LENDIAN_INT32(0x00ff0000), "Red"); + state->AddItem(B_HOST_TO_LENDIAN_INT32(0x0000ff00), "Green"); + state->AddItem(B_HOST_TO_LENDIAN_INT32(0x000000ff), "Blue"); + + return web; +} + +void +VideoProducer::Start(bigtime_t performance_time) +{ + BMediaEventLooper::Start(performance_time); +} + +void +VideoProducer::Stop(bigtime_t performance_time, bool immediate) +{ + BMediaEventLooper::Stop(performance_time, immediate); +} + +void +VideoProducer::Seek(bigtime_t media_time, bigtime_t performance_time) +{ + BMediaEventLooper::Seek(media_time, performance_time); +} + +void +VideoProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time) +{ + BMediaEventLooper::TimeWarp(at_real_time, to_performance_time); +} + +status_t +VideoProducer::AddTimer(bigtime_t at_performance_time, int32 cookie) +{ + return BMediaEventLooper::AddTimer(at_performance_time, cookie); +} + +void +VideoProducer::SetRunMode(run_mode mode) +{ + BMediaEventLooper::SetRunMode(mode); +} + +void +VideoProducer::HandleEvent(const media_timed_event *event, + bigtime_t lateness, bool realTimeEvent) +{ + TOUCH(lateness); TOUCH(realTimeEvent); + + switch(event->type) + { + case BTimedEventQueue::B_START: + HandleStart(event->event_time); + break; + case BTimedEventQueue::B_STOP: + HandleStop(); + break; + case BTimedEventQueue::B_WARP: + HandleTimeWarp(event->bigdata); + break; + case BTimedEventQueue::B_SEEK: + HandleSeek(event->bigdata); + break; + case BTimedEventQueue::B_PARAMETER: + HandleParameter(event->data); + break; + case BTimedEventQueue::B_HANDLE_BUFFER: + case BTimedEventQueue::B_DATA_STATUS: + default: + PRINTF(-1, ("HandleEvent: Unhandled event -- %lx\n", event->type)); + break; + } +} + +void +VideoProducer::CleanUpEvent(const media_timed_event *event) +{ + BMediaEventLooper::CleanUpEvent(event); +} + +bigtime_t +VideoProducer::OfflineTime() +{ + return BMediaEventLooper::OfflineTime(); +} + +void +VideoProducer::ControlLoop() +{ + BMediaEventLooper::ControlLoop(); +} + +status_t +VideoProducer::DeleteHook(BMediaNode * node) +{ + return BMediaEventLooper::DeleteHook(node); +} + +/* BBufferProducer */ + +status_t +VideoProducer::FormatSuggestionRequested( + media_type type, int32 quality, media_format *format) +{ + if (type != B_MEDIA_ENCODED_VIDEO) + return B_MEDIA_BAD_FORMAT; + + TOUCH(quality); + + *format = fOutput.format; + return B_OK; +} + +status_t +VideoProducer::FormatProposal(const media_source &output, media_format *format) +{ + status_t err; + + if (!format) + return B_BAD_VALUE; + + if (output != fOutput.source) + return B_MEDIA_BAD_SOURCE; + + err = format_is_compatible(*format, fOutput.format) ? + B_OK : B_MEDIA_BAD_FORMAT; + *format = fOutput.format; + return err; + +} + +status_t +VideoProducer::FormatChangeRequested(const media_source &source, + const media_destination &destination, media_format *io_format, + int32 *_deprecated_) +{ + TOUCH(destination); TOUCH(io_format); TOUCH(_deprecated_); + if (source != fOutput.source) + return B_MEDIA_BAD_SOURCE; + + return B_ERROR; +} + +status_t +VideoProducer::GetNextOutput(int32 *cookie, media_output *out_output) +{ + if (!out_output) + return B_BAD_VALUE; + + if ((*cookie) != 0) + return B_BAD_INDEX; + + *out_output = fOutput; + (*cookie)++; + return B_OK; +} + +status_t +VideoProducer::DisposeOutputCookie(int32 cookie) +{ + TOUCH(cookie); + + return B_OK; +} + +status_t +VideoProducer::SetBufferGroup(const media_source &for_source, + BBufferGroup *group) +{ + TOUCH(for_source); TOUCH(group); + + return B_ERROR; +} + +status_t +VideoProducer::VideoClippingChanged(const media_source &for_source, + int16 num_shorts, int16 *clip_data, + const media_video_display_info &display, int32 *_deprecated_) +{ + TOUCH(for_source); TOUCH(num_shorts); TOUCH(clip_data); + TOUCH(display); TOUCH(_deprecated_); + + return B_ERROR; +} + +status_t +VideoProducer::GetLatency(bigtime_t *out_latency) +{ + *out_latency = EventLatency() + SchedulingLatency(); + return B_OK; +} + +status_t +VideoProducer::PrepareToConnect(const media_source &source, + const media_destination &destination, media_format *format, + media_source *out_source, char *out_name) +{ + status_t err; + + PRINTF(1, ("PrepareToConnect() %ldx%ld\n", \ + format->u.raw_video.display.line_width, \ + format->u.raw_video.display.line_count)); + + if (fConnected) { + PRINTF(0, ("PrepareToConnect: Already connected\n")); + return EALREADY; + } + + if (source != fOutput.source) + return B_MEDIA_BAD_SOURCE; + + if (fOutput.destination != media_destination::null) + return B_MEDIA_ALREADY_CONNECTED; + + /* The format parameter comes in with the suggested format, and may be + * specialized as desired by the node */ + if (!format_is_compatible(*format, fOutput.format)) { + *format = fOutput.format; + return B_MEDIA_BAD_FORMAT; + } + + if (format->u.raw_video.display.line_width == 0) + format->u.raw_video.display.line_width = 320; + if (format->u.raw_video.display.line_count == 0) + format->u.raw_video.display.line_count = 240; + if (format->u.raw_video.field_rate == 0) + format->u.raw_video.field_rate = 29.97f; + + *out_source = fOutput.source; + strcpy(out_name, fOutput.name); + + fOutput.destination = destination; + + return B_OK; +} + +void +VideoProducer::Connect(status_t error, const media_source &source, + const media_destination &destination, const media_format &format, + char *io_name) +{ + PRINTF(1, ("Connect() %ldx%ld\n", \ + format.u.raw_video.display.line_width, \ + format.u.raw_video.display.line_count)); + + if (fConnected) { + PRINTF(0, ("Connect: Already connected\n")); + return; + } + + if ( (source != fOutput.source) || (error < B_OK) || + !const_cast(&format)->Matches(&fOutput.format)) { + PRINTF(1, ("Connect: Connect error\n")); + return; + } + + fOutput.destination = destination; + strcpy(io_name, fOutput.name); + + if (fOutput.format.u.raw_video.field_rate != 0.0f) { + fPerformanceTimeBase = fPerformanceTimeBase + + (bigtime_t) + ((fFrame - fFrameBase) * + (1000000 / fOutput.format.u.raw_video.field_rate)); + fFrameBase = fFrame; + } + + fConnectedFormat = format.u.raw_video; + + /* get the latency */ + bigtime_t latency = 0; + media_node_id tsID = 0; + FindLatencyFor(fOutput.destination, &latency, &tsID); + #define NODE_LATENCY 1000 + SetEventLatency(latency + NODE_LATENCY); + + uint32 *buffer, *p, f = 3; + p = buffer = (uint32 *)malloc(4 * fConnectedFormat.display.line_count * + fConnectedFormat.display.line_width); + if (!buffer) { + PRINTF(0, ("Connect: Out of memory\n")); + return; + } + bigtime_t now = system_time(); + for (int y=0;yInitCheck() < B_OK) { + delete fBufferGroup; + fBufferGroup = NULL; + return; + } + + fConnected = true; + fEnabled = true; + + /* Tell frame generation thread to recalculate delay value */ + release_sem(fFrameSync); +} + +void +VideoProducer::Disconnect(const media_source &source, + const media_destination &destination) +{ + PRINTF(1, ("Disconnect()\n")); + + if (!fConnected) { + PRINTF(0, ("Disconnect: Not connected\n")); + return; + } + + if ((source != fOutput.source) || (destination != fOutput.destination)) { + PRINTF(0, ("Disconnect: Bad source and/or destination\n")); + return; + } + + fEnabled = false; + fOutput.destination = media_destination::null; + + fLock.Lock(); + delete fBufferGroup; + fBufferGroup = NULL; + fLock.Unlock(); + + fConnected = false; +} + +void +VideoProducer::LateNoticeReceived(const media_source &source, + bigtime_t how_much, bigtime_t performance_time) +{ + TOUCH(source); TOUCH(how_much); TOUCH(performance_time); +} + +void +VideoProducer::EnableOutput(const media_source &source, bool enabled, + int32 *_deprecated_) +{ + TOUCH(_deprecated_); + + if (source != fOutput.source) + return; + + fEnabled = enabled; +} + +status_t +VideoProducer::SetPlayRate(int32 numer, int32 denom) +{ + TOUCH(numer); TOUCH(denom); + + return B_ERROR; +} + +void +VideoProducer::AdditionalBufferRequested(const media_source &source, + media_buffer_id prev_buffer, bigtime_t prev_time, + const media_seek_tag *prev_tag) +{ + TOUCH(source); TOUCH(prev_buffer); TOUCH(prev_time); TOUCH(prev_tag); +} + +void +VideoProducer::LatencyChanged(const media_source &source, + const media_destination &destination, bigtime_t new_latency, + uint32 flags) +{ + TOUCH(source); TOUCH(destination); TOUCH(new_latency); TOUCH(flags); +} + +/* BControllable */ + +status_t +VideoProducer::GetParameterValue( + int32 id, bigtime_t *last_change, void *value, size_t *size) +{ + switch(id){ + case P_CHANNEL: + *last_change = fLastChannelChange; + *size = sizeof(uint32); + *((uint32*)value) = fChannel; + break; + case P_VIDEO_INPUT: + *last_change = fLastVideoInputChange; + *size = sizeof(uint32); + *((uint32*)value) = fVideoInput; + break; + case P_AUDIO_INPUT: + *last_change = fLastAudioInputChange; + *size = sizeof(uint32); + *((uint32*)value) = fAudioInput; + break; + case P_BRIGHTNESS: + *last_change = fLastBrightnessChange; + *size = sizeof(float); + *((float *)value) = fBrightness; + break; + case P_CONTRAST: + *last_change = fLastContrastChange; + *size = sizeof(float); + *((float*)value) = fContrast; + break; + case P_SATURATION: + *last_change = fLastSaturationChange; + *size = sizeof(float); + *((float*)value) = fSaturation; + break; + case P_HUE: + *last_change = fLastHueChange; + *size = sizeof(float); + *((float*)value) = fHue; + break; + case P_CAPTURE_SIZE: + *last_change = fLastCaptureSizeChange; + *size = sizeof(uint32); + *((uint32*)value) = fCaptureSize; + break; + case P_CAPTURE_FORMAT: + *last_change = fLastCaptureFormatChange; + *size = sizeof(uint32); + *((uint32*)value) = fCaptureFormat; + break; + case P_STANDART: + *last_change = fLastStandardChange; + *size = sizeof(uint32); + *((uint32*)value) = fStandard; + break; + case P_BANDWIDTH: + *last_change = fLastBandwidthChange; + *size = sizeof(float); + *((float *)value) = fBandwidth; + break; + case P_LOCALE: + *last_change = fLastLocaleChange; + *size = sizeof(uint32); + *((uint32*)value) = fLocale; + break; + case P_VERT_OFFSET: + *last_change = fLastVertOffsetChange; + *size = sizeof(float); + *((float*)value) = fVertOffset; + break; + case P_HORZ_OFFSET: + *last_change = fLastHorzOffsetChange; + *size = sizeof(float); + *((float*)value) = fHorzOffset; + break; + case P_COLOR: + *last_change = fLastColorChange; + *size = sizeof(uint32); + *((uint32 *)value) = fColor; + break; + default: + return B_BAD_VALUE; + } + return B_OK; +} + +void +VideoProducer::SetParameterValue( + int32 id, bigtime_t when, const void *value, size_t size) +{ + switch(id){ + case P_CHANNEL: + if (*(uint32 *)value != fChannel){ + fChannel = *(uint32 *)value; + fLastChannelChange = when; + BroadcastNewParameterValue( + fLastChannelChange, P_CHANNEL, &fChannel, sizeof(fChannel)); + } + break; + case P_VIDEO_INPUT: + if (*(uint32 *)value != fVideoInput){ + fVideoInput = *(uint32 *)value; + fLastVideoInputChange = when; + BroadcastNewParameterValue( + fLastVideoInputChange, P_VIDEO_INPUT, &fVideoInput, sizeof(fVideoInput)); + } + break; + case P_AUDIO_INPUT: + if (*(uint32 *)value != fAudioInput){ + fAudioInput = *(uint32 *)value; + fLastAudioInputChange = when; + BroadcastNewParameterValue( + fLastAudioInputChange, P_AUDIO_INPUT, &fAudioInput, sizeof(fAudioInput)); + } + break; + case P_BRIGHTNESS: + if (*(float *)value != fBrightness){ + fBrightness = *(float *)value; + fLastBrightnessChange = when; + BroadcastNewParameterValue( + fLastBrightnessChange, P_BRIGHTNESS, &fBrightness, sizeof(fBrightness)); + } + break; + case P_CONTRAST: + if (*(float *)value != fContrast){ + fContrast = *(float *)value; + fLastContrastChange = when; + BroadcastNewParameterValue( + fLastContrastChange, P_CONTRAST, &fContrast, sizeof(fContrast)); + } + break; + case P_SATURATION: + if (*(float *)value != fSaturation){ + fSaturation = *(float *)value; + fLastSaturationChange = when; + BroadcastNewParameterValue( + fLastSaturationChange, P_SATURATION, &fSaturation, sizeof(fSaturation)); + } + break; + case P_HUE: + if (*(float *)value != fHue){ + fHue = *(float *)value; + fLastHueChange = when; + BroadcastNewParameterValue( + fLastHueChange, P_HUE, &fHue, sizeof(fHue)); + } + break; + case P_CAPTURE_SIZE: + if (*(uint32 *)value != fCaptureSize){ + fCaptureSize = *(uint32*)value; + fLastCaptureSizeChange = when; + BroadcastNewParameterValue( + fLastCaptureSizeChange, P_CAPTURE_SIZE, &fCaptureSize, sizeof(fCaptureSize)); + } + break; + case P_CAPTURE_FORMAT: + if (*(uint32 *)value != fCaptureFormat){ + fCaptureFormat = *(uint32*)value; + fLastCaptureFormatChange = when; + BroadcastNewParameterValue( + fLastCaptureFormatChange, P_CAPTURE_FORMAT, &fCaptureFormat, sizeof(fCaptureFormat)); + } + break; + case P_STANDART: + if (*(uint32 *)value != fStandard){ + fStandard = *(uint32*)value; + fLastStandardChange = when; + BroadcastNewParameterValue( + fLastStandardChange, P_STANDART, &fStandard, sizeof(fStandard)); + } + break; + case P_BANDWIDTH: + if (*(float *)value != fBandwidth){ + fBandwidth = *(float *)value; + fLastBandwidthChange = when; + BroadcastNewParameterValue( + fLastBandwidthChange, P_BANDWIDTH, &fBandwidth, sizeof(fBandwidth)); + } + break; + case P_LOCALE: + if (*(uint32 *)value != fLocale){ + fLocale = *(uint32 *)value; + fLastLocaleChange = when; + BroadcastNewParameterValue( + fLastLocaleChange, P_LOCALE, &fLocale, sizeof(fLocale)); + } + break; + case P_VERT_OFFSET: + if (*(float*)value != fVertOffset){ + fVertOffset = *(float *)value; + fLastVertOffsetChange = when; + BroadcastNewParameterValue( + fLastVertOffsetChange, P_VERT_OFFSET, &fVertOffset, sizeof(fVertOffset)); + } + break; + case P_HORZ_OFFSET: + if (*(float*)value != fHorzOffset){ + fHorzOffset = *(float *)value; + fLastHorzOffsetChange = when; + BroadcastNewParameterValue( + fLastHorzOffsetChange, P_HORZ_OFFSET, &fHorzOffset, sizeof(fHorzOffset)); + } + break; + case P_COLOR: + if (*(int32 *)value != fColor){ + fColor = *(uint32 *)value; + fLastColorChange = when; + BroadcastNewParameterValue( + fLastColorChange, P_COLOR, &fColor, sizeof(fColor)); + } + break; + } + + EventQueue()->AddEvent(media_timed_event(when, + BTimedEventQueue::B_PARAMETER, NULL, + BTimedEventQueue::B_NO_CLEANUP, id, 0, NULL, 0)); + +} + +status_t +VideoProducer::StartControlPanel(BMessenger *out_messenger) +{ + return BControllable::StartControlPanel(out_messenger); +} + +/* VideoProducer */ + +void +VideoProducer::HandleStart(bigtime_t performance_time) +{ + /* Start producing frames, even if the output hasn't been connected yet. */ + + PRINTF(1, ("HandleStart(%Ld)\n", performance_time)); + + if (fRunning) { + PRINTF(-1, ("HandleStart: Node already started\n")); + return; + } + + fFrame = 0; + fFrameBase = 0; + fPerformanceTimeBase = performance_time; + + fFrameSync = create_sem(0, "frame synchronization"); + if (fFrameSync < B_OK) + goto err1; + + fThread = spawn_thread(_frame_generator_, "frame generator", + B_NORMAL_PRIORITY, this); + if (fThread < B_OK) + goto err2; + + resume_thread(fThread); + + fRunning = true; + return; + +err2: + delete_sem(fFrameSync); +err1: + return; +} + +void +VideoProducer::HandleStop(void) +{ + PRINTF(1, ("HandleStop()\n")); + + if (!fRunning) { + PRINTF(-1, ("HandleStop: Node isn't running\n")); + return; + } + + delete_sem(fFrameSync); + wait_for_thread(fThread, &fThread); + + fRunning = false; +} + +void +VideoProducer::HandleTimeWarp(bigtime_t performance_time) +{ + fPerformanceTimeBase = performance_time; + fFrameBase = fFrame; + + /* Tell frame generation thread to recalculate delay value */ + release_sem(fFrameSync); +} + +void +VideoProducer::HandleSeek(bigtime_t performance_time) +{ + fPerformanceTimeBase = performance_time; + fFrameBase = fFrame; + + /* Tell frame generation thread to recalculate delay value */ + release_sem(fFrameSync); +} + +void +VideoProducer::HandleParameter(uint32 parameter) +{ + switch(parameter){ + case P_CHANNEL: + break; + case P_VIDEO_INPUT: + break; + case P_AUDIO_INPUT: + break; + case P_BRIGHTNESS: + break; + case P_CONTRAST: + break; + case P_SATURATION: + break; + case P_HUE: + break; + case P_CAPTURE_SIZE: + break; + case P_CAPTURE_FORMAT: + break; + case P_STANDART: + break; + case P_BANDWIDTH: + break; + case P_LOCALE: + { + //debugger("stop"); + BParameterWeb *web = Web(); + int nCount = web->CountParameters(); + for(int idx = 0; idx < nCount; idx++){ + BParameter *parameter = web->ParameterAt(idx); + if(parameter && parameter->Type() == BParameter::B_DISCRETE_PARAMETER && + parameter->ID() == P_CHANNEL){ + BDiscreteParameter * d_parameter = dynamic_cast(parameter); + d_parameter->MakeEmpty(); + for(int i = 0; i < fLocales[fLocale]->ChannelsCount(); i ++){ + d_parameter->AddItem(i, (fLocales[fLocale]->GetChannel(i)).Name().c_str()); + } + /*status_t st = BroadcastChangedParameter(P_CHANNEL); + if(st != B_OK) + debugger("kk");*/ + break; + } + } + } + break; + case P_VERT_OFFSET: + break; + case P_HORZ_OFFSET: + break; + } +} + +/* The following functions form the thread that generates frames. You should + * replace this with the code that interfaces to your hardware. */ +int32 +VideoProducer::FrameGenerator() +{ + bigtime_t wait_until = system_time(); + + while (1) { + status_t err = acquire_sem_etc(fFrameSync, 1, B_ABSOLUTE_TIMEOUT, + wait_until); + + /* The only acceptable responses are B_OK and B_TIMED_OUT. Everything + * else means the thread should quit. Deleting the semaphore, as in + * VideoProducer::HandleStop(), will trigger this behavior. */ + if ((err != B_OK) && (err != B_TIMED_OUT)) + break; + + fFrame++; + + /* Recalculate the time until the thread should wake up to begin + * processing the next frame. Subtract fProcessingLatency so that + * the frame is sent in time. */ + wait_until = TimeSource()->RealTimeFor(fPerformanceTimeBase + + (bigtime_t) + ((fFrame - fFrameBase) * + (1000000 / fConnectedFormat.field_rate)), 0) - + fProcessingLatency; + + /* Drop frame if it's at least a frame late */ + if (wait_until < system_time()) + continue; + + /* If the semaphore was acquired successfully, it means something + * changed the timing information (see VideoProducer::Connect()) and + * so the thread should go back to sleep until the newly-calculated + * wait_until time. */ + if (err == B_OK) + continue; + + /* Send buffers only if the node is running and the output has been + * enabled */ + if (!fRunning || !fEnabled) + continue; + + BAutolock _(fLock); + + /* Fetch a buffer from the buffer group */ + BBuffer *buffer = fBufferGroup->RequestBuffer( + 4 * fConnectedFormat.display.line_width * + fConnectedFormat.display.line_count, 0LL); + if (!buffer) + continue; + + /* Fill out the details about this buffer. */ + media_header *h = buffer->Header(); + h->type = B_MEDIA_RAW_VIDEO; + h->time_source = TimeSource()->ID(); + h->size_used = 4 * fConnectedFormat.display.line_width * + fConnectedFormat.display.line_count; + /* For a buffer originating from a device, you might want to calculate + * this based on the PerformanceTimeFor the time your buffer arrived at + * the hardware (plus any applicable adjustments). */ + h->start_time = fPerformanceTimeBase + + (bigtime_t) + ((fFrame - fFrameBase) * + (1000000 / fConnectedFormat.field_rate)); + h->file_pos = 0; + h->orig_size = 0; + h->data_offset = 0; + h->u.raw_video.field_gamma = 1.0; + h->u.raw_video.field_sequence = fFrame; + h->u.raw_video.field_number = 0; + h->u.raw_video.pulldown_number = 0; + h->u.raw_video.first_active_line = 1; + h->u.raw_video.line_count = fConnectedFormat.display.line_count; + + /* Fill in a pattern */ + uint32 *p = (uint32 *)buffer->Data(); + for (int y=0;yRecycle(); + } + } + + return B_OK; +} + +int32 +VideoProducer::_frame_generator_(void *data) +{ + return ((VideoProducer *)data)->FrameGenerator(); +} diff --git a/src/add-ons/media/media-add-ons/usb_vision/Producer.h b/src/add-ons/media/media-add-ons/usb_vision/Producer.h new file mode 100644 index 0000000000..30ebd3a5c7 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_vision/Producer.h @@ -0,0 +1,208 @@ +/* + * This file is a part of BeOS USBVision driver project. + * Copyright (c) 2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * + * Skeletal part of this code was inherired from original BeOS sample code, + * that is distributed under the terms of the Be Sample Code License. + * + */ + +#ifndef _USBVISION_PRODUCER_H +#define _USBVISION_PRODUCER_H + +#include +#include +#include +#include +#include +#include +#include + +#include "TunerLocale.h" + +class VideoProducer : + public virtual BMediaEventLooper, + public virtual BBufferProducer, + public virtual BControllable +{ +public: + VideoProducer(BMediaAddOn *addon, + const char *name, int32 internal_id); +virtual ~VideoProducer(); + +virtual status_t InitCheck() const { return fInitStatus; } + +/* BMediaNode */ +public: +virtual port_id ControlPort() const; +virtual BMediaAddOn *AddOn(int32 * internal_id) const; +virtual status_t HandleMessage(int32 message, const void *data, + size_t size); +protected: +virtual void Preroll(); +virtual void SetTimeSource(BTimeSource * time_source); +virtual status_t RequestCompleted(const media_request_info & info); + +/* BMediaEventLooper */ +protected: +virtual void NodeRegistered(); +virtual void Start(bigtime_t performance_time); +virtual void Stop(bigtime_t performance_time, bool immediate); +virtual void Seek(bigtime_t media_time, bigtime_t performance_time); +virtual void TimeWarp(bigtime_t at_real_time, + bigtime_t to_performance_time); +virtual status_t AddTimer(bigtime_t at_performance_time, int32 cookie); +virtual void SetRunMode(run_mode mode); +virtual void HandleEvent(const media_timed_event *event, + bigtime_t lateness, bool realTimeEvent = false); +virtual void CleanUpEvent(const media_timed_event *event); +virtual bigtime_t OfflineTime(); +virtual void ControlLoop(); +virtual status_t DeleteHook(BMediaNode * node); + +/* BBufferProducer */ +protected: +virtual status_t FormatSuggestionRequested(media_type type, int32 quality, + media_format * format); +virtual status_t FormatProposal(const media_source &output, + media_format *format); +virtual status_t FormatChangeRequested(const media_source &source, + const media_destination &destination, + media_format *io_format, int32 *_deprecated_); +virtual status_t GetNextOutput(int32 * cookie, media_output * out_output); +virtual status_t DisposeOutputCookie(int32 cookie); +virtual status_t SetBufferGroup(const media_source &for_source, + BBufferGroup * group); +virtual status_t VideoClippingChanged(const media_source &for_source, + int16 num_shorts, int16 *clip_data, + const media_video_display_info &display, + int32 * _deprecated_); +virtual status_t GetLatency(bigtime_t * out_latency); +virtual status_t PrepareToConnect(const media_source &what, + const media_destination &where, + media_format *format, + media_source *out_source, char *out_name); +virtual void Connect(status_t error, const media_source &source, + const media_destination &destination, + const media_format & format, char *io_name); +virtual void Disconnect(const media_source & what, + const media_destination & where); +virtual void LateNoticeReceived(const media_source & what, + bigtime_t how_much, bigtime_t performance_time); +virtual void EnableOutput(const media_source & what, bool enabled, + int32 * _deprecated_); +virtual status_t SetPlayRate(int32 numer,int32 denom); +virtual void AdditionalBufferRequested(const media_source & source, + media_buffer_id prev_buffer, bigtime_t prev_time, + const media_seek_tag * prev_tag); +virtual void LatencyChanged(const media_source & source, + const media_destination & destination, + bigtime_t new_latency, uint32 flags); + +/* BControllable */ +protected: +virtual status_t GetParameterValue(int32 id, bigtime_t *last_change, + void *value, size_t *size); +virtual void SetParameterValue(int32 id, bigtime_t when, + const void *value, size_t size); +virtual status_t StartControlPanel(BMessenger *out_messenger); + +/* state */ +private: + void HandleStart(bigtime_t performance_time); + void HandleStop(); + void HandleTimeWarp(bigtime_t performance_time); + void HandleSeek(bigtime_t performance_time); + void HandleParameter(uint32 parameter); + +static int32 fInstances; + + status_t fInitStatus; + + int32 fInternalID; + BMediaAddOn *fAddOn; + + BLocker fLock; + BBufferGroup *fBufferGroup; + + thread_id fThread; + sem_id fFrameSync; +static int32 _frame_generator_(void *data); + int32 FrameGenerator(); + + /* The remaining variables should be declared volatile, but they + * are not here to improve the legibility of the sample code. */ + uint32 fFrame; + uint32 fFrameBase; + bigtime_t fPerformanceTimeBase; + bigtime_t fProcessingLatency; + media_output fOutput; + media_raw_video_format fConnectedFormat; + bool fRunning; + bool fConnected; + bool fEnabled; + + enum { P_CHANNEL, + P_VIDEO_INPUT, + P_AUDIO_INPUT, + P_BRIGHTNESS, + P_CONTRAST, + P_SATURATION, + P_HUE, + P_CAPTURE_SIZE, + P_CAPTURE_FORMAT, + P_STANDART, + P_BANDWIDTH, + P_LOCALE, + P_VERT_OFFSET, + P_HORZ_OFFSET, + P_COLOR }; +enum { P_VI_TUNER, + P_VI_COMPOSITE, + P_VI_SVIDEO}; +enum { P_VF_NTSC_M, + P_VF_NTSC_MJ, + P_VF_PAL_BDGHI, + P_VF_PAL_M, + P_VF_PAL_N, + P_VF_SECAM}; + BParameterWeb *CreateParameterWeb(); + + uint32 fChannel; + bigtime_t fLastChannelChange; + uint32 fVideoInput; + bigtime_t fLastVideoInputChange; + uint32 fAudioInput; + bigtime_t fLastAudioInputChange; + float fBrightness; + bigtime_t fLastBrightnessChange; + float fContrast; + bigtime_t fLastContrastChange; + float fSaturation; + bigtime_t fLastSaturationChange; + float fHue; + bigtime_t fLastHueChange; + uint32 fCaptureSize; + bigtime_t fLastCaptureSizeChange; + uint32 fCaptureFormat; + bigtime_t fLastCaptureFormatChange; + uint32 fStandard; + bigtime_t fLastStandardChange; + float fBandwidth; + bigtime_t fLastBandwidthChange; + uint32 fLocale; + bigtime_t fLastLocaleChange; + float fVertOffset; + bigtime_t fLastVertOffsetChange; + float fHorzOffset; + bigtime_t fLastHorzOffsetChange; + + uint32 fColor; + bigtime_t fLastColorChange; + + Locale::Locales fLocales; +}; + +#endif /*_USBVISION_PRODUCER_H*/ diff --git a/src/add-ons/media/media-add-ons/usb_vision/TunerLocale.cpp b/src/add-ons/media/media-add-ons/usb_vision/TunerLocale.cpp new file mode 100644 index 0000000000..b60e1327cc --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_vision/TunerLocale.cpp @@ -0,0 +1,135 @@ +/* + * This file is a part of BeOS USBVision driver project. + * Copyright (c) 2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * + */ +#include +#include +#include +#include +#include + +#include "TunerLocale.h" + +using namespace Locale; + +const char *kLocalesSettings = "media/usb_vision/Locales"; + +Channel::Channel(string &str, uint32 frequency): + fName(str), fFrequency(frequency) +{ +} + +const string &Channel::Name() const +{ + return fName; +} +const uint32 Channel::Frequency() +{ + return fFrequency; +} + +TunerLocale::TunerLocale(BEntry &entry) +{ + fStatus = B_NO_INIT; + if(entry.IsFile()){ + BPath path; + if((fStatus = entry.GetPath(&path)) == B_OK){ + char name[B_FILE_NAME_LENGTH]; + if((fStatus = entry.GetName(name)) == B_OK){ + fName = name; + fStatus = LoadLocale(path.Path()); + } + } + } +} + +TunerLocale::~TunerLocale() +{ +} + +status_t TunerLocale::InitCheck() +{ + return fStatus; +} + +status_t TunerLocale::LoadLocale(const char *name) +{ + status_t status = B_OK; + ifstream ifs(name); + while(ifs.good() && !ifs.eof()){ + string str; + getline(ifs, str); + //TODO : validity check and parse strings ... + str.erase(0, str.find_first_not_of(" \t")); + str.erase(str.find_last_not_of(" \t") + 1); + switch(str[0]){ + case ';': continue; + case '@': + str.erase(0, 1); + fName = str; + break; + default: //TODO parse ... + Channel channel(str, 0); + fChannels.push_back(channel); + break; + } + } + return status; +} + +status_t TunerLocale::LoadLocales(vector &vector) +{ + status_t status = B_ERROR; + BPath path; + if((status = find_directory(B_USER_SETTINGS_DIRECTORY, &path)) != B_OK) + return status; + if((status = path.Append(kLocalesSettings)) != B_OK) + return status; + BDirectory directory(path.Path()); + if((status = directory.InitCheck()) != B_OK) + return status; + vector.clear(); + BEntry entry; + while((status = directory.GetNextEntry(&entry)) == B_OK){ + if(entry.IsFile()){ + TunerLocale *locale = new TunerLocale(entry); + if((status = locale->InitCheck()) == B_OK){ + vector.push_back(locale); + } + else + delete locale; + } + } + if(status == B_ENTRY_NOT_FOUND) //we reached the end of entries list ... + status = B_OK; + return status; +} + +status_t TunerLocale::ReleaseLocales(vector &vector) +{ + for(LocalesIterator locale = vector.begin(); + locale != vector.end(); locale ++){ + delete *locale; + } + return B_OK; +} + +const string &TunerLocale::Name() +{ + return fName; +} + +const Channel &TunerLocale::GetChannel(int idx) +{ + if(idx < 0) idx = 0; + if(idx >= (int)fChannels.size()) idx = (int)(fChannels.size() - 1); + return fChannels[idx]; +} + +uint32 TunerLocale::ChannelsCount() +{ + return fChannels.size(); +} diff --git a/src/add-ons/media/media-add-ons/usb_vision/TunerLocale.h b/src/add-ons/media/media-add-ons/usb_vision/TunerLocale.h new file mode 100644 index 0000000000..b2eff8f447 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_vision/TunerLocale.h @@ -0,0 +1,51 @@ +/* + * This file is a part of BeOS USBVision driver project. + * Copyright (c) 2003 by Siarzuk Zharski + * + * This file may be used under the terms of the BSD License + * + */ +#ifndef _TUNER_LOCALE_H_ + #define _TUNER_LOCALE_H_ + +#include +#include + +namespace Locale{ + +class Channel +{ + string fName; + uint32 fFrequency; +public: + Channel(string &str, uint32 frequency); + const string &Name() const; + const uint32 Frequency(); +}; + +typedef vector Channels; +typedef vector::iterator ChannelsIterator; + +class TunerLocale +{ + status_t fStatus; + string fName; + Channels fChannels; + TunerLocale(BEntry &entry); + status_t LoadLocale(const char *file); +public: + ~TunerLocale(); + static status_t LoadLocales(vector &vector); + static status_t ReleaseLocales(vector &vector); + status_t InitCheck(); + const string &Name(); + const Channel &GetChannel(int idx); + uint32 ChannelsCount(); +}; + +typedef vector Locales; +typedef vector::iterator LocalesIterator; + +} //namespace Locale + +#endif//_TUNER_LOCALE_H_ diff --git a/src/add-ons/media/media-add-ons/video_producer_demo/Producer.cpp b/src/add-ons/media/media-add-ons/video_producer_demo/Producer.cpp index 13be6ba64a..76ce841f2f 100644 --- a/src/add-ons/media/media-add-ons/video_producer_demo/Producer.cpp +++ b/src/add-ons/media/media-add-ons/video_producer_demo/Producer.cpp @@ -656,10 +656,10 @@ VideoProducer::FrameGenerator() /* Recalculate the time until the thread should wake up to begin * processing the next frame. Subtract fProcessingLatency so that * the frame is sent in time. */ - wait_until = TimeSource()->RealTimeFor(fPerformanceTimeBase, 0) + + wait_until = TimeSource()->RealTimeFor(fPerformanceTimeBase + (bigtime_t) ((fFrame - fFrameBase) * - (1000000 / fConnectedFormat.field_rate)) - + (1000000 / fConnectedFormat.field_rate)), 0) - fProcessingLatency; /* Drop frame if it's at least a frame late */